mirror of https://github.com/xqemu/xqemu.git
212 lines
6.2 KiB
C
212 lines
6.2 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 "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 {
|
|
/* 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"
|
|
|
|
/* Initialise gloffscreen */
|
|
static void glo_init(void) {
|
|
WNDCLASSEX wcx;
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
|
|
if (glo_inited) {
|
|
fprintf(stderr, "gloffscreen already inited\n");
|
|
abort();
|
|
}
|
|
|
|
/* 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) {
|
|
fprintf(stderr, "Unable to create window\n");
|
|
abort();
|
|
}
|
|
glo.hDC = GetDC(glo.hWnd);
|
|
|
|
/* Create a pixel format */
|
|
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;
|
|
|
|
/* Create a tempoary OpenGL 2 context */
|
|
glo.hContext = wglCreateContext(glo.hDC);
|
|
if (glo.hContext == NULL) {
|
|
fprintf(stderr, "Unable to create GL context\n");
|
|
abort();
|
|
}
|
|
wglMakeCurrent(glo.hDC, glo.hContext);
|
|
|
|
if (!epoxy_has_wgl_extension(glo.hDC, "ARB_create_context")
|
|
|| !epoxy_has_wgl_extension(glo.hDC, "ARB_pixel_format")
|
|
|| !epoxy_has_wgl_extension(glo.hDC, "ARB_pbuffer")) {
|
|
fprintf(stderr, "Unable to load the required WGL extensions\n");
|
|
abort();
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
GloContext *glo_context_create(void) {
|
|
if (!glo_inited)
|
|
glo_init();
|
|
|
|
GloContext *context = (GloContext *)malloc(sizeof(GloContext));
|
|
memset(context, 0, sizeof(GloContext));
|
|
|
|
/* Create the context proper */
|
|
const int ctx_attri[] = {
|
|
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
|
|
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
|
|
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
|
|
0
|
|
};
|
|
|
|
context->hDC = glo.hDC;
|
|
context->hContext = wglCreateContextAttribsARB(context->hDC, 0, ctx_attri);
|
|
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)
|
|
{
|
|
epoxy_handle_external_wglMakeCurrent();
|
|
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);
|
|
}
|