This is no longer needed with the new offscreen draw method, so use whatever is default and hopefully fastest. Fixes console warnings in some setups that don't have swap copy.
852 lines
22 KiB
C++
852 lines
22 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>
|
|
|
|
|
|
HGLRC GHOST_ContextWGL::s_sharedHGLRC = NULL;
|
|
int GHOST_ContextWGL::s_sharedCount = 0;
|
|
|
|
/* Some third-generation Intel video-cards are constantly bring problems */
|
|
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)
|
|
#ifndef NDEBUG
|
|
,
|
|
m_dummyVendor(NULL),
|
|
m_dummyRenderer(NULL),
|
|
m_dummyVersion(NULL)
|
|
#endif
|
|
{
|
|
assert(m_hDC != NULL);
|
|
}
|
|
|
|
|
|
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));
|
|
}
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
if (m_dummyRenderer) {
|
|
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))) {
|
|
return GHOST_kSuccess;
|
|
}
|
|
else {
|
|
return GHOST_kFailure;
|
|
}
|
|
}
|
|
|
|
|
|
GHOST_TSuccess GHOST_ContextWGL::releaseDrawingContext()
|
|
{
|
|
if (WIN32_CHK(::wglMakeCurrent(NULL, NULL))) {
|
|
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
|
|
|
|
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;
|
|
|
|
SetLastError(NO_ERROR);
|
|
|
|
prevHDC = ::wglGetCurrentDC();
|
|
WIN32_CHK(GetLastError() == NO_ERROR);
|
|
|
|
prevHGLRC = ::wglGetCurrentContext();
|
|
WIN32_CHK(GetLastError() == NO_ERROR);
|
|
|
|
iPixelFormat = choose_pixel_format_legacy(m_hDC, preferredPFD);
|
|
|
|
if (iPixelFormat == 0)
|
|
goto finalize;
|
|
|
|
PIXELFORMATDESCRIPTOR chosenPFD;
|
|
if (!WIN32_CHK(::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD)))
|
|
goto finalize;
|
|
|
|
if (m_hWnd) {
|
|
dummyHWND = clone_window(m_hWnd, NULL);
|
|
|
|
if (dummyHWND == NULL)
|
|
goto finalize;
|
|
|
|
dummyHDC = GetDC(dummyHWND);
|
|
}
|
|
|
|
if (!WIN32_CHK(dummyHDC != NULL))
|
|
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;
|
|
|
|
if (GLEW_CHK(glewInit()) != GLEW_OK)
|
|
fprintf(stderr, "Warning! Dummy GLEW/WGLEW failed to initialize properly.\n");
|
|
|
|
// 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
|
|
|
|
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,
|
|
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);
|
|
|
|
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_1(
|
|
bool stereoVisual,
|
|
int numOfAASamples,
|
|
bool needAlpha,
|
|
bool needStencil,
|
|
bool sRGB)
|
|
{
|
|
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,
|
|
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);
|
|
}
|
|
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");
|
|
}
|
|
}
|
|
}
|
|
return iPixelFormat;
|
|
}
|
|
|
|
|
|
int GHOST_ContextWGL::choose_pixel_format_arb(
|
|
bool stereoVisual,
|
|
int numOfAASamples,
|
|
bool needAlpha,
|
|
bool needStencil,
|
|
bool sRGB)
|
|
{
|
|
int iPixelFormat;
|
|
|
|
iPixelFormat = _choose_pixel_format_arb_1(
|
|
stereoVisual,
|
|
numOfAASamples,
|
|
needAlpha,
|
|
needStencil,
|
|
sRGB);
|
|
|
|
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);
|
|
|
|
m_stereoVisual = false; // set context property to actual value
|
|
}
|
|
|
|
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_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 (dummy && strcmp(dummy, context) != 0)
|
|
fprintf(stderr, "Warning! Dummy %s: %s\n", name, dummy);
|
|
}
|
|
#endif
|
|
|
|
|
|
GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
|
|
{
|
|
SetLastError(NO_ERROR);
|
|
|
|
HGLRC prevHGLRC = ::wglGetCurrentContext();
|
|
WIN32_CHK(GetLastError() == NO_ERROR);
|
|
|
|
HDC prevHDC = ::wglGetCurrentDC();
|
|
WIN32_CHK(GetLastError() == NO_ERROR);
|
|
|
|
if (!WGLEW_ARB_create_context || ::GetPixelFormat(m_hDC) == 0) {
|
|
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
|
|
int iPixelFormat;
|
|
int lastPFD;
|
|
|
|
PIXELFORMATDESCRIPTOR chosenPFD;
|
|
|
|
iPixelFormat = choose_pixel_format(m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, sRGB);
|
|
|
|
if (iPixelFormat == 0) {
|
|
goto error;
|
|
}
|
|
|
|
lastPFD = ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD);
|
|
|
|
if (!WIN32_CHK(lastPFD != 0)) {
|
|
goto error;
|
|
}
|
|
|
|
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))) {
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
m_hGLRC = ::wglCreateContextAttribsARB(m_hDC, NULL, &(iAttributes[0]));
|
|
}
|
|
|
|
if (!WIN32_CHK(m_hGLRC != NULL)) {
|
|
goto error;
|
|
}
|
|
|
|
s_sharedCount++;
|
|
|
|
if (s_sharedHGLRC == NULL) {
|
|
s_sharedHGLRC = m_hGLRC;
|
|
}
|
|
else if (!WIN32_CHK(::wglShareLists(s_sharedHGLRC, m_hGLRC))) {
|
|
goto error;
|
|
}
|
|
|
|
if (!WIN32_CHK(::wglMakeCurrent(m_hDC, m_hGLRC))) {
|
|
goto error;
|
|
}
|
|
|
|
initContextGLEW();
|
|
|
|
if (is_crappy_intel_card()) {
|
|
/* Some Intel cards with context 4.1 or 4.2
|
|
* don't have the point sprite enabled by default.
|
|
*
|
|
* However GL_POINT_SPRITE was removed in 3.2 and is now permanently ON.
|
|
* Then use brute force. */
|
|
glEnable(GL_POINT_SPRITE);
|
|
}
|
|
|
|
initClearGL();
|
|
::SwapBuffers(m_hDC);
|
|
|
|
#ifndef NDEBUG
|
|
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));
|
|
|
|
reportContextString("Vendor", m_dummyVendor, vendor);
|
|
reportContextString("Renderer", m_dummyRenderer, renderer);
|
|
reportContextString("Version", m_dummyVersion, version);
|
|
|
|
fprintf(stderr, "Context Version: %d.%d\n", m_contextMajorVersion, m_contextMinorVersion);
|
|
#endif
|
|
|
|
return GHOST_kSuccess;
|
|
error:
|
|
::wglMakeCurrent(prevHDC, prevHGLRC);
|
|
return GHOST_kFailure;
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
}
|