/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkWGL.h"
#include "SkTDArray.h"
#include "SkTSearch.h"
bool SkWGLExtensions::hasExtension(HDC dc, const char* ext) const {
if (NULL == this->fGetExtensionsString) {
return false;
}
if (!strcmp("WGL_ARB_extensions_string", ext)) {
return true;
}
const char* extensionString = this->getExtensionsString(dc);
int extLength = strlen(ext);
while (true) {
int n = strcspn(extensionString, " ");
if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
return true;
}
if (0 == extensionString[n]) {
return false;
}
extensionString += n+1;
}
return false;
}
const char* SkWGLExtensions::getExtensionsString(HDC hdc) const {
return fGetExtensionsString(hdc);
}
BOOL SkWGLExtensions::choosePixelFormat(HDC hdc,
const int* piAttribIList,
const FLOAT* pfAttribFList,
UINT nMaxFormats,
int* piFormats,
UINT* nNumFormats) const {
return fChoosePixelFormat(hdc, piAttribIList, pfAttribFList,
nMaxFormats, piFormats, nNumFormats);
}
BOOL SkWGLExtensions::getPixelFormatAttribiv(HDC hdc,
int iPixelFormat,
int iLayerPlane,
UINT nAttributes,
const int *piAttributes,
int *piValues) const {
return fGetPixelFormatAttribiv(hdc, iPixelFormat, iLayerPlane,
nAttributes, piAttributes, piValues);
}
BOOL SkWGLExtensions::getPixelFormatAttribfv(HDC hdc,
int iPixelFormat,
int iLayerPlane,
UINT nAttributes,
const int *piAttributes,
float *pfValues) const {
return fGetPixelFormatAttribfv(hdc, iPixelFormat, iLayerPlane,
nAttributes, piAttributes, pfValues);
}
HGLRC SkWGLExtensions::createContextAttribs(HDC hDC,
HGLRC hShareContext,
const int *attribList) const {
return fCreateContextAttribs(hDC, hShareContext, attribList);
}
namespace {
struct PixelFormat {
int fFormat;
int fCoverageSamples;
int fColorSamples;
int fChoosePixelFormatRank;
};
int compare_pf(const PixelFormat* a, const PixelFormat* b) {
if (a->fCoverageSamples < b->fCoverageSamples) {
return -1;
} else if (b->fCoverageSamples < a->fCoverageSamples) {
return 1;
} else if (a->fColorSamples < b->fColorSamples) {
return -1;
} else if (b->fColorSamples < a->fColorSamples) {
return 1;
} else if (a->fChoosePixelFormatRank < b->fChoosePixelFormatRank) {
return -1;
} else if (b->fChoosePixelFormatRank < a->fChoosePixelFormatRank) {
return 1;
}
return 0;
}
}
int SkWGLExtensions::selectFormat(const int formats[],
int formatCount,
HDC dc,
int desiredSampleCount) {
PixelFormat desiredFormat = {
0,
desiredSampleCount,
0,
0,
};
SkTDArray<PixelFormat> rankedFormats;
rankedFormats.setCount(formatCount);
bool supportsCoverage = this->hasExtension(dc,
"WGL_NV_multisample_coverage");
for (int i = 0; i < formatCount; ++i) {
static const int queryAttrs[] = {
SK_WGL_COVERAGE_SAMPLES,
// Keep COLOR_SAMPLES at the end so it can be skipped
SK_WGL_COLOR_SAMPLES,
};
int answers[2];
int queryAttrCnt = supportsCoverage ?
SK_ARRAY_COUNT(queryAttrs) :
SK_ARRAY_COUNT(queryAttrs) - 1;
this->getPixelFormatAttribiv(dc,
formats[i],
0,
queryAttrCnt,
queryAttrs,
answers);
rankedFormats[i].fFormat = formats[i];
rankedFormats[i].fCoverageSamples = answers[0];
rankedFormats[i].fColorSamples = answers[supportsCoverage ? 1 : 0];
rankedFormats[i].fChoosePixelFormatRank = i;
}
qsort(rankedFormats.begin(),
rankedFormats.count(),
sizeof(PixelFormat),
SkCastForQSort(compare_pf));
int idx = SkTSearch<PixelFormat>(rankedFormats.begin(),
rankedFormats.count(),
desiredFormat,
sizeof(PixelFormat),
compare_pf);
if (idx < 0) {
idx = ~idx;
}
return rankedFormats[idx].fFormat;
}
namespace {
#if defined(UNICODE)
#define STR_LIT(X) L## #X
#else
#define STR_LIT(X) #X
#endif
#define DUMMY_CLASS STR_LIT("DummyClass")
HWND create_dummy_window() {
HMODULE module = GetModuleHandle(NULL);
HWND dummy;
RECT windowRect;
windowRect.left = 0;
windowRect.right = 8;
windowRect.top = 0;
windowRect.bottom = 8;
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) DefWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = module;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = DUMMY_CLASS;
if(!RegisterClass(&wc)) {
return 0;
}
DWORD style, exStyle;
exStyle = WS_EX_CLIENTEDGE;
style = WS_SYSMENU;
AdjustWindowRectEx(&windowRect, style, false, exStyle);
if(!(dummy = CreateWindowEx(exStyle,
DUMMY_CLASS,
STR_LIT("DummyWindow"),
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
0, 0,
windowRect.right-windowRect.left,
windowRect.bottom-windowRect.top,
NULL, NULL,
module,
NULL))) {
UnregisterClass(DUMMY_CLASS, module);
return NULL;
}
ShowWindow(dummy, SW_HIDE);
return dummy;
}
void destroy_dummy_window(HWND dummy) {
DestroyWindow(dummy);
HMODULE module = GetModuleHandle(NULL);
UnregisterClass(DUMMY_CLASS, module);
}
}
#define GET_PROC(NAME, SUFFIX) f##NAME = \
(##NAME##Proc) wglGetProcAddress("wgl" #NAME #SUFFIX)
SkWGLExtensions::SkWGLExtensions()
: fGetExtensionsString(NULL)
, fChoosePixelFormat(NULL)
, fGetPixelFormatAttribfv(NULL)
, fGetPixelFormatAttribiv(NULL)
, fCreateContextAttribs(NULL) {
HDC prevDC = wglGetCurrentDC();
HGLRC prevGLRC = wglGetCurrentContext();
PIXELFORMATDESCRIPTOR dummyPFD;
ZeroMemory(&dummyPFD, sizeof(dummyPFD));
dummyPFD.nSize = sizeof(dummyPFD);
dummyPFD.nVersion = 1;
dummyPFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
dummyPFD.iPixelType = PFD_TYPE_RGBA;
dummyPFD.cColorBits = 32;
dummyPFD.cDepthBits = 0;
dummyPFD.cStencilBits = 8;
dummyPFD.iLayerType = PFD_MAIN_PLANE;
HWND dummyWND = create_dummy_window();
if (dummyWND) {
HDC dummyDC = GetDC(dummyWND);
int dummyFormat = ChoosePixelFormat(dummyDC, &dummyPFD);
SetPixelFormat(dummyDC, dummyFormat, &dummyPFD);
HGLRC dummyGLRC = wglCreateContext(dummyDC);
SkASSERT(dummyGLRC);
wglMakeCurrent(dummyDC, dummyGLRC);
GET_PROC(GetExtensionsString, ARB);
GET_PROC(ChoosePixelFormat, ARB);
GET_PROC(GetPixelFormatAttribiv, ARB);
GET_PROC(GetPixelFormatAttribfv, ARB);
GET_PROC(CreateContextAttribs, ARB);
wglMakeCurrent(dummyDC, NULL);
wglDeleteContext(dummyGLRC);
destroy_dummy_window(dummyWND);
}
wglMakeCurrent(prevDC, prevGLRC);
}