blob: baff735cd6c87e3b0a1d5593f4f9cad270b24b21 [file] [log] [blame]
bsalomon@google.combd7c6412011-12-01 16:34:28 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "SkWGL.h"
10
bsalomon@google.com8a189b02012-04-17 12:43:00 +000011#include "SkTDArray.h"
12#include "SkTSearch.h"
13
bsalomon@google.combd7c6412011-12-01 16:34:28 +000014bool SkWGLExtensions::hasExtension(HDC dc, const char* ext) const {
15 if (NULL == this->fGetExtensionsString) {
16 return false;
17 }
18 if (!strcmp("WGL_ARB_extensions_string", ext)) {
19 return true;
20 }
21 const char* extensionString = this->getExtensionsString(dc);
22 int extLength = strlen(ext);
23
24 while (true) {
25 int n = strcspn(extensionString, " ");
26 if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
27 return true;
28 }
29 if (0 == extensionString[n]) {
30 return false;
31 }
32 extensionString += n+1;
33 }
34
35 return false;
36}
37
38const char* SkWGLExtensions::getExtensionsString(HDC hdc) const {
39 return fGetExtensionsString(hdc);
40}
41
42BOOL SkWGLExtensions::choosePixelFormat(HDC hdc,
43 const int* piAttribIList,
44 const FLOAT* pfAttribFList,
45 UINT nMaxFormats,
46 int* piFormats,
47 UINT* nNumFormats) const {
48 return fChoosePixelFormat(hdc, piAttribIList, pfAttribFList,
49 nMaxFormats, piFormats, nNumFormats);
50}
51
52BOOL SkWGLExtensions::getPixelFormatAttribiv(HDC hdc,
53 int iPixelFormat,
54 int iLayerPlane,
55 UINT nAttributes,
56 const int *piAttributes,
57 int *piValues) const {
58 return fGetPixelFormatAttribiv(hdc, iPixelFormat, iLayerPlane,
59 nAttributes, piAttributes, piValues);
60}
61
62BOOL SkWGLExtensions::getPixelFormatAttribfv(HDC hdc,
63 int iPixelFormat,
64 int iLayerPlane,
65 UINT nAttributes,
66 const int *piAttributes,
67 float *pfValues) const {
68 return fGetPixelFormatAttribfv(hdc, iPixelFormat, iLayerPlane,
69 nAttributes, piAttributes, pfValues);
70}
71HGLRC SkWGLExtensions::createContextAttribs(HDC hDC,
72 HGLRC hShareContext,
73 const int *attribList) const {
74 return fCreateContextAttribs(hDC, hShareContext, attribList);
75}
76
77namespace {
78
bsalomon@google.com8a189b02012-04-17 12:43:00 +000079struct PixelFormat {
80 int fFormat;
81 int fCoverageSamples;
82 int fColorSamples;
83 int fChoosePixelFormatRank;
84};
85
86int compare_pf(const PixelFormat* a, const PixelFormat* b) {
87 if (a->fCoverageSamples < b->fCoverageSamples) {
88 return -1;
89 } else if (b->fCoverageSamples < a->fCoverageSamples) {
90 return 1;
91 } else if (a->fColorSamples < b->fColorSamples) {
92 return -1;
93 } else if (b->fColorSamples < a->fColorSamples) {
94 return 1;
95 } else if (a->fChoosePixelFormatRank < b->fChoosePixelFormatRank) {
96 return -1;
97 } else if (b->fChoosePixelFormatRank < a->fChoosePixelFormatRank) {
98 return 1;
99 }
100 return 0;
101}
102}
103
104int SkWGLExtensions::selectFormat(const int formats[],
105 int formatCount,
106 HDC dc,
107 int desiredSampleCount) {
108 PixelFormat desiredFormat = {
109 0,
110 desiredSampleCount,
111 0,
112 0,
113 };
114 SkTDArray<PixelFormat> rankedFormats;
115 rankedFormats.setCount(formatCount);
116 bool supportsCoverage = this->hasExtension(dc,
117 "WGL_NV_multisample_coverage");
118 for (int i = 0; i < formatCount; ++i) {
119 static const int queryAttrs[] = {
120 SK_WGL_COVERAGE_SAMPLES,
121 SK_WGL_COLOR_SAMPLES,
122 };
123 int answers[2];
124 int queryAttrCnt = supportsCoverage ? 2 : 1;
125 this->getPixelFormatAttribiv(dc,
126 formats[i],
127 0,
128 SK_ARRAY_COUNT(queryAttrs),
129 queryAttrs,
130 answers);
131 rankedFormats[i].fFormat = formats[i];
132 rankedFormats[i].fCoverageSamples = answers[0];
133 rankedFormats[i].fColorSamples = answers[supportsCoverage ? 1 : 0];
134 rankedFormats[i].fChoosePixelFormatRank = i;
135 }
136 SkQSort(rankedFormats.begin(),
137 rankedFormats.count(),
138 sizeof(PixelFormat),
139 (SkQSortCompareProc)compare_pf);
140 int idx = SkTSearch<PixelFormat>(rankedFormats.begin(),
141 rankedFormats.count(),
142 desiredFormat,
143 sizeof(PixelFormat),
144 compare_pf);
145 if (idx < 0) {
146 idx = ~idx;
147 }
148 return rankedFormats[idx].fFormat;
149}
150
151
152namespace {
153
bsalomon@google.combd7c6412011-12-01 16:34:28 +0000154#if defined(UNICODE)
155 #define STR_LIT(X) L## #X
156#else
157 #define STR_LIT(X) #X
158#endif
159
160#define DUMMY_CLASS STR_LIT("DummyClass")
161
162HWND create_dummy_window() {
163 HMODULE module = GetModuleHandle(NULL);
164 HWND dummy;
165 RECT windowRect;
166 windowRect.left = 0;
167 windowRect.right = 8;
168 windowRect.top = 0;
169 windowRect.bottom = 8;
170
171 WNDCLASS wc;
172
173 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
174 wc.lpfnWndProc = (WNDPROC) DefWindowProc;
175 wc.cbClsExtra = 0;
176 wc.cbWndExtra = 0;
177 wc.hInstance = module;
178 wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
179 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
180 wc.hbrBackground = NULL;
181 wc.lpszMenuName = NULL;
182 wc.lpszClassName = DUMMY_CLASS;
183
184 if(!RegisterClass(&wc)) {
185 return 0;
186 }
187
188 DWORD style, exStyle;
189 exStyle = WS_EX_CLIENTEDGE;
190 style = WS_SYSMENU;
191
192 AdjustWindowRectEx(&windowRect, style, false, exStyle);
193 if(!(dummy = CreateWindowEx(exStyle,
194 DUMMY_CLASS,
195 STR_LIT("DummyWindow"),
196 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
197 0, 0,
198 windowRect.right-windowRect.left,
199 windowRect.bottom-windowRect.top,
200 NULL, NULL,
201 module,
202 NULL))) {
203 UnregisterClass(DUMMY_CLASS, module);
204 return NULL;
205 }
206 ShowWindow(dummy, SW_HIDE);
207
208 return dummy;
209}
210
211void destroy_dummy_window(HWND dummy) {
212 DestroyWindow(dummy);
213 HMODULE module = GetModuleHandle(NULL);
214 UnregisterClass(DUMMY_CLASS, module);
215}
216}
217
218#define GET_PROC(NAME, SUFFIX) f##NAME = \
219 (##NAME##Proc) wglGetProcAddress("wgl" #NAME #SUFFIX)
220
221SkWGLExtensions::SkWGLExtensions()
222 : fGetExtensionsString(NULL)
223 , fChoosePixelFormat(NULL)
224 , fGetPixelFormatAttribfv(NULL)
225 , fGetPixelFormatAttribiv(NULL)
226 , fCreateContextAttribs(NULL) {
227 HDC prevDC = wglGetCurrentDC();
228 HGLRC prevGLRC = wglGetCurrentContext();
229
230 PIXELFORMATDESCRIPTOR dummyPFD;
231
232 ZeroMemory(&dummyPFD, sizeof(dummyPFD));
233 dummyPFD.nSize = sizeof(dummyPFD);
234 dummyPFD.nVersion = 1;
235 dummyPFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
236 dummyPFD.iPixelType = PFD_TYPE_RGBA;
237 dummyPFD.cColorBits = 32;
238 dummyPFD.cDepthBits = 0;
239 dummyPFD.cStencilBits = 8;
240 dummyPFD.iLayerType = PFD_MAIN_PLANE;
241 HWND dummyWND = create_dummy_window();
242 if (dummyWND) {
243 HDC dummyDC = GetDC(dummyWND);
244 int dummyFormat = ChoosePixelFormat(dummyDC, &dummyPFD);
245 SetPixelFormat(dummyDC, dummyFormat, &dummyPFD);
246 HGLRC dummyGLRC = wglCreateContext(dummyDC);
247 SkASSERT(dummyGLRC);
248 wglMakeCurrent(dummyDC, dummyGLRC);
249
250 GET_PROC(GetExtensionsString, ARB);
251 GET_PROC(ChoosePixelFormat, ARB);
252 GET_PROC(GetPixelFormatAttribiv, ARB);
253 GET_PROC(GetPixelFormatAttribfv, ARB);
254 GET_PROC(CreateContextAttribs, ARB);
255
256 wglMakeCurrent(dummyDC, NULL);
257 wglDeleteContext(dummyGLRC);
258 destroy_dummy_window(dummyWND);
259 }
260
261 wglMakeCurrent(prevDC, prevGLRC);
262}