PrusaSlicer_app_msvc.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. // Why?
  2. #define _WIN32_WINNT 0x0502
  3. // The standard Windows includes.
  4. #define WIN32_LEAN_AND_MEAN
  5. #define NOMINMAX
  6. #include <Windows.h>
  7. #include <shellapi.h>
  8. #include <wchar.h>
  9. #ifdef SLIC3R_GUI
  10. extern "C"
  11. {
  12. // Let the NVIDIA and AMD know we want to use their graphics card
  13. // on a dual graphics card system.
  14. __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
  15. __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
  16. }
  17. #endif /* SLIC3R_GUI */
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #ifdef SLIC3R_GUI
  21. #include <GL/GL.h>
  22. #endif /* SLIC3R_GUI */
  23. #include <string>
  24. #include <vector>
  25. #include <boost/algorithm/string/split.hpp>
  26. #include <boost/algorithm/string/classification.hpp>
  27. #include <stdio.h>
  28. #ifdef SLIC3R_GUI
  29. class OpenGLVersionCheck
  30. {
  31. public:
  32. std::string version;
  33. std::string glsl_version;
  34. std::string vendor;
  35. std::string renderer;
  36. HINSTANCE hOpenGL = nullptr;
  37. bool success = false;
  38. bool load_opengl_dll()
  39. {
  40. MSG msg = {0};
  41. WNDCLASS wc = {0};
  42. wc.lpfnWndProc = OpenGLVersionCheck::supports_opengl2_wndproc;
  43. wc.hInstance = (HINSTANCE)GetModuleHandle(nullptr);
  44. wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
  45. wc.lpszClassName = L"PrusaSlicer_opengl_version_check";
  46. wc.style = CS_OWNDC;
  47. if (RegisterClass(&wc)) {
  48. HWND hwnd = CreateWindowW(wc.lpszClassName, L"PrusaSlicer_opengl_version_check", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, wc.hInstance, (LPVOID)this);
  49. if (hwnd) {
  50. message_pump_exit = false;
  51. while (GetMessage(&msg, NULL, 0, 0 ) > 0 && ! message_pump_exit)
  52. DispatchMessage(&msg);
  53. }
  54. }
  55. return this->success;
  56. }
  57. void unload_opengl_dll()
  58. {
  59. if (this->hOpenGL) {
  60. BOOL released = FreeLibrary(this->hOpenGL);
  61. if (released)
  62. printf("System OpenGL library released\n");
  63. else
  64. printf("System OpenGL library NOT released\n");
  65. this->hOpenGL = nullptr;
  66. }
  67. }
  68. bool is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const
  69. {
  70. // printf("is_version_greater_or_equal_to, version: %s\n", version.c_str());
  71. std::vector<std::string> tokens;
  72. boost::split(tokens, version, boost::is_any_of(" "), boost::token_compress_on);
  73. if (tokens.empty())
  74. return false;
  75. std::vector<std::string> numbers;
  76. boost::split(numbers, tokens[0], boost::is_any_of("."), boost::token_compress_on);
  77. unsigned int gl_major = 0;
  78. unsigned int gl_minor = 0;
  79. if (numbers.size() > 0)
  80. gl_major = ::atoi(numbers[0].c_str());
  81. if (numbers.size() > 1)
  82. gl_minor = ::atoi(numbers[1].c_str());
  83. // printf("Major: %d, minor: %d\n", gl_major, gl_minor);
  84. if (gl_major < major)
  85. return false;
  86. else if (gl_major > major)
  87. return true;
  88. else
  89. return gl_minor >= minor;
  90. }
  91. protected:
  92. static bool message_pump_exit;
  93. void check(HWND hWnd)
  94. {
  95. hOpenGL = LoadLibraryExW(L"opengl32.dll", nullptr, 0);
  96. if (hOpenGL == nullptr) {
  97. printf("Failed loading the system opengl32.dll\n");
  98. return;
  99. }
  100. typedef HGLRC (WINAPI *Func_wglCreateContext)(HDC);
  101. typedef BOOL (WINAPI *Func_wglMakeCurrent )(HDC, HGLRC);
  102. typedef BOOL (WINAPI *Func_wglDeleteContext)(HGLRC);
  103. typedef GLubyte* (WINAPI *Func_glGetString )(GLenum);
  104. Func_wglCreateContext wglCreateContext = (Func_wglCreateContext)GetProcAddress(hOpenGL, "wglCreateContext");
  105. Func_wglMakeCurrent wglMakeCurrent = (Func_wglMakeCurrent) GetProcAddress(hOpenGL, "wglMakeCurrent");
  106. Func_wglDeleteContext wglDeleteContext = (Func_wglDeleteContext)GetProcAddress(hOpenGL, "wglDeleteContext");
  107. Func_glGetString glGetString = (Func_glGetString) GetProcAddress(hOpenGL, "glGetString");
  108. if (wglCreateContext == nullptr || wglMakeCurrent == nullptr || wglDeleteContext == nullptr || glGetString == nullptr) {
  109. printf("Failed loading the system opengl32.dll: The library is invalid.\n");
  110. return;
  111. }
  112. PIXELFORMATDESCRIPTOR pfd =
  113. {
  114. sizeof(PIXELFORMATDESCRIPTOR),
  115. 1,
  116. PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
  117. PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette.
  118. 32, // Color depth of the framebuffer.
  119. 0, 0, 0, 0, 0, 0,
  120. 0,
  121. 0,
  122. 0,
  123. 0, 0, 0, 0,
  124. 24, // Number of bits for the depthbuffer
  125. 8, // Number of bits for the stencilbuffer
  126. 0, // Number of Aux buffers in the framebuffer.
  127. PFD_MAIN_PLANE,
  128. 0,
  129. 0, 0, 0
  130. };
  131. HDC ourWindowHandleToDeviceContext = ::GetDC(hWnd);
  132. // Gdi32.dll
  133. int letWindowsChooseThisPixelFormat = ::ChoosePixelFormat(ourWindowHandleToDeviceContext, &pfd);
  134. // Gdi32.dll
  135. SetPixelFormat(ourWindowHandleToDeviceContext, letWindowsChooseThisPixelFormat, &pfd);
  136. // Opengl32.dll
  137. HGLRC glcontext = wglCreateContext(ourWindowHandleToDeviceContext);
  138. wglMakeCurrent(ourWindowHandleToDeviceContext, glcontext);
  139. // Opengl32.dll
  140. const char *data = (const char*)glGetString(GL_VERSION);
  141. if (data != nullptr)
  142. this->version = data;
  143. // printf("check -version: %s\n", version.c_str());
  144. data = (const char*)glGetString(0x8B8C); // GL_SHADING_LANGUAGE_VERSION
  145. if (data != nullptr)
  146. this->glsl_version = data;
  147. data = (const char*)glGetString(GL_VENDOR);
  148. if (data != nullptr)
  149. this->vendor = data;
  150. data = (const char*)glGetString(GL_RENDERER);
  151. if (data != nullptr)
  152. this->renderer = data;
  153. // Opengl32.dll
  154. wglDeleteContext(glcontext);
  155. ::ReleaseDC(hWnd, ourWindowHandleToDeviceContext);
  156. this->success = true;
  157. }
  158. static LRESULT CALLBACK supports_opengl2_wndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  159. {
  160. switch(message)
  161. {
  162. case WM_CREATE:
  163. {
  164. CREATESTRUCT *pCreate = reinterpret_cast<CREATESTRUCT*>(lParam);
  165. OpenGLVersionCheck *ogl_data = reinterpret_cast<OpenGLVersionCheck*>(pCreate->lpCreateParams);
  166. ogl_data->check(hWnd);
  167. DestroyWindow(hWnd);
  168. return 0;
  169. }
  170. case WM_NCDESTROY:
  171. message_pump_exit = true;
  172. return 0;
  173. default:
  174. return DefWindowProc(hWnd, message, wParam, lParam);
  175. }
  176. }
  177. };
  178. bool OpenGLVersionCheck::message_pump_exit = false;
  179. #endif /* SLIC3R_GUI */
  180. extern "C" {
  181. typedef int (__stdcall *Slic3rMainFunc)(int argc, wchar_t **argv);
  182. Slic3rMainFunc slic3r_main = nullptr;
  183. }
  184. extern "C" {
  185. #ifdef SLIC3R_WRAPPER_NOCONSOLE
  186. int APIENTRY wWinMain(HINSTANCE /* hInstance */, HINSTANCE /* hPrevInstance */, PWSTR /* lpCmdLine */, int /* nCmdShow */)
  187. {
  188. int argc;
  189. wchar_t **argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
  190. #else
  191. int wmain(int argc, wchar_t **argv)
  192. {
  193. #endif
  194. // Allow the asserts to open message box, such message box allows to ignore the assert and continue with the application.
  195. // Without this call, the seemingly same message box is being opened by the abort() function, but that is too late and
  196. // the application will be killed even if "Ignore" button is pressed.
  197. _set_error_mode(_OUT_TO_MSGBOX);
  198. std::vector<wchar_t*> argv_extended;
  199. argv_extended.emplace_back(argv[0]);
  200. #ifdef SLIC3R_WRAPPER_GCODEVIEWER
  201. wchar_t gcodeviewer_param[] = L"--gcodeviewer";
  202. argv_extended.emplace_back(gcodeviewer_param);
  203. #endif /* SLIC3R_WRAPPER_GCODEVIEWER */
  204. #ifdef SLIC3R_GUI
  205. // Here one may push some additional parameters based on the wrapper type.
  206. bool force_mesa = false;
  207. #endif /* SLIC3R_GUI */
  208. for (int i = 1; i < argc; ++ i) {
  209. #ifdef SLIC3R_GUI
  210. if (wcscmp(argv[i], L"--sw-renderer") == 0)
  211. force_mesa = true;
  212. else if (wcscmp(argv[i], L"--no-sw-renderer") == 0)
  213. force_mesa = false;
  214. #endif /* SLIC3R_GUI */
  215. argv_extended.emplace_back(argv[i]);
  216. }
  217. argv_extended.emplace_back(nullptr);
  218. #ifdef SLIC3R_GUI
  219. OpenGLVersionCheck opengl_version_check;
  220. bool load_mesa =
  221. // Forced from the command line.
  222. force_mesa ||
  223. // Running over a rempote desktop, and the RemoteFX is not enabled, therefore Windows will only provide SW OpenGL 1.1 context.
  224. // In that case, use Mesa.
  225. ::GetSystemMetrics(SM_REMOTESESSION) ||
  226. // Try to load the default OpenGL driver and test its context version.
  227. ! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(2, 0);
  228. #endif /* SLIC3R_GUI */
  229. wchar_t path_to_exe[MAX_PATH + 1] = { 0 };
  230. ::GetModuleFileNameW(nullptr, path_to_exe, MAX_PATH);
  231. wchar_t drive[_MAX_DRIVE];
  232. wchar_t dir[_MAX_DIR];
  233. wchar_t fname[_MAX_FNAME];
  234. wchar_t ext[_MAX_EXT];
  235. _wsplitpath(path_to_exe, drive, dir, fname, ext);
  236. _wmakepath(path_to_exe, drive, dir, nullptr, nullptr);
  237. #ifdef SLIC3R_GUI
  238. // https://wiki.qt.io/Cross_compiling_Mesa_for_Windows
  239. // http://download.qt.io/development_releases/prebuilt/llvmpipe/windows/
  240. if (load_mesa) {
  241. opengl_version_check.unload_opengl_dll();
  242. wchar_t path_to_mesa[MAX_PATH + 1] = { 0 };
  243. wcscpy(path_to_mesa, path_to_exe);
  244. wcscat(path_to_mesa, L"mesa\\opengl32.dll");
  245. printf("Loading MESA OpenGL library: %S\n", path_to_mesa);
  246. HINSTANCE hInstance_OpenGL = LoadLibraryExW(path_to_mesa, nullptr, 0);
  247. if (hInstance_OpenGL == nullptr) {
  248. printf("MESA OpenGL library was not loaded\n");
  249. } else
  250. printf("MESA OpenGL library was loaded sucessfully\n");
  251. }
  252. #endif /* SLIC3R_GUI */
  253. wchar_t path_to_slic3r[MAX_PATH + 1] = { 0 };
  254. wcscpy(path_to_slic3r, path_to_exe);
  255. wcscat(path_to_slic3r, L"PrusaSlicer.dll");
  256. // printf("Loading Slic3r library: %S\n", path_to_slic3r);
  257. HINSTANCE hInstance_Slic3r = LoadLibraryExW(path_to_slic3r, nullptr, 0);
  258. if (hInstance_Slic3r == nullptr) {
  259. printf("PrusaSlicer.dll was not loaded\n");
  260. return -1;
  261. }
  262. // resolve function address here
  263. slic3r_main = (Slic3rMainFunc)GetProcAddress(hInstance_Slic3r,
  264. #ifdef _WIN64
  265. // there is just a single calling conversion, therefore no mangling of the function name.
  266. "slic3r_main"
  267. #else // stdcall calling convention declaration
  268. "_slic3r_main@8"
  269. #endif
  270. );
  271. if (slic3r_main == nullptr) {
  272. printf("could not locate the function slic3r_main in PrusaSlicer.dll\n");
  273. return -1;
  274. }
  275. // argc minus the trailing nullptr of the argv
  276. return slic3r_main((int)argv_extended.size() - 1, argv_extended.data());
  277. }
  278. }