SkWGL_win.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. /*
  2. * Copyright 2011 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "include/core/SkTypes.h"
  8. #if defined(SK_BUILD_FOR_WIN) && !defined(_M_ARM64)
  9. #include "src/utils/win/SkWGL.h"
  10. #include "include/private/SkOnce.h"
  11. #include "include/private/SkTDArray.h"
  12. #include "src/core/SkTSearch.h"
  13. #include "src/core/SkTSort.h"
  14. bool SkWGLExtensions::hasExtension(HDC dc, const char* ext) const {
  15. if (nullptr == 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. size_t extLength = strlen(ext);
  23. while (true) {
  24. size_t n = strcspn(extensionString, " ");
  25. if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
  26. return true;
  27. }
  28. if (0 == extensionString[n]) {
  29. return false;
  30. }
  31. extensionString += n+1;
  32. }
  33. return false;
  34. }
  35. const char* SkWGLExtensions::getExtensionsString(HDC hdc) const {
  36. return fGetExtensionsString(hdc);
  37. }
  38. BOOL SkWGLExtensions::choosePixelFormat(HDC hdc,
  39. const int* piAttribIList,
  40. const FLOAT* pfAttribFList,
  41. UINT nMaxFormats,
  42. int* piFormats,
  43. UINT* nNumFormats) const {
  44. return fChoosePixelFormat(hdc, piAttribIList, pfAttribFList,
  45. nMaxFormats, piFormats, nNumFormats);
  46. }
  47. BOOL SkWGLExtensions::getPixelFormatAttribiv(HDC hdc,
  48. int iPixelFormat,
  49. int iLayerPlane,
  50. UINT nAttributes,
  51. const int *piAttributes,
  52. int *piValues) const {
  53. return fGetPixelFormatAttribiv(hdc, iPixelFormat, iLayerPlane,
  54. nAttributes, piAttributes, piValues);
  55. }
  56. BOOL SkWGLExtensions::getPixelFormatAttribfv(HDC hdc,
  57. int iPixelFormat,
  58. int iLayerPlane,
  59. UINT nAttributes,
  60. const int *piAttributes,
  61. float *pfValues) const {
  62. return fGetPixelFormatAttribfv(hdc, iPixelFormat, iLayerPlane,
  63. nAttributes, piAttributes, pfValues);
  64. }
  65. HGLRC SkWGLExtensions::createContextAttribs(HDC hDC,
  66. HGLRC hShareContext,
  67. const int *attribList) const {
  68. return fCreateContextAttribs(hDC, hShareContext, attribList);
  69. }
  70. BOOL SkWGLExtensions::swapInterval(int interval) const {
  71. return fSwapInterval(interval);
  72. }
  73. HPBUFFER SkWGLExtensions::createPbuffer(HDC hDC,
  74. int iPixelFormat,
  75. int iWidth,
  76. int iHeight,
  77. const int *piAttribList) const {
  78. return fCreatePbuffer(hDC, iPixelFormat, iWidth, iHeight, piAttribList);
  79. }
  80. HDC SkWGLExtensions::getPbufferDC(HPBUFFER hPbuffer) const {
  81. return fGetPbufferDC(hPbuffer);
  82. }
  83. int SkWGLExtensions::releasePbufferDC(HPBUFFER hPbuffer, HDC hDC) const {
  84. return fReleasePbufferDC(hPbuffer, hDC);
  85. }
  86. BOOL SkWGLExtensions::destroyPbuffer(HPBUFFER hPbuffer) const {
  87. return fDestroyPbuffer(hPbuffer);
  88. }
  89. namespace {
  90. struct PixelFormat {
  91. int fFormat;
  92. int fSampleCnt;
  93. int fChoosePixelFormatRank;
  94. };
  95. bool pf_less(const PixelFormat& a, const PixelFormat& b) {
  96. if (a.fSampleCnt < b.fSampleCnt) {
  97. return true;
  98. } else if (b.fSampleCnt < a.fSampleCnt) {
  99. return false;
  100. } else if (a.fChoosePixelFormatRank < b.fChoosePixelFormatRank) {
  101. return true;
  102. }
  103. return false;
  104. }
  105. }
  106. int SkWGLExtensions::selectFormat(const int formats[],
  107. int formatCount,
  108. HDC dc,
  109. int desiredSampleCount) const {
  110. SkASSERT(desiredSampleCount >= 1);
  111. if (formatCount <= 0) {
  112. return -1;
  113. }
  114. PixelFormat desiredFormat = {
  115. 0,
  116. desiredSampleCount,
  117. 0,
  118. };
  119. SkTDArray<PixelFormat> rankedFormats;
  120. rankedFormats.setCount(formatCount);
  121. for (int i = 0; i < formatCount; ++i) {
  122. static const int kQueryAttr = SK_WGL_SAMPLES;
  123. int numSamples;
  124. this->getPixelFormatAttribiv(dc,
  125. formats[i],
  126. 0,
  127. 1,
  128. &kQueryAttr,
  129. &numSamples);
  130. rankedFormats[i].fFormat = formats[i];
  131. rankedFormats[i].fSampleCnt = SkTMax(1, numSamples);
  132. rankedFormats[i].fChoosePixelFormatRank = i;
  133. }
  134. SkTQSort(rankedFormats.begin(),
  135. rankedFormats.begin() + rankedFormats.count() - 1,
  136. SkTLessFunctionToFunctorAdaptor<PixelFormat, pf_less>());
  137. int idx = SkTSearch<PixelFormat, pf_less>(rankedFormats.begin(),
  138. rankedFormats.count(),
  139. desiredFormat,
  140. sizeof(PixelFormat));
  141. if (idx < 0) {
  142. idx = ~idx;
  143. }
  144. // If the caller asked for non-MSAA fail if the closest format has MSAA.
  145. if (desiredSampleCount == 1 && rankedFormats[idx].fSampleCnt != 1) {
  146. return -1;
  147. }
  148. return rankedFormats[idx].fFormat;
  149. }
  150. namespace {
  151. #if defined(UNICODE)
  152. #define STR_LIT(X) L## #X
  153. #else
  154. #define STR_LIT(X) #X
  155. #endif
  156. #define DUMMY_CLASS STR_LIT("DummyClass")
  157. HWND create_dummy_window() {
  158. HMODULE module = GetModuleHandle(nullptr);
  159. HWND dummy;
  160. RECT windowRect;
  161. windowRect.left = 0;
  162. windowRect.right = 8;
  163. windowRect.top = 0;
  164. windowRect.bottom = 8;
  165. WNDCLASS wc;
  166. wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  167. wc.lpfnWndProc = (WNDPROC) DefWindowProc;
  168. wc.cbClsExtra = 0;
  169. wc.cbWndExtra = 0;
  170. wc.hInstance = module;
  171. wc.hIcon = LoadIcon(nullptr, IDI_WINLOGO);
  172. wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
  173. wc.hbrBackground = nullptr;
  174. wc.lpszMenuName = nullptr;
  175. wc.lpszClassName = DUMMY_CLASS;
  176. if(!RegisterClass(&wc)) {
  177. return 0;
  178. }
  179. DWORD style, exStyle;
  180. exStyle = WS_EX_CLIENTEDGE;
  181. style = WS_SYSMENU;
  182. AdjustWindowRectEx(&windowRect, style, false, exStyle);
  183. if(!(dummy = CreateWindowEx(exStyle,
  184. DUMMY_CLASS,
  185. STR_LIT("DummyWindow"),
  186. WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
  187. 0, 0,
  188. windowRect.right-windowRect.left,
  189. windowRect.bottom-windowRect.top,
  190. nullptr, nullptr,
  191. module,
  192. nullptr))) {
  193. UnregisterClass(DUMMY_CLASS, module);
  194. return nullptr;
  195. }
  196. ShowWindow(dummy, SW_HIDE);
  197. return dummy;
  198. }
  199. void destroy_dummy_window(HWND dummy) {
  200. DestroyWindow(dummy);
  201. HMODULE module = GetModuleHandle(nullptr);
  202. UnregisterClass(DUMMY_CLASS, module);
  203. }
  204. }
  205. #define GET_PROC(NAME, SUFFIX) f##NAME = \
  206. (NAME##Proc) wglGetProcAddress("wgl" #NAME #SUFFIX)
  207. SkWGLExtensions::GetExtensionsStringProc SkWGLExtensions::fGetExtensionsString = nullptr;
  208. SkWGLExtensions::ChoosePixelFormatProc SkWGLExtensions::fChoosePixelFormat = nullptr;
  209. SkWGLExtensions::GetPixelFormatAttribfvProc SkWGLExtensions::fGetPixelFormatAttribfv = nullptr;
  210. SkWGLExtensions::GetPixelFormatAttribivProc SkWGLExtensions::fGetPixelFormatAttribiv = nullptr;
  211. SkWGLExtensions::CreateContextAttribsProc SkWGLExtensions::fCreateContextAttribs = nullptr;
  212. SkWGLExtensions::SwapIntervalProc SkWGLExtensions::fSwapInterval = nullptr;
  213. SkWGLExtensions::CreatePbufferProc SkWGLExtensions::fCreatePbuffer = nullptr;
  214. SkWGLExtensions::GetPbufferDCProc SkWGLExtensions::fGetPbufferDC = nullptr;
  215. SkWGLExtensions::ReleasePbufferDCProc SkWGLExtensions::fReleasePbufferDC = nullptr;
  216. SkWGLExtensions::DestroyPbufferProc SkWGLExtensions::fDestroyPbuffer = nullptr;
  217. SkWGLExtensions::SkWGLExtensions() {
  218. // We cache these function pointers once, and then reuse them. That's possibly incorrect if
  219. // there are multiple GPUs, or if we intend to use these for rendering contexts of different
  220. // pixel formats (where wglGetProcAddress is not guaranteed to return the same pointer).
  221. static SkOnce once;
  222. once([] {
  223. HDC prevDC = wglGetCurrentDC();
  224. HGLRC prevGLRC = wglGetCurrentContext();
  225. PIXELFORMATDESCRIPTOR dummyPFD;
  226. ZeroMemory(&dummyPFD, sizeof(dummyPFD));
  227. dummyPFD.nSize = sizeof(dummyPFD);
  228. dummyPFD.nVersion = 1;
  229. dummyPFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
  230. dummyPFD.iPixelType = PFD_TYPE_RGBA;
  231. dummyPFD.cColorBits = 32;
  232. dummyPFD.cDepthBits = 0;
  233. dummyPFD.cStencilBits = 8;
  234. dummyPFD.iLayerType = PFD_MAIN_PLANE;
  235. HWND dummyWND = create_dummy_window();
  236. if (dummyWND) {
  237. HDC dummyDC = GetDC(dummyWND);
  238. int dummyFormat = ChoosePixelFormat(dummyDC, &dummyPFD);
  239. SetPixelFormat(dummyDC, dummyFormat, &dummyPFD);
  240. HGLRC dummyGLRC = wglCreateContext(dummyDC);
  241. SkASSERT(dummyGLRC);
  242. wglMakeCurrent(dummyDC, dummyGLRC);
  243. GET_PROC(GetExtensionsString, ARB);
  244. GET_PROC(ChoosePixelFormat, ARB);
  245. GET_PROC(GetPixelFormatAttribiv, ARB);
  246. GET_PROC(GetPixelFormatAttribfv, ARB);
  247. GET_PROC(CreateContextAttribs, ARB);
  248. GET_PROC(SwapInterval, EXT);
  249. GET_PROC(CreatePbuffer, ARB);
  250. GET_PROC(GetPbufferDC, ARB);
  251. GET_PROC(ReleasePbufferDC, ARB);
  252. GET_PROC(DestroyPbuffer, ARB);
  253. wglMakeCurrent(dummyDC, nullptr);
  254. wglDeleteContext(dummyGLRC);
  255. destroy_dummy_window(dummyWND);
  256. }
  257. wglMakeCurrent(prevDC, prevGLRC);
  258. });
  259. }
  260. ///////////////////////////////////////////////////////////////////////////////
  261. static void get_pixel_formats_to_try(HDC dc, const SkWGLExtensions& extensions,
  262. bool doubleBuffered, int msaaSampleCount, bool deepColor,
  263. int formatsToTry[2]) {
  264. auto appendAttr = [](SkTDArray<int>& attrs, int attr, int value) {
  265. attrs.push_back(attr);
  266. attrs.push_back(value);
  267. };
  268. SkTDArray<int> iAttrs;
  269. appendAttr(iAttrs, SK_WGL_DRAW_TO_WINDOW, TRUE);
  270. appendAttr(iAttrs, SK_WGL_DOUBLE_BUFFER, (doubleBuffered ? TRUE : FALSE));
  271. appendAttr(iAttrs, SK_WGL_ACCELERATION, SK_WGL_FULL_ACCELERATION);
  272. appendAttr(iAttrs, SK_WGL_SUPPORT_OPENGL, TRUE);
  273. if (deepColor) {
  274. appendAttr(iAttrs, SK_WGL_RED_BITS, 10);
  275. appendAttr(iAttrs, SK_WGL_GREEN_BITS, 10);
  276. appendAttr(iAttrs, SK_WGL_BLUE_BITS, 10);
  277. appendAttr(iAttrs, SK_WGL_ALPHA_BITS, 2);
  278. } else {
  279. appendAttr(iAttrs, SK_WGL_COLOR_BITS, 24);
  280. appendAttr(iAttrs, SK_WGL_ALPHA_BITS, 8);
  281. }
  282. appendAttr(iAttrs, SK_WGL_STENCIL_BITS, 8);
  283. float fAttrs[] = {0, 0};
  284. // Get a MSAA format if requested and possible.
  285. if (msaaSampleCount > 0 &&
  286. extensions.hasExtension(dc, "WGL_ARB_multisample")) {
  287. SkTDArray<int> msaaIAttrs = iAttrs;
  288. appendAttr(msaaIAttrs, SK_WGL_SAMPLE_BUFFERS, TRUE);
  289. appendAttr(msaaIAttrs, SK_WGL_SAMPLES, msaaSampleCount);
  290. appendAttr(msaaIAttrs, 0, 0);
  291. unsigned int num;
  292. int formats[64];
  293. extensions.choosePixelFormat(dc, msaaIAttrs.begin(), fAttrs, 64, formats, &num);
  294. num = SkTMin(num, 64U);
  295. formatsToTry[0] = extensions.selectFormat(formats, num, dc, msaaSampleCount);
  296. }
  297. // Get a non-MSAA format
  298. int* format = -1 == formatsToTry[0] ? &formatsToTry[0] : &formatsToTry[1];
  299. unsigned int num;
  300. appendAttr(iAttrs, 0, 0);
  301. extensions.choosePixelFormat(dc, iAttrs.begin(), fAttrs, 1, format, &num);
  302. }
  303. static HGLRC create_gl_context(HDC dc, const SkWGLExtensions& extensions,
  304. SkWGLContextRequest contextType, HGLRC shareContext) {
  305. HDC prevDC = wglGetCurrentDC();
  306. HGLRC prevGLRC = wglGetCurrentContext();
  307. HGLRC glrc = nullptr;
  308. if (kGLES_SkWGLContextRequest == contextType) {
  309. if (!extensions.hasExtension(dc, "WGL_EXT_create_context_es2_profile")) {
  310. wglMakeCurrent(prevDC, prevGLRC);
  311. return nullptr;
  312. }
  313. static const int glesAttribs[] = {
  314. SK_WGL_CONTEXT_MAJOR_VERSION, 3,
  315. SK_WGL_CONTEXT_MINOR_VERSION, 0,
  316. SK_WGL_CONTEXT_PROFILE_MASK, SK_WGL_CONTEXT_ES2_PROFILE_BIT,
  317. 0,
  318. };
  319. glrc = extensions.createContextAttribs(dc, shareContext, glesAttribs);
  320. if (nullptr == glrc) {
  321. wglMakeCurrent(prevDC, prevGLRC);
  322. return nullptr;
  323. }
  324. } else {
  325. if (kGLPreferCoreProfile_SkWGLContextRequest == contextType &&
  326. extensions.hasExtension(dc, "WGL_ARB_create_context")) {
  327. static const int kCoreGLVersions[] = {
  328. 4, 3,
  329. 4, 2,
  330. 4, 1,
  331. 4, 0,
  332. 3, 3,
  333. 3, 2,
  334. };
  335. int coreProfileAttribs[] = {
  336. SK_WGL_CONTEXT_MAJOR_VERSION, -1,
  337. SK_WGL_CONTEXT_MINOR_VERSION, -1,
  338. SK_WGL_CONTEXT_PROFILE_MASK, SK_WGL_CONTEXT_CORE_PROFILE_BIT,
  339. 0,
  340. };
  341. for (size_t v = 0; v < SK_ARRAY_COUNT(kCoreGLVersions) / 2; ++v) {
  342. coreProfileAttribs[1] = kCoreGLVersions[2 * v];
  343. coreProfileAttribs[3] = kCoreGLVersions[2 * v + 1];
  344. glrc = extensions.createContextAttribs(dc, shareContext, coreProfileAttribs);
  345. if (glrc) {
  346. break;
  347. }
  348. }
  349. }
  350. }
  351. if (nullptr == glrc) {
  352. glrc = wglCreateContext(dc);
  353. if (shareContext) {
  354. if (!wglShareLists(shareContext, glrc)) {
  355. wglDeleteContext(glrc);
  356. return nullptr;
  357. }
  358. }
  359. }
  360. SkASSERT(glrc);
  361. wglMakeCurrent(prevDC, prevGLRC);
  362. return glrc;
  363. }
  364. HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool deepColor,
  365. SkWGLContextRequest contextType, HGLRC shareContext) {
  366. SkWGLExtensions extensions;
  367. if (!extensions.hasExtension(dc, "WGL_ARB_pixel_format")) {
  368. return nullptr;
  369. }
  370. BOOL set = FALSE;
  371. int pixelFormatsToTry[] = { -1, -1 };
  372. get_pixel_formats_to_try(dc, extensions, true, msaaSampleCount, deepColor, pixelFormatsToTry);
  373. for (size_t f = 0;
  374. !set && -1 != pixelFormatsToTry[f] && f < SK_ARRAY_COUNT(pixelFormatsToTry);
  375. ++f) {
  376. PIXELFORMATDESCRIPTOR pfd;
  377. DescribePixelFormat(dc, pixelFormatsToTry[f], sizeof(pfd), &pfd);
  378. set = SetPixelFormat(dc, pixelFormatsToTry[f], &pfd);
  379. }
  380. if (!set) {
  381. return nullptr;
  382. }
  383. return create_gl_context(dc, extensions, contextType, shareContext);
  384. }
  385. sk_sp<SkWGLPbufferContext> SkWGLPbufferContext::Create(HDC parentDC,
  386. SkWGLContextRequest contextType,
  387. HGLRC shareContext) {
  388. SkWGLExtensions extensions;
  389. if (!extensions.hasExtension(parentDC, "WGL_ARB_pixel_format") ||
  390. !extensions.hasExtension(parentDC, "WGL_ARB_pbuffer")) {
  391. return nullptr;
  392. }
  393. // We cache the pixel formats once, and then reuse them. That's possibly incorrect if
  394. // there are multiple GPUs, but this function is always called with a freshly made,
  395. // identically constructed HDC (see WinGLTestContext).
  396. //
  397. // We only store two potential pixel formats, one for single buffer, one for double buffer.
  398. // We never ask for MSAA, so we don't need the second pixel format for each buffering state.
  399. static int gPixelFormats[2] = { -1, -1 };
  400. static SkOnce once;
  401. once([=] {
  402. {
  403. // Single buffer
  404. int pixelFormatsToTry[2] = { -1, -1 };
  405. get_pixel_formats_to_try(parentDC, extensions, false, 0, false, pixelFormatsToTry);
  406. gPixelFormats[0] = pixelFormatsToTry[0];
  407. }
  408. {
  409. // Double buffer
  410. int pixelFormatsToTry[2] = { -1, -1 };
  411. get_pixel_formats_to_try(parentDC, extensions, true, 0, false, pixelFormatsToTry);
  412. gPixelFormats[1] = pixelFormatsToTry[0];
  413. }
  414. });
  415. // try for single buffer first
  416. for (int pixelFormat : gPixelFormats) {
  417. if (-1 == pixelFormat) {
  418. continue;
  419. }
  420. HPBUFFER pbuf = extensions.createPbuffer(parentDC, pixelFormat, 1, 1, nullptr);
  421. if (0 != pbuf) {
  422. HDC dc = extensions.getPbufferDC(pbuf);
  423. if (dc) {
  424. HGLRC glrc = create_gl_context(dc, extensions, contextType, shareContext);
  425. if (glrc) {
  426. return sk_sp<SkWGLPbufferContext>(new SkWGLPbufferContext(pbuf, dc, glrc));
  427. }
  428. extensions.releasePbufferDC(pbuf, dc);
  429. }
  430. extensions.destroyPbuffer(pbuf);
  431. }
  432. }
  433. return nullptr;
  434. }
  435. SkWGLPbufferContext::~SkWGLPbufferContext() {
  436. SkASSERT(fExtensions.hasExtension(fDC, "WGL_ARB_pbuffer"));
  437. wglDeleteContext(fGLRC);
  438. fExtensions.releasePbufferDC(fPbuffer, fDC);
  439. fExtensions.destroyPbuffer(fPbuffer);
  440. }
  441. SkWGLPbufferContext::SkWGLPbufferContext(HPBUFFER pbuffer, HDC dc, HGLRC glrc)
  442. : fPbuffer(pbuffer)
  443. , fDC(dc)
  444. , fGLRC(glrc) {
  445. }
  446. #endif//defined(SK_BUILD_FOR_WIN)