Add SkWGLExtensionInterface for dealing with WGL extensions

Review URL: http://codereview.appspot.com/5447059

git-svn-id: http://skia.googlecode.com/svn/trunk@2777 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bsalomon@google.com 2011-12-01 16:34:28 +00:00
Родитель 06711bd972
Коммит bd7c64150c
4 изменённых файлов: 770 добавлений и 3 удалений

Просмотреть файл

@ -36,6 +36,7 @@
'../include/utils/SkSfntUtils.h',
'../include/utils/SkTextBox.h',
'../include/utils/SkUnitMappers.h',
'../include/utils/SkWGL.h',
'../src/utils/SkBoundaryPatch.cpp',
'../src/utils/SkCamera.cpp',
@ -77,7 +78,8 @@
'../src/utils/win/skia_win.cpp',
'../src/utils/win/SkHRESULT.cpp',
'../src/utils/win/SkIStream.cpp',
'../src/utils/win/SkOSWindow_Win.cpp',
'../src/utils/win/SkOSWindow_win.cpp',
'../src/utils/win/SkWGL_win.cpp',
],
'sources!': [
'../src/utils/SDL/SkOSWindow_SDL.cpp',
@ -131,16 +133,15 @@
'include_dirs!': [
'../include/utils/win',
],
'sources/': [ ['exclude', '_win.(h|cpp)$'],],
'sources!': [
'../include/utils/win/SkAutoCoInitialize.h',
'../include/utils/win/SkHRESULT.h',
'../include/utils/win/SkIStream.h',
'../include/utils/win/SkTScopedComPtr.h',
'../src/utils/win/SkAutoCoInitialize.cpp',
'../src/utils/win/skia_win.cpp',
'../src/utils/win/SkHRESULT.cpp',
'../src/utils/win/SkIStream.cpp',
'../src/utils/win/SkOSWindow_Win.cpp',
],
}],
],

90
include/utils/SkWGL.h Normal file
Просмотреть файл

@ -0,0 +1,90 @@
/*
* 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 "SkRefCnt.h"
#ifndef SkWGL_DEFINED
#define SkWGL_DEFINED
/**
* Working with WGL extensions can be a pain. Among the reasons is that You must
* have a GL context to get the proc addresses, but you want to use the procs to
* create a context in the first place. So you have to create a dummy GL ctx to
* get the proc addresses.
*
* This file helps by providing SkCreateWGLInterface(). It returns a struct of
* function pointers that it initializes. It also has a helper function to query
* for WGL extensions. It handles the fact that wglGetExtensionsString is itself
* an extension.
*/
#if !defined(WIN32_LEAN_AND_MEAN)
#define WIN32_LEAN_AND_MEAN
#define SK_LOCAL_LEAN_AND_MEAN
#endif
#include <Windows.h>
#if defined(SK_LOCAL_LEAN_AND_MEAN)
#undef WIN32_LEAN_AND_MEAN
#undef SK_LOCAL_LEAN_AND_MEAN
#endif
#define SK_WGL_DRAW_TO_WINDOW_ARB 0x2001
#define SK_WGL_ACCELERATION_ARB 0x2003
#define SK_WGL_SUPPORT_OPENGL_ARB 0x2010
#define SK_WGL_DOUBLE_BUFFER_ARB 0x2011
#define SK_WGL_COLOR_BITS_ARB 0x2014
#define SK_WGL_ALPHA_BITS_ARB 0x201B
#define SK_WGL_STENCIL_BITS_ARB 0x2023
#define SK_WGL_FULL_ACCELERATION_ARB 0x2027
#define SK_WGL_SAMPLE_BUFFERS_ARB 0x2041
#define SK_WGL_SAMPLES_ARB 0x2042
#define SK_WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define SK_WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
#define SK_WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
#define SK_WGL_CONTEXT_FLAGS_ARB 0x2094
#define SK_WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
#define SK_WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
#define SK_WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
#define SK_WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define SK_WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#define SK_WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
#define SK_ERROR_INVALID_VERSION_ARB 0x2095
#define SK_ERROR_INVALID_PROFILE_ARB 0x2096
class SkWGLExtensions {
public:
SkWGLExtensions();
/**
* Determines if an extensions is available for a given DC.
* WGL_ARB_extensions_string is considered a prerequisite for all other
* extensions. It is necessary to check this before calling other class
* functions.
*/
bool hasExtension(HDC dc, const char* ext) const;
const char* getExtensionsString(HDC hdc) const;
BOOL choosePixelFormat(HDC hdc, const int*, const FLOAT*, UINT, int*, UINT*) const;
BOOL getPixelFormatAttribiv(HDC, int, int, UINT, const int*, int*) const;
BOOL getPixelFormatAttribfv(HDC hdc, int, int, UINT, const int*, FLOAT*) const;
HGLRC createContextAttribs(HDC, HGLRC, const int *) const;
private:
typedef const char* (WINAPI *GetExtensionsStringProc)(HDC hdc);
typedef BOOL (WINAPI *ChoosePixelFormatProc)(HDC hdc, const int *, const FLOAT *, UINT, int *, UINT *);
typedef BOOL (WINAPI *GetPixelFormatAttribivProc)(HDC, int, int, UINT, const int*, int*);
typedef BOOL (WINAPI *GetPixelFormatAttribfvProc)(HDC hdc, int, int, UINT, const int*, FLOAT*);
typedef HGLRC (WINAPI *CreateContextAttribsProc)(HDC hDC, HGLRC, const int *);
GetExtensionsStringProc fGetExtensionsString;
ChoosePixelFormatProc fChoosePixelFormat;
GetPixelFormatAttribfvProc fGetPixelFormatAttribfv;
GetPixelFormatAttribivProc fGetPixelFormatAttribiv;
CreateContextAttribsProc fCreateContextAttribs;
};
#endif

Просмотреть файл

@ -0,0 +1,492 @@
/*
* 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 "SkTypes.h"
#if defined(SK_BUILD_FOR_WIN)
#include <GL/gl.h>
#include <d3d9.h>
#include <WindowsX.h>
#include "SkWGL.h"
#include "SkWindow.h"
#include "SkCanvas.h"
#include "SkOSMenu.h"
#include "SkTime.h"
#include "SkUtils.h"
#include "SkGraphics.h"
#define INVALIDATE_DELAY_MS 200
static SkOSWindow* gCurrOSWin;
static HWND gEventTarget;
#define WM_EVENT_CALLBACK (WM_USER+0)
void post_skwinevent()
{
PostMessage(gEventTarget, WM_EVENT_CALLBACK, 0, 0);
}
SkOSWindow::SkOSWindow(void* hWnd) : fHWND(hWnd),
fHGLRC(NULL),
fGLAttached(false),
fD3D9Device(NULL),
fD3D9Attached(FALSE) {
gEventTarget = (HWND)hWnd;
}
SkOSWindow::~SkOSWindow() {
if (NULL != fD3D9Device) {
((IDirect3DDevice9*)fD3D9Device)->Release();
}
if (NULL != fHGLRC) {
wglDeleteContext((HGLRC)fHGLRC);
}
}
static SkKey winToskKey(WPARAM vk) {
static const struct {
WPARAM fVK;
SkKey fKey;
} gPair[] = {
{ VK_BACK, kBack_SkKey },
{ VK_CLEAR, kBack_SkKey },
{ VK_RETURN, kOK_SkKey },
{ VK_UP, kUp_SkKey },
{ VK_DOWN, kDown_SkKey },
{ VK_LEFT, kLeft_SkKey },
{ VK_RIGHT, kRight_SkKey }
};
for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
if (gPair[i].fVK == vk) {
return gPair[i].fKey;
}
}
return kNONE_SkKey;
}
bool SkOSWindow::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_KEYDOWN: {
SkKey key = winToskKey(wParam);
if (kNONE_SkKey != key) {
this->handleKey(key);
return true;
}
} break;
case WM_KEYUP: {
SkKey key = winToskKey(wParam);
if (kNONE_SkKey != key) {
this->handleKeyUp(key);
return true;
}
} break;
case WM_UNICHAR:
this->handleChar(wParam);
return true;
case WM_CHAR: {
this->handleChar(SkUTF8_ToUnichar((char*)&wParam));
return true;
} break;
case WM_SIZE:
this->resize(lParam & 0xFFFF, lParam >> 16);
break;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
this->doPaint(hdc);
EndPaint(hWnd, &ps);
return true;
} break;
case WM_TIMER: {
RECT* rect = (RECT*)wParam;
InvalidateRect(hWnd, rect, FALSE);
KillTimer(hWnd, (UINT_PTR)rect);
delete rect;
return true;
} break;
case WM_LBUTTONDOWN:
this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), Click::kDown_State);
return true;
case WM_MOUSEMOVE:
this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), Click::kMoved_State);
return true;
case WM_LBUTTONUP:
this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), Click::kUp_State);
return true;
case WM_EVENT_CALLBACK:
if (SkEvent::ProcessEvent()) {
post_skwinevent();
}
return true;
}
return false;
}
void SkOSWindow::doPaint(void* ctx) {
this->update(NULL);
if (!fGLAttached && !fD3D9Attached)
{
HDC hdc = (HDC)ctx;
const SkBitmap& bitmap = this->getBitmap();
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = bitmap.width();
bmi.bmiHeader.biHeight = -bitmap.height(); // top-down image
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 0;
//
// Do the SetDIBitsToDevice.
//
// TODO(wjmaclean):
// Fix this call to handle SkBitmaps that have rowBytes != width,
// i.e. may have padding at the end of lines. The SkASSERT below
// may be ignored by builds, and the only obviously safe option
// seems to be to copy the bitmap to a temporary (contiguous)
// buffer before passing to SetDIBitsToDevice().
SkASSERT(bitmap.width() * bitmap.bytesPerPixel() == bitmap.rowBytes());
bitmap.lockPixels();
int iRet = SetDIBitsToDevice(hdc,
0, 0,
bitmap.width(), bitmap.height(),
0, 0,
0, bitmap.height(),
bitmap.getPixels(),
&bmi,
DIB_RGB_COLORS);
bitmap.unlockPixels();
}
}
#if 0
void SkOSWindow::updateSize()
{
RECT r;
GetWindowRect((HWND)this->getHWND(), &r);
this->resize(r.right - r.left, r.bottom - r.top);
}
#endif
void SkOSWindow::onHandleInval(const SkIRect& r) {
RECT* rect = new RECT;
rect->left = r.fLeft;
rect->top = r.fTop;
rect->right = r.fRight;
rect->bottom = r.fBottom;
SetTimer((HWND)fHWND, (UINT_PTR)rect, INVALIDATE_DELAY_MS, NULL);
}
void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)
{
}
void SkOSWindow::onSetTitle(const char title[]){
SetWindowTextA((HWND)fHWND, title);
}
enum {
SK_MacReturnKey = 36,
SK_MacDeleteKey = 51,
SK_MacEndKey = 119,
SK_MacLeftKey = 123,
SK_MacRightKey = 124,
SK_MacDownKey = 125,
SK_MacUpKey = 126,
SK_Mac0Key = 0x52,
SK_Mac1Key = 0x53,
SK_Mac2Key = 0x54,
SK_Mac3Key = 0x55,
SK_Mac4Key = 0x56,
SK_Mac5Key = 0x57,
SK_Mac6Key = 0x58,
SK_Mac7Key = 0x59,
SK_Mac8Key = 0x5b,
SK_Mac9Key = 0x5c
};
static SkKey raw2key(uint32_t raw)
{
static const struct {
uint32_t fRaw;
SkKey fKey;
} gKeys[] = {
{ SK_MacUpKey, kUp_SkKey },
{ SK_MacDownKey, kDown_SkKey },
{ SK_MacLeftKey, kLeft_SkKey },
{ SK_MacRightKey, kRight_SkKey },
{ SK_MacReturnKey, kOK_SkKey },
{ SK_MacDeleteKey, kBack_SkKey },
{ SK_MacEndKey, kEnd_SkKey },
{ SK_Mac0Key, k0_SkKey },
{ SK_Mac1Key, k1_SkKey },
{ SK_Mac2Key, k2_SkKey },
{ SK_Mac3Key, k3_SkKey },
{ SK_Mac4Key, k4_SkKey },
{ SK_Mac5Key, k5_SkKey },
{ SK_Mac6Key, k6_SkKey },
{ SK_Mac7Key, k7_SkKey },
{ SK_Mac8Key, k8_SkKey },
{ SK_Mac9Key, k9_SkKey }
};
for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++)
if (gKeys[i].fRaw == raw)
return gKeys[i].fKey;
return kNONE_SkKey;
}
///////////////////////////////////////////////////////////////////////////////////////
void SkEvent::SignalNonEmptyQueue()
{
post_skwinevent();
//SkDebugf("signal nonempty\n");
}
static UINT_PTR gTimer;
VOID CALLBACK sk_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
SkEvent::ServiceQueueTimer();
//SkDebugf("timer task fired\n");
}
void SkEvent::SignalQueueTimer(SkMSec delay)
{
if (gTimer)
{
KillTimer(NULL, gTimer);
gTimer = NULL;
}
if (delay)
{
gTimer = SetTimer(NULL, 0, delay, sk_timer_proc);
//SkDebugf("SetTimer of %d returned %d\n", delay, gTimer);
}
}
#define USE_MSAA 0
HGLRC create_gl(HWND hwnd) {
HDC dc = GetDC(hwnd);
SkWGLExtensions extensions;
if (!extensions.hasExtension(dc, "WGL_ARB_pixel_format")) {
return NULL;
}
HDC prevDC = wglGetCurrentDC();
HGLRC prevGLRC = wglGetCurrentContext();
PIXELFORMATDESCRIPTOR pfd;
int format = 0;
GLint iattrs[] = {
SK_WGL_DRAW_TO_WINDOW_ARB, TRUE,
SK_WGL_DOUBLE_BUFFER_ARB, TRUE,
SK_WGL_ACCELERATION_ARB, SK_WGL_FULL_ACCELERATION_ARB,
SK_WGL_SUPPORT_OPENGL_ARB, TRUE,
SK_WGL_COLOR_BITS_ARB, 24,
SK_WGL_ALPHA_BITS_ARB, 8,
SK_WGL_STENCIL_BITS_ARB, 8,
// these must be kept last
SK_WGL_SAMPLE_BUFFERS_ARB, TRUE,
SK_WGL_SAMPLES_ARB, 0,
0,0
};
static const int kSampleBuffersValueIdx = SK_ARRAY_COUNT(iattrs) - 5;
static const int kSamplesValueIdx = SK_ARRAY_COUNT(iattrs) - 3;
if (USE_MSAA && extensions.hasExtension(dc, "WGL_ARB_multisample")) {
for (int samples = 16; samples > 1; --samples) {
iattrs[kSamplesValueIdx] = samples;
GLfloat fattrs[] = {0,0};
GLuint num;
int formats[64];
extensions.choosePixelFormat(dc, iattrs, fattrs, 64, formats, &num);
num = min(num,64);
for (GLuint i = 0; i < num; ++i) {
DescribePixelFormat(dc, formats[i], sizeof(pfd), &pfd);
if (SetPixelFormat(dc, formats[i], &pfd)) {
format = formats[i];
break;
}
}
}
}
if (0 == format) {
iattrs[kSampleBuffersValueIdx-1] = iattrs[kSampleBuffersValueIdx] = 0;
iattrs[kSamplesValueIdx-1] = iattrs[kSamplesValueIdx] = 0;
GLfloat fattrs[] = {0,0};
GLuint num;
extensions.choosePixelFormat(dc, iattrs, fattrs, 1, &format, &num);
DescribePixelFormat(dc, format, sizeof(pfd), &pfd);
BOOL set = SetPixelFormat(dc, format, &pfd);
SkASSERT(TRUE == set);
}
HGLRC glrc = wglCreateContext(dc);
SkASSERT(glrc);
wglMakeCurrent(prevDC, prevGLRC);
return glrc;
}
bool SkOSWindow::attachGL() {
if (NULL == fHGLRC) {
fHGLRC = create_gl((HWND)fHWND);
if (NULL == fHGLRC) {
return false;
}
glClearStencil(0);
glClearColor(0, 0, 0, 0);
glStencilMask(0xffffffff);
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
}
if (wglMakeCurrent(GetDC((HWND)fHWND), (HGLRC)fHGLRC)) {
glViewport(0, 0, SkScalarRound(this->width()),
SkScalarRound(this->height()));
fGLAttached = true;
return true;
}
return false;
}
void SkOSWindow::detachGL() {
wglMakeCurrent(GetDC((HWND)fHWND), 0);
fGLAttached = false;
}
void SkOSWindow::presentGL() {
glFlush();
SwapBuffers(GetDC((HWND)fHWND));
}
IDirect3DDevice9* create_d3d9_device(HWND hwnd) {
HRESULT hr;
IDirect3D9* d3d9;
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if (NULL == d3d9) {
return NULL;
}
D3DDEVTYPE devType = D3DDEVTYPE_HAL;
//D3DDEVTYPE devType = D3DDEVTYPE_REF;
DWORD qLevels;
DWORD qLevelsDepth;
D3DMULTISAMPLE_TYPE type;
for (type = D3DMULTISAMPLE_16_SAMPLES;
type >= D3DMULTISAMPLE_NONMASKABLE; --(*(DWORD*)&type)) {
hr = d3d9->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT,
devType, D3DFMT_D24S8, TRUE,
type, &qLevels);
qLevels = (hr == D3D_OK) ? qLevels : 0;
hr = d3d9->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT,
devType, D3DFMT_A8R8G8B8, TRUE,
type, &qLevelsDepth);
qLevelsDepth = (hr == D3D_OK) ? qLevelsDepth : 0;
qLevels = min(qLevels,qLevelsDepth);
if (qLevels > 0) {
break;
}
}
qLevels = 0;
IDirect3DDevice9* d3d9Device;
D3DPRESENT_PARAMETERS pres;
memset(&pres, 0, sizeof(pres));
pres.EnableAutoDepthStencil = TRUE;
pres.AutoDepthStencilFormat = D3DFMT_D24S8;
pres.BackBufferCount = 2;
pres.BackBufferFormat = D3DFMT_A8R8G8B8;
pres.BackBufferHeight = 0;
pres.BackBufferWidth = 0;
if (qLevels > 0) {
pres.MultiSampleType = type;
pres.MultiSampleQuality = qLevels-1;
} else {
pres.MultiSampleType = D3DMULTISAMPLE_NONE;
pres.MultiSampleQuality = 0;
}
pres.SwapEffect = D3DSWAPEFFECT_DISCARD;
pres.Windowed = TRUE;
pres.hDeviceWindow = hwnd;
pres.PresentationInterval = 1;
pres.Flags = 0;
hr = d3d9->CreateDevice(D3DADAPTER_DEFAULT,
devType,
hwnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
&pres,
&d3d9Device);
D3DERR_INVALIDCALL;
if (SUCCEEDED(hr)) {
d3d9Device->Clear(0, NULL, D3DCLEAR_TARGET, 0xFFFFFFFF, 0, 0);
return d3d9Device;
}
return NULL;
}
// This needs some improvement. D3D doesn't have the same notion of attach/detach
// as GL. However, just allowing GDI to write to the window after creating the
// D3D device seems to work.
// We need to handle resizing. On XP and earlier Reset() will trash all our textures
// so we would need to inform the SkGpu/caches or just recreate them. On Vista+ we
// could use an IDirect3DDevice9Ex and call ResetEx() to resize without trashing
// everything. Currently we do nothing and the D3D9 image gets stretched/compressed
// when resized.
bool SkOSWindow::attachD3D9() {
if (NULL == fD3D9Device) {
fD3D9Device = (void*) create_d3d9_device((HWND)fHWND);
}
if (NULL != fD3D9Device) {
((IDirect3DDevice9*)fD3D9Device)->BeginScene();
fD3D9Attached = true;
}
return fD3D9Attached;
}
void SkOSWindow::detachD3D9() {
if (NULL != fD3D9Device) {
((IDirect3DDevice9*)fD3D9Device)->EndScene();
}
fD3D9Attached = false;
}
void SkOSWindow::presentD3D9() {
if (NULL != fD3D9Device) {
HRESULT hr;
hr = ((IDirect3DDevice9*)fD3D9Device)->EndScene();
SkASSERT(SUCCEEDED(hr));
hr = ((IDirect3DDevice9*)d3d9Device())->Present(NULL, NULL, NULL, NULL);
SkASSERT(SUCCEEDED(hr));
hr = ((IDirect3DDevice9*)fD3D9Device)->Clear(0,NULL,D3DCLEAR_TARGET |
D3DCLEAR_STENCIL, 0x0, 0,
0);
SkASSERT(SUCCEEDED(hr));
hr = ((IDirect3DDevice9*)fD3D9Device)->BeginScene();
SkASSERT(SUCCEEDED(hr));
}
}
#endif

184
src/utils/win/SkWGL_win.cpp Normal file
Просмотреть файл

@ -0,0 +1,184 @@
/*
* 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"
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 {
#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);
}