blender/intern/ghost/intern/GHOST_ContextWGL.cpp
2016-09-01 14:00:20 -06:00

997 lines
26 KiB
C++

/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2013 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Jason Wilkins
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file ghost/intern/GHOST_ContextWGL.cpp
* \ingroup GHOST
*
* Definition of GHOST_ContextWGL class.
*/
#include "GHOST_ContextWGL.h"
#include <tchar.h>
#include <cstdio>
#include <cassert>
#include <vector>
#ifdef WITH_GLEW_MX
WGLEWContext *wglewContext = NULL;
#endif
HGLRC GHOST_ContextWGL::s_sharedHGLRC = NULL;
int GHOST_ContextWGL::s_sharedCount = 0;
bool GHOST_ContextWGL::s_singleContextMode = false;
/* Intel video-cards don't work fine with multiple contexts and
* have to share the same context for all windows.
* But if we just share context for all windows it could work incorrect
* with multiple videocards configuration. Suppose, that Intel videocards
* can't be in multiple-devices configuration. */
static bool is_crappy_intel_card()
{
return strstr((const char *)glGetString(GL_VENDOR), "Intel") != NULL;
}
GHOST_ContextWGL::GHOST_ContextWGL(
bool stereoVisual,
bool alphaBackground,
GHOST_TUns16 numOfAASamples,
HWND hWnd,
HDC hDC,
int contextProfileMask,
int contextMajorVersion,
int contextMinorVersion,
int contextFlags,
int contextResetNotificationStrategy)
: GHOST_Context(stereoVisual, numOfAASamples),
m_hWnd(hWnd),
m_hDC(hDC),
m_contextProfileMask(contextProfileMask),
m_contextMajorVersion(contextMajorVersion),
m_contextMinorVersion(contextMinorVersion),
m_contextFlags(contextFlags),
m_alphaBackground(alphaBackground),
m_contextResetNotificationStrategy(contextResetNotificationStrategy),
m_hGLRC(NULL)
#ifdef WITH_GLEW_MX
,
m_wglewContext(NULL)
#endif
#ifndef NDEBUG
,
m_dummyVendor(NULL),
m_dummyRenderer(NULL),
m_dummyVersion(NULL)
#endif
{
assert(m_hWnd);
assert(m_hDC);
}
GHOST_ContextWGL::~GHOST_ContextWGL()
{
if (m_hGLRC != NULL) {
if (m_hGLRC == ::wglGetCurrentContext())
WIN32_CHK(::wglMakeCurrent(NULL, NULL));
if (m_hGLRC != s_sharedHGLRC || s_sharedCount == 1) {
assert(s_sharedCount > 0);
s_sharedCount--;
if (s_sharedCount == 0)
s_sharedHGLRC = NULL;
WIN32_CHK(::wglDeleteContext(m_hGLRC));
}
}
#ifdef WITH_GLEW_MX
delete m_wglewContext;
#endif
#ifndef NDEBUG
free((void*)m_dummyRenderer);
free((void*)m_dummyVendor);
free((void*)m_dummyVersion);
#endif
}
GHOST_TSuccess GHOST_ContextWGL::swapBuffers()
{
return WIN32_CHK(::SwapBuffers(m_hDC)) ? GHOST_kSuccess : GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextWGL::setSwapInterval(int interval)
{
if (WGLEW_EXT_swap_control)
return WIN32_CHK(::wglSwapIntervalEXT(interval)) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
else
return GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextWGL::getSwapInterval(int &intervalOut)
{
if (WGLEW_EXT_swap_control) {
intervalOut = ::wglGetSwapIntervalEXT();
return GHOST_kSuccess;
}
else {
return GHOST_kFailure;
}
}
GHOST_TSuccess GHOST_ContextWGL::activateDrawingContext()
{
if (WIN32_CHK(::wglMakeCurrent(m_hDC, m_hGLRC))) {
activateGLEW();
return GHOST_kSuccess;
}
else {
return GHOST_kFailure;
}
}
/* Ron Fosner's code for weighting pixel formats and forcing software.
* See http://www.opengl.org/resources/faq/technical/weight.cpp
*/
static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd, PIXELFORMATDESCRIPTOR &preferredPFD)
{
int weight = 0;
/* assume desktop color depth is 32 bits per pixel */
/* cull unusable pixel formats */
/* if no formats can be found, can we determine why it was rejected? */
if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL) ||
!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
!(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */
!(pfd.iPixelType == PFD_TYPE_RGBA) ||
(pfd.cDepthBits < 16) ||
(pfd.cColorBits > 32) || /* 64 bit formats disable aero */
(pfd.dwFlags & PFD_GENERIC_FORMAT)) /* no software renderers */
{
return 0;
}
weight = 1; /* it's usable */
/* the bigger the depth buffer the better */
/* give no weight to a 16-bit depth buffer, because those are crap */
weight += pfd.cDepthBits - 16;
weight += pfd.cColorBits - 8;
if (preferredPFD.cAlphaBits > 0 && pfd.cAlphaBits > 0)
weight++;
#ifdef WIN32_COMPOSITING
if ((preferredPFD.dwFlags & PFD_SUPPORT_COMPOSITION) && (pfd.dwFlags & PFD_SUPPORT_COMPOSITION))
weight++;
#endif
#ifdef GHOST_OPENGL_STENCIL
if (pfd.cStencilBits >= 8)
weight++;
#endif
/* want swap copy capability -- it matters a lot */
if (pfd.dwFlags & PFD_SWAP_COPY)
weight += 16;
return weight;
}
/*
* A modification of Ron Fosner's replacement for ChoosePixelFormat
* returns 0 on error, else returns the pixel format number to be used
*/
static int choose_pixel_format_legacy(HDC hDC, PIXELFORMATDESCRIPTOR &preferredPFD)
{
int iPixelFormat = 0;
int weight = 0;
int iStereoPixelFormat = 0;
int stereoWeight = 0;
/* choose a pixel format using the useless Windows function in case we come up empty handed */
int iLastResortPixelFormat = ::ChoosePixelFormat(hDC, &preferredPFD);
WIN32_CHK(iLastResortPixelFormat != 0);
int lastPFD = ::DescribePixelFormat(hDC, 1, sizeof(PIXELFORMATDESCRIPTOR), NULL);
WIN32_CHK(lastPFD != 0);
for (int i = 1; i <= lastPFD; i++) {
PIXELFORMATDESCRIPTOR pfd;
int check = ::DescribePixelFormat(hDC, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
WIN32_CHK(check == lastPFD);
int w = weight_pixel_format(pfd, preferredPFD);
if (w > weight) {
weight = w;
iPixelFormat = i;
}
if (w > stereoWeight && (preferredPFD.dwFlags & pfd.dwFlags & PFD_STEREO)) {
stereoWeight = w;
iStereoPixelFormat = i;
}
}
/* choose any available stereo format over a non-stereo format */
if (iStereoPixelFormat != 0)
iPixelFormat = iStereoPixelFormat;
if (iPixelFormat == 0) {
fprintf(stderr, "Warning! Using result of ChoosePixelFormat.\n");
iPixelFormat = iLastResortPixelFormat;
}
return iPixelFormat;
}
/*
* Clone a window for the purpose of creating a temporary context to initialize WGL extensions.
* There is no generic way to clone the lpParam parameter, so the caller is responsible for cloning it themselves.
*/
static HWND clone_window(HWND hWnd, LPVOID lpParam)
{
int count;
SetLastError(NO_ERROR);
DWORD dwExStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
WIN32_CHK(GetLastError() == NO_ERROR);
WCHAR lpClassName[100] = L"";
count = GetClassNameW(hWnd, lpClassName, sizeof(lpClassName));
WIN32_CHK(count != 0);
WCHAR lpWindowName[100] = L"";
count = GetWindowTextW(hWnd, lpWindowName, sizeof(lpWindowName));
WIN32_CHK(count != 0);
DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
WIN32_CHK(GetLastError() == NO_ERROR);
RECT rect;
GetWindowRect(hWnd, &rect);
WIN32_CHK(GetLastError() == NO_ERROR);
HWND hWndParent = (HWND)GetWindowLongPtr(hWnd, GWLP_HWNDPARENT);
WIN32_CHK(GetLastError() == NO_ERROR);
HMENU hMenu = GetMenu(hWnd);
WIN32_CHK(GetLastError() == NO_ERROR);
HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
WIN32_CHK(GetLastError() == NO_ERROR);
HWND hwndCloned = CreateWindowExW(
dwExStyle,
lpClassName,
lpWindowName,
dwStyle,
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
hWndParent,
hMenu,
hInstance,
lpParam);
WIN32_CHK(hwndCloned != NULL);
return hwndCloned;
}
void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD)
{
HWND dummyHWND = NULL;
HDC dummyHDC = NULL;
HGLRC dummyHGLRC = NULL;
HDC prevHDC;
HGLRC prevHGLRC;
int iPixelFormat;
#ifdef WITH_GLEW_MX
wglewContext = new WGLEWContext;
memset(wglewContext, 0, sizeof(WGLEWContext));
delete m_wglewContext;
m_wglewContext = wglewContext;
#endif
SetLastError(NO_ERROR);
prevHDC = ::wglGetCurrentDC();
WIN32_CHK(GetLastError() == NO_ERROR);
prevHGLRC = ::wglGetCurrentContext();
WIN32_CHK(GetLastError() == NO_ERROR);
dummyHWND = clone_window(m_hWnd, NULL);
if (dummyHWND == NULL)
goto finalize;
dummyHDC = GetDC(dummyHWND);
if (!WIN32_CHK(dummyHDC != NULL))
goto finalize;
iPixelFormat = choose_pixel_format_legacy(dummyHDC, preferredPFD);
if (iPixelFormat == 0)
goto finalize;
PIXELFORMATDESCRIPTOR chosenPFD;
if (!WIN32_CHK(::DescribePixelFormat(dummyHDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD)))
goto finalize;
if (!WIN32_CHK(::SetPixelFormat(dummyHDC, iPixelFormat, &chosenPFD)))
goto finalize;
dummyHGLRC = ::wglCreateContext(dummyHDC);
if (!WIN32_CHK(dummyHGLRC != NULL))
goto finalize;
if (!WIN32_CHK(::wglMakeCurrent(dummyHDC, dummyHGLRC)))
goto finalize;
#ifdef WITH_GLEW_MX
if (GLEW_CHK(wglewInit()) != GLEW_OK)
fprintf(stderr, "Warning! WGLEW failed to initialize properly.\n");
#else
if (GLEW_CHK(glewInit()) != GLEW_OK)
fprintf(stderr, "Warning! Dummy GLEW/WGLEW failed to initialize properly.\n");
#endif
// the following are not technially WGLEW, but they also require a context to work
#ifndef NDEBUG
free((void*)m_dummyRenderer);
free((void*)m_dummyVendor);
free((void*)m_dummyVersion);
m_dummyRenderer = _strdup(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
m_dummyVendor = _strdup(reinterpret_cast<const char *>(glGetString(GL_VENDOR)));
m_dummyVersion = _strdup(reinterpret_cast<const char *>(glGetString(GL_VERSION)));
#endif
s_singleContextMode = is_crappy_intel_card();
finalize:
WIN32_CHK(::wglMakeCurrent(prevHDC, prevHGLRC));
if (dummyHGLRC != NULL)
WIN32_CHK(::wglDeleteContext(dummyHGLRC));
if (dummyHWND != NULL) {
if (dummyHDC != NULL)
WIN32_CHK(::ReleaseDC(dummyHWND, dummyHDC));
WIN32_CHK(::DestroyWindow(dummyHWND));
}
}
static void makeAttribList(
std::vector<int>& out,
bool stereoVisual,
int numOfAASamples,
int swapMethod,
bool needAlpha,
bool needStencil,
bool sRGB)
{
out.clear();
out.reserve(30);
out.push_back(WGL_SUPPORT_OPENGL_ARB);
out.push_back(GL_TRUE);
out.push_back(WGL_DRAW_TO_WINDOW_ARB);
out.push_back(GL_TRUE);
out.push_back(WGL_DOUBLE_BUFFER_ARB);
out.push_back(GL_TRUE);
out.push_back(WGL_ACCELERATION_ARB);
out.push_back(WGL_FULL_ACCELERATION_ARB);
out.push_back(WGL_SWAP_METHOD_ARB);
out.push_back(swapMethod);
if (stereoVisual) {
out.push_back(WGL_STEREO_ARB);
out.push_back(GL_TRUE);
}
out.push_back(WGL_PIXEL_TYPE_ARB);
out.push_back(WGL_TYPE_RGBA_ARB);
out.push_back(WGL_COLOR_BITS_ARB);
out.push_back(24);
out.push_back(WGL_DEPTH_BITS_ARB);
out.push_back(24);
if (needAlpha) {
out.push_back(WGL_ALPHA_BITS_ARB);
out.push_back(8);
}
if (needStencil) {
out.push_back(WGL_STENCIL_BITS_ARB);
out.push_back(8);
}
if (numOfAASamples > 0) {
out.push_back(WGL_SAMPLES_ARB);
out.push_back(numOfAASamples);
out.push_back(WGL_SAMPLE_BUFFERS_ARB);
out.push_back(GL_TRUE);
}
if (sRGB) {
out.push_back(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB);
out.push_back(GL_TRUE);
}
out.push_back(0);
}
int GHOST_ContextWGL::_choose_pixel_format_arb_2(
bool stereoVisual,
int *numOfAASamples,
bool needAlpha,
bool needStencil,
bool sRGB,
int swapMethod)
{
std::vector<int> iAttributes;
#define _MAX_PIXEL_FORMATS 32
int iPixelFormat = 0;
int iPixelFormats[_MAX_PIXEL_FORMATS];
int samples;
// guard against some insanely high number of samples
if (*numOfAASamples > 64) {
fprintf(stderr, "Warning! Clamping number of samples to 64.\n");
samples = 64;
}
else {
samples = *numOfAASamples;
}
// request a format with as many samples as possible, but not more than requested
while (samples >= 0) {
makeAttribList(
iAttributes,
stereoVisual,
samples,
swapMethod,
needAlpha,
needStencil,
sRGB);
UINT nNumFormats;
WIN32_CHK(wglChoosePixelFormatARB(m_hDC, &(iAttributes[0]), NULL, _MAX_PIXEL_FORMATS, iPixelFormats, &nNumFormats));
#ifdef WIN32_COMPOSITING
if (needAlpha && nNumFormats) {
// scan through all pixel format to make sure one supports compositing
PIXELFORMATDESCRIPTOR pfd;
int i;
for (i = 0; i < nNumFormats; i++) {
if (DescribePixelFormat(m_hDC, iPixelFormats[i], sizeof(PIXELFORMATDESCRIPTOR), &pfd)) {
if (pfd.dwFlags & PFD_SUPPORT_COMPOSITION) {
iPixelFormat = iPixelFormats[i];
break;
}
}
}
if (i == nNumFormats) {
fprintf(stderr,
"Warning! Unable to find a pixel format with compositing capability.\n");
iPixelFormat = iPixelFormats[0];
}
}
else
#endif
iPixelFormat = iPixelFormats[0];
/* total number of formats that match (regardless of size of iPixelFormat array)
* see: WGL_ARB_pixel_format extension spec */
if (nNumFormats > 0)
break;
/* if not reset, then the state of iPixelFormat is undefined after call to wglChoosePixelFormatARB
* see: WGL_ARB_pixel_format extension spec */
iPixelFormat = 0;
samples--;
}
// check how many samples were actually gotten
if (iPixelFormat != 0) {
int iQuery[] = { WGL_SAMPLES_ARB };
int actualSamples, alphaBits;
wglGetPixelFormatAttribivARB(m_hDC, iPixelFormat, 0, 1, iQuery, &actualSamples);
if (actualSamples != *numOfAASamples) {
fprintf(stderr,
"Warning! Unable to find a multisample pixel format that supports exactly %d samples. "
"Substituting one that uses %d samples.\n",
*numOfAASamples, actualSamples);
*numOfAASamples = actualSamples; // set context property to actual value
}
if (needAlpha) {
iQuery[0] = WGL_ALPHA_BITS_ARB;
wglGetPixelFormatAttribivARB(m_hDC, iPixelFormat, 0, 1, iQuery, &alphaBits);
if (alphaBits == 0) {
fprintf(stderr,
"Warning! Unable to find a frame buffer with alpha channel.\n");
}
}
}
else {
*numOfAASamples = 0;
}
return iPixelFormat;
}
int GHOST_ContextWGL::_choose_pixel_format_arb_1(bool stereoVisual,
int numOfAASamples,
bool needAlpha,
bool needStencil,
bool sRGB,
int *swapMethodOut)
{
int iPixelFormat;
int copyPixelFormat = 0;
int undefPixelFormat = 0;
int exchPixelFormat = 0;
int copyNumOfAASamples = 0;
int undefNumOfAASamples = 0;
int exchNumOfAASamples = 0;
*swapMethodOut = WGL_SWAP_COPY_ARB;
copyNumOfAASamples = numOfAASamples;
copyPixelFormat = _choose_pixel_format_arb_2(
stereoVisual, &copyNumOfAASamples, needAlpha, needStencil, sRGB, *swapMethodOut);
if (copyPixelFormat == 0 || copyNumOfAASamples < numOfAASamples) {
*swapMethodOut = WGL_SWAP_UNDEFINED_ARB;
undefNumOfAASamples = numOfAASamples;
undefPixelFormat = _choose_pixel_format_arb_2(
stereoVisual, &undefNumOfAASamples, needAlpha, needStencil, sRGB, *swapMethodOut);
if (undefPixelFormat == 0 || undefNumOfAASamples < numOfAASamples) {
*swapMethodOut = WGL_SWAP_EXCHANGE_ARB;
exchNumOfAASamples = numOfAASamples;
exchPixelFormat = _choose_pixel_format_arb_2(
stereoVisual, &exchNumOfAASamples, needAlpha, needStencil, sRGB, *swapMethodOut);
if (exchPixelFormat == 0 || exchNumOfAASamples < numOfAASamples) {
// the number of AA samples cannot be met, take the highest
if (undefPixelFormat != 0 && undefNumOfAASamples >= exchNumOfAASamples) {
exchNumOfAASamples = undefNumOfAASamples;
exchPixelFormat = undefPixelFormat;
*swapMethodOut = WGL_SWAP_UNDEFINED_ARB;
}
if (copyPixelFormat != 0 && copyNumOfAASamples >= exchNumOfAASamples) {
exchNumOfAASamples = copyNumOfAASamples;
exchPixelFormat = copyPixelFormat;
*swapMethodOut = WGL_SWAP_COPY_ARB;
}
}
iPixelFormat = exchPixelFormat;
m_numOfAASamples = exchNumOfAASamples;
}
else {
iPixelFormat = undefPixelFormat;
m_numOfAASamples = undefNumOfAASamples;
}
}
else {
iPixelFormat = copyPixelFormat;
m_numOfAASamples = copyNumOfAASamples;
}
return iPixelFormat;
}
int GHOST_ContextWGL::choose_pixel_format_arb(
bool stereoVisual,
int numOfAASamples,
bool needAlpha,
bool needStencil,
bool sRGB)
{
int iPixelFormat;
int swapMethodOut;
iPixelFormat = _choose_pixel_format_arb_1(
stereoVisual,
numOfAASamples,
needAlpha,
needStencil,
sRGB,
&swapMethodOut);
if (iPixelFormat == 0 && stereoVisual) {
fprintf(stderr, "Warning! Unable to find a stereo pixel format.\n");
iPixelFormat = _choose_pixel_format_arb_1(
false,
numOfAASamples,
needAlpha,
needStencil,
sRGB,
&swapMethodOut);
m_stereoVisual = false; // set context property to actual value
}
if (swapMethodOut != WGL_SWAP_COPY_ARB) {
fprintf(stderr,
"Warning! Unable to find a pixel format that supports WGL_SWAP_COPY_ARB. "
"Substituting one that uses %s.\n",
swapMethodOut == WGL_SWAP_UNDEFINED_ARB ? "WGL_SWAP_UNDEFINED_ARB" : "WGL_SWAP_EXCHANGE_ARB");
}
return iPixelFormat;
}
int GHOST_ContextWGL::choose_pixel_format(
bool stereoVisual,
int numOfAASamples,
bool needAlpha,
bool needStencil,
bool sRGB)
{
PIXELFORMATDESCRIPTOR preferredPFD = {
sizeof(PIXELFORMATDESCRIPTOR), /* size */
1, /* version */
(DWORD) (
PFD_SUPPORT_OPENGL |
PFD_DRAW_TO_WINDOW |
PFD_SWAP_COPY | /* support swap copy */
PFD_DOUBLEBUFFER | /* support double-buffering */
(stereoVisual ? PFD_STEREO : 0) |/* support stereo */
(
#ifdef WIN32_COMPOSITING
needAlpha ? PFD_SUPPORT_COMPOSITION : /* support composition for transparent background */
#endif
0
)),
PFD_TYPE_RGBA, /* color type */
(BYTE) (needAlpha ? 32 : 24), /* preferred color depth */
0, 0, 0, 0, 0, 0, /* color bits (ignored) */
(BYTE) (needAlpha ? 8 : 0), /* alpha buffer */
0, /* alpha shift (ignored) */
0, /* no accumulation buffer */
0, 0, 0, 0, /* accum bits (ignored) */
24, /* depth buffer */
(BYTE) (needStencil ? 8 : 0), /* stencil buffer */
0, /* no auxiliary buffers */
PFD_MAIN_PLANE, /* main layer */
0, /* reserved */
0, 0, 0 /* layer, visible, and damage masks (ignored) */
};
initContextWGLEW(preferredPFD);
if (numOfAASamples > 0 && !WGLEW_ARB_multisample) {
fprintf(stderr, "Warning! Unable to request a multisample framebuffer.\n");
numOfAASamples = 0;
}
if (sRGB && !(WGLEW_ARB_framebuffer_sRGB || WGLEW_EXT_framebuffer_sRGB)) {
fprintf(stderr, "Warning! Unable to request an sRGB framebuffer.\n");
sRGB = false;
}
int iPixelFormat = 0;
if (WGLEW_ARB_pixel_format)
iPixelFormat = choose_pixel_format_arb(stereoVisual, numOfAASamples, needAlpha, needStencil, sRGB);
if (iPixelFormat == 0)
iPixelFormat = choose_pixel_format_legacy(m_hDC, preferredPFD);
return iPixelFormat;
}
#ifndef NDEBUG
static void reportContextString(const char *name, const char *dummy, const char *context)
{
fprintf(stderr, "%s: %s\n", name, context);
if (strcmp(dummy, context) != 0)
fprintf(stderr, "Warning! Dummy %s: %s\n", name, dummy);
}
#endif
GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
{
const bool needAlpha = m_alphaBackground;
#ifdef GHOST_OPENGL_STENCIL
const bool needStencil = true;
#else
const bool needStencil = false;
#endif
#ifdef GHOST_OPENGL_SRGB
const bool sRGB = true;
#else
const bool sRGB = false;
#endif
HGLRC prevHGLRC;
HDC prevHDC;
int iPixelFormat;
int lastPFD;
PIXELFORMATDESCRIPTOR chosenPFD;
SetLastError(NO_ERROR);
prevHGLRC = ::wglGetCurrentContext();
WIN32_CHK(GetLastError() == NO_ERROR);
prevHDC = ::wglGetCurrentDC();
WIN32_CHK(GetLastError() == NO_ERROR);
iPixelFormat = choose_pixel_format(m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, sRGB);
if (iPixelFormat == 0) {
::wglMakeCurrent(prevHDC, prevHGLRC);
return GHOST_kFailure;
}
lastPFD = ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD);
if (!WIN32_CHK(lastPFD != 0)) {
::wglMakeCurrent(prevHDC, prevHGLRC);
return GHOST_kFailure;
}
if (needAlpha && chosenPFD.cAlphaBits == 0)
fprintf(stderr, "Warning! Unable to find a pixel format with an alpha channel.\n");
if (needStencil && chosenPFD.cStencilBits == 0)
fprintf(stderr, "Warning! Unable to find a pixel format with a stencil buffer.\n");
if (!WIN32_CHK(::SetPixelFormat(m_hDC, iPixelFormat, &chosenPFD))) {
::wglMakeCurrent(prevHDC, prevHGLRC);
return GHOST_kFailure;
}
activateWGLEW();
if (WGLEW_ARB_create_context) {
int profileBitCore = m_contextProfileMask & WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
int profileBitCompat = m_contextProfileMask & WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
#ifdef WITH_GLEW_ES
int profileBitES = m_contextProfileMask & WGL_CONTEXT_ES_PROFILE_BIT_EXT;
#endif
if (!WGLEW_ARB_create_context_profile && profileBitCore)
fprintf(stderr, "Warning! OpenGL core profile not available.\n");
if (!WGLEW_ARB_create_context_profile && profileBitCompat)
fprintf(stderr, "Warning! OpenGL compatibility profile not available.\n");
#ifdef WITH_GLEW_ES
if (!WGLEW_EXT_create_context_es_profile && profileBitES && m_contextMajorVersion == 1)
fprintf(stderr, "Warning! OpenGL ES profile not available.\n");
if (!WGLEW_EXT_create_context_es2_profile && profileBitES && m_contextMajorVersion == 2)
fprintf(stderr, "Warning! OpenGL ES2 profile not available.\n");
#endif
int profileMask = 0;
if (WGLEW_ARB_create_context_profile && profileBitCore)
profileMask |= profileBitCore;
if (WGLEW_ARB_create_context_profile && profileBitCompat)
profileMask |= profileBitCompat;
#ifdef WITH_GLEW_ES
if (WGLEW_EXT_create_context_es_profile && profileBitES)
profileMask |= profileBitES;
#endif
if (profileMask != m_contextProfileMask)
fprintf(stderr, "Warning! Ignoring untested OpenGL context profile mask bits.");
std::vector<int> iAttributes;
if (profileMask) {
iAttributes.push_back(WGL_CONTEXT_PROFILE_MASK_ARB);
iAttributes.push_back(profileMask);
}
if (m_contextMajorVersion != 0) {
iAttributes.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB);
iAttributes.push_back(m_contextMajorVersion);
}
if (m_contextMinorVersion != 0) {
iAttributes.push_back(WGL_CONTEXT_MINOR_VERSION_ARB);
iAttributes.push_back(m_contextMinorVersion);
}
if (m_contextFlags != 0) {
iAttributes.push_back(WGL_CONTEXT_FLAGS_ARB);
iAttributes.push_back(m_contextFlags);
}
if (m_contextResetNotificationStrategy != 0) {
if (WGLEW_ARB_create_context_robustness) {
iAttributes.push_back(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
iAttributes.push_back(m_contextResetNotificationStrategy);
}
else {
fprintf(stderr, "Warning! Cannot set the reset notification strategy.");
}
}
iAttributes.push_back(0);
if (!s_singleContextMode || s_sharedHGLRC == NULL)
m_hGLRC = ::wglCreateContextAttribsARB(m_hDC, NULL, &(iAttributes[0]));
else
m_hGLRC = s_sharedHGLRC;
}
else {
if (m_contextProfileMask != 0)
fprintf(stderr, "Warning! Legacy WGL is unable to select between OpenGL profiles.");
if (m_contextMajorVersion != 0 || m_contextMinorVersion != 0)
fprintf(stderr, "Warning! Legacy WGL is unable to select between OpenGL versions.");
if (m_contextFlags != 0)
fprintf(stderr, "Warning! Legacy WGL is unable to set context flags.");
if (!s_singleContextMode || s_sharedHGLRC == NULL)
m_hGLRC = ::wglCreateContext(m_hDC);
else
m_hGLRC = s_sharedHGLRC;
}
if (!WIN32_CHK(m_hGLRC != NULL)) {
::wglMakeCurrent(prevHDC, prevHGLRC);
return GHOST_kFailure;
}
if (s_sharedHGLRC == NULL)
s_sharedHGLRC = m_hGLRC;
s_sharedCount++;
if (!s_singleContextMode && s_sharedHGLRC != m_hGLRC && !WIN32_CHK(::wglShareLists(s_sharedHGLRC, m_hGLRC))) {
::wglMakeCurrent(prevHDC, prevHGLRC);
return GHOST_kFailure;
}
if (!WIN32_CHK(::wglMakeCurrent(m_hDC, m_hGLRC))) {
::wglMakeCurrent(prevHDC, prevHGLRC);
return GHOST_kFailure;
}
initContextGLEW();
initClearGL();
::SwapBuffers(m_hDC);
const char *vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
const char *renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
const char *version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
#ifndef NDEBUG
reportContextString("Vendor", m_dummyVendor, vendor);
reportContextString("Renderer", m_dummyRenderer, renderer);
reportContextString("Version", m_dummyVersion, version);
#endif
if ((strcmp(vendor, "Microsoft Corporation") == 0 ||
strcmp(renderer, "GDI Generic") == 0) && version[0] == '1' && version[2] == '1')
{
MessageBox(m_hWnd, "Your system does not use 3D hardware acceleration.\n"
"Blender requires a graphics driver with OpenGL 2.1 support.\n\n"
"This may be caused by:\n"
"* A missing or faulty graphics driver installation.\n"
" Blender needs a graphics card driver to work correctly.\n"
"* Accessing Blender through a remote connection.\n"
"* Using Blender through a virtual machine.\n\n"
"The program will now close.",
"Blender - Can't detect 3D hardware accelerated Driver!",
MB_OK | MB_ICONERROR);
exit(0);
}
else if (version[0] < '2' || (version[0] == '2' && version[2] < '1')) {
MessageBox(m_hWnd, "Blender requires a graphics driver with OpenGL 2.1 support.\n\n"
"The program will now close.",
"Blender - Unsupported Graphics Driver!",
MB_OK | MB_ICONERROR);
exit(0);
}
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_ContextWGL::releaseNativeHandles()
{
GHOST_TSuccess success = m_hGLRC != s_sharedHGLRC || s_sharedCount == 1 ? GHOST_kSuccess : GHOST_kFailure;
m_hWnd = NULL;
m_hDC = NULL;
return success;
}