997 lines
26 KiB
C++
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, ©NumOfAASamples, 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;
|
|
}
|