mirror of https://github.com/xemu-project/xemu.git
307 lines
9.4 KiB
C
307 lines
9.4 KiB
C
/*
|
|
* Offscreen OpenGL abstraction layer - WGL (windows) specific
|
|
*
|
|
* Copyright (c) 2010 Intel
|
|
* Written by:
|
|
* Gordon Williams <gordon.williams@collabora.co.uk>
|
|
* Ian Molton <ian.molton@collabora.co.uk>
|
|
* Copyright (c) 2013 Wayo
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <windows.h>
|
|
#include <wingdi.h>
|
|
|
|
#include <GL/glew.h>
|
|
#include <GL/gl.h>
|
|
#include <GL/glext.h>
|
|
#include <GL/wglext.h>
|
|
#include <GL/glut.h>
|
|
|
|
#include "gloffscreen.h"
|
|
|
|
/* In Windows, you must create a window *before* you can create a pbuffer or
|
|
* get a context. So we create a hidden Window on startup(see glo_init/GloMain).
|
|
*
|
|
* Also, you can't share contexts that have different pixel formats, so we can't
|
|
* just create a new context from the window. We must create a whole new PBuffer
|
|
* just for a context :(
|
|
*/
|
|
|
|
struct GloMain {
|
|
HINSTANCE hInstance;
|
|
HDC hDC;
|
|
HWND hWnd; /* Our hidden window */
|
|
HGLRC hContext;
|
|
};
|
|
|
|
struct GloMain glo;
|
|
int glo_inited = 0;
|
|
|
|
struct _GloContext {
|
|
int formatFlags;
|
|
/* Pixel format returned by wglChoosePixelFormat */
|
|
int wglPixelFormat;
|
|
/* We need a pbuffer to make a context of the right pixelformat :( */
|
|
HPBUFFERARB hPBuffer;
|
|
HDC hDC;
|
|
HGLRC hContext;
|
|
};
|
|
|
|
|
|
#define GLO_WINDOW_CLASS "QEmuGLClass"
|
|
#define DEFAULT_DEPTH_BUFFER (16)
|
|
|
|
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
|
|
PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB;
|
|
PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB;
|
|
PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB;
|
|
PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB;
|
|
|
|
/* Initialise gloffscreen */
|
|
static void glo_init(void) {
|
|
WNDCLASSEX wcx;
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
|
|
if (glo_inited) {
|
|
printf("gloffscreen already inited\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* Grab An Instance For Our Window */
|
|
glo.hInstance = GetModuleHandle(NULL);
|
|
|
|
wcx.cbSize = sizeof(wcx);
|
|
wcx.style = 0;
|
|
wcx.lpfnWndProc = DefWindowProc;
|
|
wcx.cbClsExtra = 0;
|
|
wcx.cbWndExtra = 0;
|
|
wcx.hInstance = glo.hInstance;
|
|
wcx.hIcon = NULL;
|
|
wcx.hCursor = NULL;
|
|
wcx.hbrBackground = NULL;
|
|
wcx.lpszMenuName = NULL;
|
|
wcx.lpszClassName = GLO_WINDOW_CLASS;
|
|
wcx.hIconSm = NULL;
|
|
RegisterClassEx(&wcx);
|
|
glo.hWnd = CreateWindow(
|
|
GLO_WINDOW_CLASS,
|
|
"QEmuGL",
|
|
0,0,0,0,0,
|
|
(HWND)NULL, (HMENU)NULL,
|
|
glo.hInstance,
|
|
(LPVOID) NULL);
|
|
|
|
if (!glo.hWnd) {
|
|
printf("Unable to create window\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
glo.hDC = GetDC(glo.hWnd);
|
|
|
|
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
|
|
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
|
pfd.nVersion = 1;
|
|
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
|
|
pfd.iPixelType = PFD_TYPE_RGBA;
|
|
pfd.cColorBits = 24;
|
|
pfd.iLayerType = PFD_MAIN_PLANE;
|
|
unsigned int pixelFormat = ChoosePixelFormat(glo.hDC, &pfd);
|
|
DescribePixelFormat(glo.hDC,
|
|
pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
|
|
if (!SetPixelFormat(glo.hDC, pixelFormat, &pfd))
|
|
return;
|
|
|
|
glo.hContext = wglCreateContext(glo.hDC);
|
|
if (glo.hContext == NULL) {
|
|
printf("Unable to create GL context\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
wglMakeCurrent(glo.hDC, glo.hContext);
|
|
|
|
wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)
|
|
wglGetProcAddress("wglChoosePixelFormatARB");
|
|
wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC)
|
|
wglGetProcAddress("wglGetPbufferDCARB");
|
|
wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC)
|
|
wglGetProcAddress("wglReleasePbufferDCARB");
|
|
wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC)
|
|
wglGetProcAddress("wglCreatePbufferARB");
|
|
wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC)
|
|
wglGetProcAddress("wglDestroyPbufferARB");
|
|
|
|
if (!wglChoosePixelFormatARB ||
|
|
!wglGetPbufferDCARB ||
|
|
!wglReleasePbufferDCARB ||
|
|
!wglCreatePbufferARB ||
|
|
!wglDestroyPbufferARB) {
|
|
printf("Unable to load the required WGL extensions\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* Initialize glew */
|
|
if (GLEW_OK != glewInit()) {
|
|
/* GLEW failed! */
|
|
printf("Glew init failed.");
|
|
exit(1);
|
|
}
|
|
glo_inited = 1;
|
|
}
|
|
|
|
/* Uninitialise gloffscreen */
|
|
static void glo_kill(void) {
|
|
if (glo.hContext) {
|
|
wglMakeCurrent(NULL, NULL);
|
|
wglDeleteContext(glo.hContext);
|
|
glo.hContext = NULL;
|
|
}
|
|
if (glo.hDC) {
|
|
ReleaseDC(glo.hWnd, glo.hDC);
|
|
glo.hDC = NULL;
|
|
}
|
|
if (glo.hWnd) {
|
|
DestroyWindow(glo.hWnd);
|
|
glo.hWnd = NULL;
|
|
}
|
|
UnregisterClass(GLO_WINDOW_CLASS, glo.hInstance);
|
|
}
|
|
|
|
/* Create an OpenGL context for a certain pixel format. formatflags are from
|
|
* the GLO_ constants */
|
|
GloContext *glo_context_create(int formatFlags) {
|
|
GloContext *context;
|
|
/* pixel format attributes */
|
|
int pf_attri[] = {
|
|
WGL_SUPPORT_OPENGL_ARB, TRUE,
|
|
WGL_DRAW_TO_PBUFFER_ARB, TRUE,
|
|
WGL_RED_BITS_ARB, 8,
|
|
WGL_GREEN_BITS_ARB, 8,
|
|
WGL_BLUE_BITS_ARB, 8,
|
|
WGL_ALPHA_BITS_ARB, 8,
|
|
WGL_DEPTH_BITS_ARB, 0,
|
|
WGL_STENCIL_BITS_ARB, 0,
|
|
WGL_DOUBLE_BUFFER_ARB, FALSE,
|
|
0
|
|
};
|
|
float pf_attrf[] = {0, 0};
|
|
unsigned int numReturned = 0;
|
|
int pb_attr[] = { 0 };
|
|
int rgbaBits[4];
|
|
|
|
if (!glo_inited)
|
|
glo_init();
|
|
|
|
context = (GloContext *)malloc(sizeof(GloContext));
|
|
memset(context, 0, sizeof(GloContext));
|
|
context->formatFlags = formatFlags;
|
|
|
|
/* set up the surface format from the flags we were given */
|
|
glo_flags_get_rgba_bits(context->formatFlags, rgbaBits);
|
|
pf_attri[5] = rgbaBits[0];
|
|
pf_attri[7] = rgbaBits[1];
|
|
pf_attri[9] = rgbaBits[2];
|
|
pf_attri[11] = rgbaBits[3];
|
|
pf_attri[13] = glo_flags_get_depth_bits(context->formatFlags);
|
|
pf_attri[15] = glo_flags_get_stencil_bits(context->formatFlags);
|
|
|
|
/* find out what pixel format to use */
|
|
wglChoosePixelFormatARB(glo.hDC, pf_attri, pf_attrf, 1,
|
|
&context->wglPixelFormat, &numReturned);
|
|
if (numReturned == 0) {
|
|
printf( "No matching configs found.\n" );
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* We create a tiny pbuffer - just so we can make a context of
|
|
* the right pixel format */
|
|
context->hPBuffer = wglCreatePbufferARB(glo.hDC, context->wglPixelFormat,
|
|
16, 16, pb_attr);
|
|
if (!context->hPBuffer) {
|
|
printf("Couldn't create the PBuffer\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
context->hDC = wglGetPbufferDCARB(context->hPBuffer);
|
|
if (!context->hDC) {
|
|
printf("Couldn't create the DC\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
context->hContext = wglCreateContext(context->hDC);
|
|
if (context->hContext == NULL) {
|
|
printf("Unable to create GL context\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
glo_set_current(context);
|
|
return context;
|
|
}
|
|
|
|
/* Set current context */
|
|
void glo_set_current(GloContext *context) {
|
|
|
|
if (context == NULL) {
|
|
wglMakeCurrent(NULL, NULL);
|
|
} else {
|
|
wglMakeCurrent(context->hDC, context->hContext);
|
|
}
|
|
}
|
|
|
|
/* Destroy a previously created OpenGL context */
|
|
void glo_context_destroy(GloContext *context)
|
|
{
|
|
if (!context) return;
|
|
|
|
wglMakeCurrent(NULL, NULL);
|
|
if (context->hPBuffer != NULL) {
|
|
wglReleasePbufferDCARB(context->hPBuffer, context->hDC);
|
|
wglDestroyPbufferARB(context->hPBuffer);
|
|
}
|
|
if (context->hDC != NULL) {
|
|
ReleaseDC(glo.hWnd, context->hDC);
|
|
}
|
|
if (context->hContext) {
|
|
wglDeleteContext(context->hContext);
|
|
}
|
|
free(context);
|
|
}
|
|
|
|
|
|
/* Check extension implementation for Windows.
|
|
* The Glu 1.2 framework in Windows doesn't include them... */
|
|
GLboolean glo_check_extension(const GLubyte *extName,
|
|
const GLubyte *extString)
|
|
{
|
|
char *p = (char *) glGetString(GL_EXTENSIONS);
|
|
char *end;
|
|
if (p == NULL) {
|
|
return GL_FALSE;
|
|
}
|
|
end = p + strlen(p);
|
|
|
|
while (p < end) {
|
|
int n = strcspn(p, " ");
|
|
if ((strlen(extName) == n) && (strncmp(extName, p, n) == 0)) {
|
|
return GL_TRUE;
|
|
}
|
|
p += (n + 1);
|
|
}
|
|
return GL_FALSE;
|
|
}
|