diff options
33 files changed, 999 insertions, 125 deletions
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 220e7aab8cd..5e0216c0339 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -66,6 +66,21 @@ extern GHOST_SystemHandle GHOST_CreateSystem(void); extern GHOST_TSuccess GHOST_DisposeSystem(GHOST_SystemHandle systemhandle); /** + * Show a system message box to the user + * \param systemhandle The handle to the system + * \param title Title of the message box + * \param message Message of the message box + * \param link Optional (hyper)link to a webpage to show when pressing help + * \param dialog_options Options to configure the message box. + * \return void. + */ +extern void GHOST_ShowMessageBox(GHOST_SystemHandle systemhandle, + const char *title, + const char *message, + const char *link, + GHOST_DialogOptions dialog_options); + +/** * Creates an event consumer object * \param eventCallback The event callback routine. * \param userdata Pointer to user data returned to the callback routine. @@ -191,6 +206,7 @@ extern GHOST_WindowHandle GHOST_CreateDialogWindow(GHOST_SystemHandle systemhand * Create a new offscreen context. * Never explicitly delete the context, use disposeContext() instead. * \param systemhandle The handle to the system + * \param platform_support_callback An optional callback to check platform support * \return A handle to the new context ( == NULL if creation failed). */ extern GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemhandle); diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h index 1eeb6cd852f..d89785ad9b2 100644 --- a/intern/ghost/GHOST_ISystem.h +++ b/intern/ghost/GHOST_ISystem.h @@ -437,6 +437,23 @@ class GHOST_ISystem { */ virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const = 0; + /*************************************************************************************** + * System Message Box. + ***************************************************************************************/ + + /** + * Show a system message box + * + * \param title The title of the message box + * \param message The message to display + * \param link An optional hyperlink + * \param dialog_options Options how to display the message + */ + virtual GHOST_TSuccess showMessageBox(const char * /*title*/, + const char * /*message*/, + const char * /*link*/, + GHOST_DialogOptions /*dialog_options*/) const = 0; + protected: /** * Initialize the system. diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 891f9d982b9..32472373b17 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -58,6 +58,11 @@ typedef enum { GHOST_glAlphaBackground = (1 << 2), } GHOST_GLFlags; +typedef enum GHOST_DialogOptions { + GHOST_DialogWarning = (1 << 0), + GHOST_DialogError = (1 << 1), +} GHOST_DialogOptions; + #ifdef _MSC_VER typedef __int64 GHOST_TInt64; typedef unsigned __int64 GHOST_TUns64; diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index d907c10570c..4d755de77ff 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -47,6 +47,16 @@ GHOST_TSuccess GHOST_DisposeSystem(GHOST_SystemHandle systemhandle) return system->disposeSystem(); } +void GHOST_ShowMessageBox(GHOST_SystemHandle systemhandle, + const char *title, + const char *message, + const char *link, + GHOST_DialogOptions dialog_options) +{ + GHOST_ISystem *system = (GHOST_ISystem *)systemhandle; + system->showMessageBox(title, message, link, dialog_options); +} + GHOST_EventConsumerHandle GHOST_CreateEventConsumer(GHOST_EventCallbackProcPtr eventCallback, GHOST_TUserDataPtr userdata) { @@ -651,8 +661,13 @@ GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandl GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle) { GHOST_IContext *context = (GHOST_IContext *)contexthandle; - - return context->activateDrawingContext(); + if (context) { + return context->activateDrawingContext(); + } + else { + GHOST_PRINT("GHOST_ActivateOpenGLContext: Context not valid"); + return GHOST_kFailure; + } } GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle) diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h index 2e45592e055..ea85611870a 100644 --- a/intern/ghost/intern/GHOST_System.h +++ b/intern/ghost/intern/GHOST_System.h @@ -309,6 +309,21 @@ class GHOST_System : public GHOST_ISystem { */ virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const = 0; + /** + * Show a system message box + * \param title The title of the message box + * \param message The message to display + * \param link An optional hyperlink + * \param dialog_options Options how to display the message + */ + virtual GHOST_TSuccess showMessageBox(const char * /*title*/, + const char * /*message*/, + const char * /*link*/, + GHOST_DialogOptions /*dialog_options*/) const + { + return GHOST_kFailure; + }; + protected: /** * Initialize the system. diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 68bac7d153b..5902abf8382 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -1383,7 +1383,8 @@ bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr) // Check open windows if some changes are not saved if (m_windowManager->getAnyModifiedState()) { - @autoreleasepool { + @autoreleasepool + { NSAlert *alert = [[NSAlert alloc] init]; NSString *title = [NSString stringWithFormat:@"Opening %@", [filepath lastPathComponent]]; NSString *text = @"Current document has not been saved.\nDo you really want to proceed?"; diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 1b04e1fde79..1423e0df8ec 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -31,6 +31,7 @@ #include <shlobj.h> #include <tlhelp32.h> #include <psapi.h> +#include <shellapi.h> #include <windowsx.h> #include "utfconv.h" @@ -358,14 +359,8 @@ GHOST_IContext *GHOST_SystemWin32::createOffscreenContext() goto finished; } else { - MessageBox(NULL, - "A graphics card and driver with support for OpenGL 3.3 or higher is required.\n" - "Installing the latest driver for your graphics card may resolve the issue.\n\n" - "The program will now close.", - "Blender - Unsupported Graphics Card or Driver", - MB_OK | MB_ICONERROR); delete context; - exit(); + return NULL; } #elif defined(WITH_GL_PROFILE_COMPAT) @@ -1776,6 +1771,47 @@ void GHOST_SystemWin32::putClipboard(GHOST_TInt8 *buffer, bool selection) const } } +/** \name Message Box + * \{ */ +static const char *MESSAGE_BOX_HELP_LINK_PTR = NULL; +VOID CALLBACK showMessageBoxCallBack(LPHELPINFO lpHelpInfo) +{ + if (MESSAGE_BOX_HELP_LINK_PTR) { + ShellExecute(NULL, "open", MESSAGE_BOX_HELP_LINK_PTR, NULL, NULL, SW_SHOWNORMAL); + } +} + +GHOST_TSuccess GHOST_SystemWin32::showMessageBox(const char *title, + const char *message, + const char *link, + GHOST_DialogOptions dialog_options) const +{ + uint style = MB_OK | + (dialog_options & GHOST_DialogError ? + MB_ICONERROR : + dialog_options & GHOST_DialogWarning ? MB_ICONWARNING : MB_ICONINFORMATION); + bool show_help = link && strlen(link); + if (show_help) { + GHOST_ASSERT(MESSAGE_BOX_HELP_LINK_PTR == NULL, + "showMessageBox: MESSAGE_BOX_HELP_LINK_PTR is in use"); + style |= MB_HELP; + MESSAGE_BOX_HELP_LINK_PTR = link; + } + + MSGBOXPARAMSA message_box_params = {0}; + message_box_params.cbSize = sizeof(MSGBOXCALLBACK); + message_box_params.lpszText = message; + message_box_params.lpszCaption = title; + message_box_params.dwStyle = style; + message_box_params.lpszText = message; + message_box_params.lpfnMsgBoxCallback = showMessageBoxCallBack; + + MessageBoxIndirectA(&message_box_params); + MESSAGE_BOX_HELP_LINK_PTR = NULL; + return GHOST_kSuccess; +} +/* \} */ + static DWORD GetParentProcessID(void) { HANDLE snapshot; diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index a92dea84d70..6e803b3d760 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -205,6 +205,18 @@ class GHOST_SystemWin32 : public GHOST_System { void putClipboard(GHOST_TInt8 *buffer, bool selection) const; /** + * Show a system message box + * \param title The title of the message box + * \param message The message to display + * \param link An optional hyperlink + * \param dialog_options Options how to display the message + */ + GHOST_TSuccess showMessageBox(const char *title, + const char *message, + const char *link, + GHOST_DialogOptions dialog_options) const; + + /** * Creates a drag'n'drop event and pushes it immediately onto the event queue. * Called by GHOST_DropTargetWin32 class. * \param eventType: The type of drag'n'drop event diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index a9435f3faff..a6c6aaffd6f 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -2145,6 +2145,216 @@ void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const } } +/** \name Message Box + * \{ */ +class DialogData { + public: + /* Width of the dialog */ + uint width; + /* Heigth of the dialog */ + uint height; + /* Default padding (x direction) between controls and edge of dialog */ + uint padding_x; + /* Default padding (y direction) between controls and edge of dialog */ + uint padding_y; + /* Width of a single button */ + uint button_width; + /* Height of a single button */ + uint button_height; + /* Inset of a button to its text */ + uint button_inset_x; + /* Size of the border of the button */ + uint button_border_size; + /* Height of a line of text */ + uint line_height; + /* offset of the text inside the button */ + uint button_text_offset_y; + + /* Construct a new DialogData with the default settings */ + DialogData() + : width(640), + height(175), + padding_x(10), + padding_y(5), + button_width(50), + button_height(24), + button_inset_x(10), + button_border_size(1), + line_height(16) + { + button_text_offset_y = button_height - line_height; + } + + void drawButton(Display *display, + Window &window, + GC &borderGC, + GC &buttonGC, + uint button_num, + const char *label) + { + XFillRectangle(display, + window, + borderGC, + width - (padding_x + button_width) * button_num, + height - padding_y - button_height, + button_width, + button_height); + + XFillRectangle(display, + window, + buttonGC, + width - (padding_x + button_width) * button_num + button_border_size, + height - padding_y - button_height + button_border_size, + button_width - button_border_size * 2, + button_height - button_border_size * 2); + + XDrawString(display, + window, + borderGC, + width - (padding_x + button_width) * button_num + button_inset_x, + height - padding_y - button_text_offset_y, + label, + strlen(label)); + } + + /* Is the mouse inside the given button */ + bool isInsideButton(XEvent &e, uint button_num) + { + return ((e.xmotion.y > height - padding_y - button_height) && + (e.xmotion.y < height - padding_y) && + (e.xmotion.x > width - (padding_x + button_width) * button_num) && + (e.xmotion.x < width - padding_x - (padding_x + button_width) * (button_num - 1))); + } +}; + +static void split(const char *text, const char *seps, char ***str, int *count) +{ + char *tok, *data; + int i; + *count = 0; + + data = strdup(text); + for (tok = strtok(data, seps); tok != NULL; tok = strtok(NULL, seps)) + (*count)++; + free(data); + + data = strdup(text); + *str = (char **)malloc((size_t)(*count) * sizeof(char *)); + for (i = 0, tok = strtok(data, seps); tok != NULL; tok = strtok(NULL, seps), i++) + (*str)[i] = strdup(tok); + free(data); +} + +GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title, + const char *message, + const char *link, + GHOST_DialogOptions) const +{ + char **text_splitted = NULL; + int textLines = 0; + split(message, "\n", &text_splitted, &textLines); + + DialogData dialog_data; + XSizeHints hints; + + Window window; + XEvent e; + int screen = DefaultScreen(m_display); + window = XCreateSimpleWindow(m_display, + RootWindow(m_display, screen), + 0, + 0, + dialog_data.width, + dialog_data.height, + 1, + BlackPixel(m_display, screen), + WhitePixel(m_display, screen)); + + /* Window Should not be resizable */ + { + hints.flags = PSize | PMinSize | PMaxSize; + hints.min_width = hints.max_width = hints.base_width = dialog_data.width; + hints.min_height = hints.max_height = hints.base_height = dialog_data.height; + XSetWMNormalHints(m_display, window, &hints); + } + + /* Set title */ + { + Atom wm_Name = XInternAtom(m_display, "_NET_WM_NAME", False); + Atom utf8Str = XInternAtom(m_display, "UTF8_STRING", False); + + Atom winType = XInternAtom(m_display, "_NET_WM_WINDOW_TYPE", False); + Atom typeDialog = XInternAtom(m_display, "_NET_WM_WINDOW_TYPE_DIALOG", False); + + XChangeProperty(m_display, + window, + wm_Name, + utf8Str, + 8, + PropModeReplace, + (const unsigned char *)title, + (int)strlen(title)); + + XChangeProperty( + m_display, window, winType, XA_ATOM, 32, PropModeReplace, (unsigned char *)&typeDialog, 1); + } + + /* Create buttons GC */ + XGCValues buttonBorderGCValues; + buttonBorderGCValues.foreground = BlackPixel(m_display, screen); + buttonBorderGCValues.background = WhitePixel(m_display, screen); + XGCValues buttonGCValues; + buttonGCValues.foreground = WhitePixel(m_display, screen); + buttonGCValues.background = BlackPixel(m_display, screen); + + GC buttonBorderGC = XCreateGC(m_display, window, GCForeground, &buttonBorderGCValues); + GC buttonGC = XCreateGC(m_display, window, GCForeground, &buttonGCValues); + + XSelectInput(m_display, window, ExposureMask | ButtonPressMask | ButtonReleaseMask); + XMapWindow(m_display, window); + + while (1) { + XNextEvent(m_display, &e); + if (e.type == Expose) { + for (int i = 0; i < textLines; i++) { + XDrawString(m_display, + window, + DefaultGC(m_display, screen), + dialog_data.padding_x, + dialog_data.padding_x + (i + 1) * dialog_data.line_height, + text_splitted[i], + (int)strlen(text_splitted[i])); + } + dialog_data.drawButton(m_display, window, buttonBorderGC, buttonGC, 1, "Ok"); + if (strlen(link)) { + dialog_data.drawButton(m_display, window, buttonBorderGC, buttonGC, 2, "Help"); + } + } + else if (e.type == ButtonRelease) { + if (dialog_data.isInsideButton(e, 1)) { + break; + } + else if (strlen(link) && dialog_data.isInsideButton(e, 2)) { + string cmd = "xdg-open \"" + string(link) + "\""; + if (system(cmd.c_str()) != 0) { + GHOST_PRINTF("GHOST_SystemX11::showMessageBox: Unable to run system command [%s]", cmd); + } + } + } + } + + for (int i = 0; i < textLines; i++) { + free(text_splitted[i]); + } + free(text_splitted); + + XDestroyWindow(m_display, window); + XFreeGC(m_display, buttonBorderGC); + XFreeGC(m_display, buttonGC); + return GHOST_kSuccess; +} +/* \} */ + #ifdef WITH_XDND GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType, diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index 6ad2d6decae..ba7371c6ea0 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -233,6 +233,17 @@ class GHOST_SystemX11 : public GHOST_System { */ void putClipboard(GHOST_TInt8 *buffer, bool selection) const; + /** + * Show a system message box + * \param title The title of the message box + * \param message The message to display + * \param link An optional hyperlink + * \param dialog_options Options how to display the message + */ + GHOST_TSuccess showMessageBox(const char *title, + const char *message, + const char *link, + GHOST_DialogOptions dialog_options) const; #ifdef WITH_XDND /** * Creates a drag'n'drop event and pushes it immediately onto the event queue. diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h index e55cb69a5c6..b35abb1ecef 100644 --- a/source/blender/blenkernel/BKE_appdir.h +++ b/source/blender/blenkernel/BKE_appdir.h @@ -91,5 +91,6 @@ enum { #define BLENDER_QUIT_FILE "quit.blend" #define BLENDER_BOOKMARK_FILE "bookmarks.txt" #define BLENDER_HISTORY_FILE "recent-files.txt" +#define BLENDER_PLATFORM_SUPPORT_FILE "platform_support.txt" #endif /* __BKE_APPDIR_H__ */ diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 7df1c299454..d59d1f56e92 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -29,6 +29,7 @@ #include "eevee_private.h" #include "GPU_texture.h" #include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_state.h" static struct { diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index c60aa173b48..48e9b5bcc13 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -33,6 +33,7 @@ #include "eevee_private.h" #include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_state.h" static struct { diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 3de9ce74dbc..fa7c44c1b1f 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -29,6 +29,7 @@ #include "BKE_global.h" #include "GPU_extensions.h" +#include "GPU_platform.h" #include "intern/gpu_shader_private.h" #include "intern/gpu_primitive_private.h" diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c index 316604156de..a6b8bba73e3 100644 --- a/source/blender/editors/screen/screen_draw.c +++ b/source/blender/editors/screen/screen_draw.c @@ -21,7 +21,7 @@ #include "ED_screen.h" #include "GPU_batch_presets.h" -#include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_framebuffer.h" #include "GPU_immediate.h" #include "GPU_matrix.h" diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index c0eedfeea1d..a5b18ff7589 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -47,7 +47,7 @@ #include "GPU_batch.h" #include "GPU_batch_presets.h" -#include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_immediate.h" #include "GPU_matrix.h" #include "GPU_state.h" diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index bc08da4b2cb..9320e849194 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -69,6 +69,7 @@ set(SRC intern/gpu_init_exit.c intern/gpu_material.c intern/gpu_matrix.c + intern/gpu_platform.c intern/gpu_primitive.c intern/gpu_select.c intern/gpu_select_pick.c @@ -101,6 +102,7 @@ set(SRC GPU_legacy_stubs.h GPU_material.h GPU_matrix.h + GPU_platform.h GPU_primitive.h GPU_select.h GPU_shader.h diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index 023cbb804d9..245f7f47510 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -55,34 +55,6 @@ void GPU_mem_stats_get(int *totalmem, int *freemem); void GPU_code_generate_glsl_lib(void); -/* GPU Types */ - -typedef enum eGPUDeviceType { - GPU_DEVICE_NVIDIA = (1 << 0), - GPU_DEVICE_ATI = (1 << 1), - GPU_DEVICE_INTEL = (1 << 2), - GPU_DEVICE_INTEL_UHD = (1 << 3), - GPU_DEVICE_SOFTWARE = (1 << 4), - GPU_DEVICE_UNKNOWN = (1 << 5), - GPU_DEVICE_ANY = (0xff), -} eGPUDeviceType; - -typedef enum eGPUOSType { - GPU_OS_WIN = (1 << 8), - GPU_OS_MAC = (1 << 9), - GPU_OS_UNIX = (1 << 10), - GPU_OS_ANY = (0xff00), -} eGPUOSType; - -typedef enum eGPUDriverType { - GPU_DRIVER_OFFICIAL = (1 << 16), - GPU_DRIVER_OPENSOURCE = (1 << 17), - GPU_DRIVER_SOFTWARE = (1 << 18), - GPU_DRIVER_ANY = (0xff0000), -} eGPUDriverType; - -bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver); - #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_platform.h b/source/blender/gpu/GPU_platform.h new file mode 100644 index 00000000000..f199a748cb5 --- /dev/null +++ b/source/blender/gpu/GPU_platform.h @@ -0,0 +1,75 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#ifndef __GPU_PLATFORM_H__ +#define __GPU_PLATFORM_H__ + +#include "BLI_sys_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* GPU platform support */ + +/* GPU Types */ +typedef enum eGPUDeviceType { + GPU_DEVICE_NVIDIA = (1 << 0), + GPU_DEVICE_ATI = (1 << 1), + GPU_DEVICE_INTEL = (1 << 2), + GPU_DEVICE_INTEL_UHD = (1 << 3), + GPU_DEVICE_SOFTWARE = (1 << 4), + GPU_DEVICE_UNKNOWN = (1 << 5), + GPU_DEVICE_ANY = (0xff), +} eGPUDeviceType; + +typedef enum eGPUOSType { + GPU_OS_WIN = (1 << 8), + GPU_OS_MAC = (1 << 9), + GPU_OS_UNIX = (1 << 10), + GPU_OS_ANY = (0xff00), +} eGPUOSType; + +typedef enum eGPUDriverType { + GPU_DRIVER_OFFICIAL = (1 << 16), + GPU_DRIVER_OPENSOURCE = (1 << 17), + GPU_DRIVER_SOFTWARE = (1 << 18), + GPU_DRIVER_ANY = (0xff0000), +} eGPUDriverType; + +typedef enum eGPUSupportLevel { + GPU_SUPPORT_LEVEL_SUPPORTED, + GPU_SUPPORT_LEVEL_LIMITED, + GPU_SUPPORT_LEVEL_UNSUPPORTED, +} eGPUSupportLevel; + +bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver); +eGPUSupportLevel GPU_platform_support_level(void); +const char *GPU_platform_support_level_key(void); +const char *GPU_platform_gpu_name(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __GPU_PLATFORM_H__ */ diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c index 9c1e627b6fd..dcc94cd843c 100644 --- a/source/blender/gpu/intern/gpu_batch.c +++ b/source/blender/gpu/intern/gpu_batch.c @@ -29,6 +29,7 @@ #include "GPU_batch.h" #include "GPU_batch_presets.h" #include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_matrix.h" #include "GPU_shader.h" diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index c9ae6c60293..7fa2eb6424c 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -66,6 +66,7 @@ #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_glew.h" +#include "GPU_platform.h" #include "GPU_texture.h" #include "PIL_time.h" diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index c6425854ee4..33f918559f7 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -35,6 +35,7 @@ #include "GPU_framebuffer.h" #include "GPU_glew.h" #include "GPU_texture.h" +#include "GPU_platform.h" #include "intern/gpu_private.h" @@ -68,9 +69,6 @@ static struct GPUGlobal { GLint maxubosize; GLint maxubobinds; int samples_color_texture_max; - eGPUDeviceType device; - eGPUOSType os; - eGPUDriverType driver; float line_width_range[2]; /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers * calculate dfdy in shader differently when drawing to an offscreen buffer. First @@ -126,13 +124,6 @@ static void gpu_detect_mip_render_workaround(void) GPU_texture_free(tex); } -/* GPU Types */ - -bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver) -{ - return (GG.device & device) && (GG.os & os) && (GG.driver & driver); -} - /* GPU Extensions */ int GPU_max_texture_size(void) @@ -266,11 +257,7 @@ void gpu_extensions_init(void) const char *renderer = (const char *)glGetString(GL_RENDERER); const char *version = (const char *)glGetString(GL_VERSION); - if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) { - GG.device = GPU_DEVICE_ATI; - GG.driver = GPU_DRIVER_OFFICIAL; - -#ifdef _WIN32 + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_OFFICIAL)) { if (strstr(version, "4.5.13399") || strstr(version, "4.5.13417") || strstr(version, "4.5.13422")) { /* The renderers include: @@ -282,75 +269,14 @@ void gpu_extensions_init(void) GG.unused_fb_slot_workaround = true; } -#endif + } -#if defined(__APPLE__) + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_MAC, GPU_DRIVER_OFFICIAL)) { if (strstr(renderer, "AMD Radeon Pro") || strstr(renderer, "AMD Radeon R9") || strstr(renderer, "AMD Radeon RX")) { GG.depth_blitting_workaround = true; } -#endif - } - else if (strstr(vendor, "NVIDIA")) { - GG.device = GPU_DEVICE_NVIDIA; - GG.driver = GPU_DRIVER_OFFICIAL; - } - else if (strstr(vendor, "Intel") || - /* src/mesa/drivers/dri/intel/intel_context.c */ - strstr(renderer, "Mesa DRI Intel") || strstr(renderer, "Mesa DRI Mobile Intel")) { - GG.device = GPU_DEVICE_INTEL; - GG.driver = GPU_DRIVER_OFFICIAL; - - if (strstr(renderer, "UHD Graphics") || - /* Not UHD but affected by the same bugs. */ - strstr(renderer, "HD Graphics 530") || strstr(renderer, "Kaby Lake GT2")) { - GG.device |= GPU_DEVICE_INTEL_UHD; - } } - else if ((strstr(renderer, "Mesa DRI R")) || - (strstr(renderer, "Radeon") && strstr(vendor, "X.Org")) || - (strstr(renderer, "AMD") && strstr(vendor, "X.Org")) || - (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) || - (strstr(renderer, "Gallium ") && strstr(renderer, " on AMD "))) { - GG.device = GPU_DEVICE_ATI; - GG.driver = GPU_DRIVER_OPENSOURCE; - } - else if (strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) { - GG.device = GPU_DEVICE_NVIDIA; - GG.driver = GPU_DRIVER_OPENSOURCE; - } - else if (strstr(vendor, "Mesa")) { - GG.device = GPU_DEVICE_SOFTWARE; - GG.driver = GPU_DRIVER_SOFTWARE; - } - else if (strstr(vendor, "Microsoft")) { - GG.device = GPU_DEVICE_SOFTWARE; - GG.driver = GPU_DRIVER_SOFTWARE; - } - else if (strstr(renderer, "Apple Software Renderer")) { - GG.device = GPU_DEVICE_SOFTWARE; - GG.driver = GPU_DRIVER_SOFTWARE; - } - else if (strstr(renderer, "llvmpipe")) { - GG.device = GPU_DEVICE_SOFTWARE; - GG.driver = GPU_DRIVER_SOFTWARE; - } - else { - printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n"); - printf("Detected OpenGL configuration:\n"); - printf("Vendor: %s\n", vendor); - printf("Renderer: %s\n", renderer); - GG.device = GPU_DEVICE_ANY; - GG.driver = GPU_DRIVER_ANY; - } - -#ifdef _WIN32 - GG.os = GPU_OS_WIN; -#elif defined(__APPLE__) - GG.os = GPU_OS_MAC; -#else - GG.os = GPU_OS_UNIX; -#endif GG.glew_arb_base_instance_is_supported = GLEW_ARB_base_instance; gpu_detect_mip_render_workaround(); @@ -372,11 +298,12 @@ void gpu_extensions_init(void) GG.dfdyfactors[0] = 1.0; GG.dfdyfactors[1] = 1.0; - if ((strstr(vendor, "ATI") && strstr(version, "3.3.10750"))) { + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY) && + strstr(version, "3.3.10750")) { GG.dfdyfactors[0] = 1.0; GG.dfdyfactors[1] = -1.0; } - else if ((GG.device == GPU_DEVICE_INTEL) && (GG.os == GPU_OS_WIN)) { + else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY)) { if (strstr(version, "4.0.0 - Build 10.18.10.3308") || strstr(version, "4.0.0 - Build 9.18.10.3186") || strstr(version, "4.0.0 - Build 9.18.10.3165") || @@ -401,8 +328,7 @@ void gpu_extensions_init(void) GG.context_local_shaders_workaround = true; } } - else if ((GG.device == GPU_DEVICE_ATI) && (GG.os == GPU_OS_UNIX) && - (GG.driver == GPU_DRIVER_OPENSOURCE)) { + else if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) { /* See T70187: merging vertices fail. This has been tested from 18.2.2 till 19.3.0~dev of the * Mesa driver */ GG.unused_fb_slot_workaround = true; diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index 0009e7d8c47..7b6016e11cb 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -46,7 +46,7 @@ void GPU_init(void) } initialized = true; - + gpu_platform_init(); gpu_extensions_init(); /* must come first */ gpu_codegen_init(); @@ -82,7 +82,8 @@ void GPU_exit(void) gpu_framebuffer_module_exit(); gpu_codegen_exit(); - gpu_extensions_exit(); /* must come last */ + gpu_extensions_exit(); + gpu_platform_exit(); /* must come last */ initialized = false; } diff --git a/source/blender/gpu/intern/gpu_platform.c b/source/blender/gpu/intern/gpu_platform.c new file mode 100644 index 00000000000..bcdf3224426 --- /dev/null +++ b/source/blender/gpu/intern/gpu_platform.c @@ -0,0 +1,246 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Wrap OpenGL features such as textures, shaders and GLSL + * with checks for drivers and GPU support. + */ +#include "GPU_platform.h" +#include "GPU_glew.h" +#include "gpu_private.h" + +#include <string.h> + +#include "BLI_dynstr.h" +#include "BLI_string.h" + +#include "MEM_guardedalloc.h" + +static struct GPUPlatformGlobal { + bool initialized; + eGPUDeviceType device; + eGPUOSType os; + eGPUDriverType driver; + eGPUSupportLevel support_level; + char *support_key; + char *gpu_name; +} GPG = {false}; + +typedef struct GPUPlatformSupportTest { + eGPUSupportLevel support_level; + eGPUDeviceType device; + eGPUOSType os; + eGPUDriverType driver; + const char *vendor; + const char *renderer; + const char *version; +} GPUPlatformSupportTest; + +// clang-format off +static GPUPlatformSupportTest GPU_PLATFORM_SUPPORT_TESTS[] = { + /* AMD has confirmed that drivers with this specific OpenGL backend + * has issues. The issue is that clearing multiple color buffers at once is + * not working, but is part of the OpenGL specification. Their + * advice is to tell our users to not use this driver. (T69972) */ + {GPU_SUPPORT_LEVEL_UNSUPPORTED, GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_ANY, "", "", "4.5.13571"}, + + /* This terminator record must be the last item */ + {-1, GPU_DEVICE_ANY, GPU_OS_ANY, GPU_DRIVER_ANY, "", "", ""}}; +// clang-format on + +static bool gpu_platform_support_match(const GPUPlatformSupportTest *test_record, + const char *vendor, + const char *renderer, + const char *version) +{ + return GPU_type_matches(test_record->device, test_record->os, test_record->driver) && + (strstr(vendor, test_record->vendor) && strstr(renderer, test_record->renderer) && + strstr(version, test_record->version)); +} + +eGPUSupportLevel GPU_platform_support_level(void) +{ + return GPG.support_level; +} + +const char *GPU_platform_support_level_key(void) +{ + return GPG.support_key; +} + +const char *GPU_platform_gpu_name(void) +{ + return GPG.gpu_name; +} + +/* GPU Types */ +bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver) +{ + return (GPG.device & device) && (GPG.os & os) && (GPG.driver & driver); +} + +static char *gpu_platform_create_key(eGPUSupportLevel support_level, + const char *vendor, + const char *renderer, + const char *version) +{ + DynStr *ds = BLI_dynstr_new(); + BLI_dynstr_append(ds, "{"); + BLI_dynstr_append(ds, vendor); + BLI_dynstr_append(ds, "/"); + BLI_dynstr_append(ds, renderer); + BLI_dynstr_append(ds, "/"); + BLI_dynstr_append(ds, version); + BLI_dynstr_append(ds, "}"); + BLI_dynstr_append(ds, "="); + if (support_level == GPU_SUPPORT_LEVEL_SUPPORTED) { + BLI_dynstr_append(ds, "SUPPORTED"); + } + else if (support_level == GPU_SUPPORT_LEVEL_LIMITED) { + BLI_dynstr_append(ds, "LIMITED"); + } + else { + BLI_dynstr_append(ds, "UNSUPPORTED"); + } + + char *support_key = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + BLI_str_replace_char(support_key, '\n', ' '); + BLI_str_replace_char(support_key, '\r', ' '); + return support_key; +} + +static char *gpu_platform_create_gpu_name(const char *vendor, + const char *renderer, + const char *version) +{ + DynStr *ds = BLI_dynstr_new(); + BLI_dynstr_append(ds, vendor); + BLI_dynstr_append(ds, " "); + BLI_dynstr_append(ds, renderer); + BLI_dynstr_append(ds, " "); + BLI_dynstr_append(ds, version); + + char *gpu_name = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + BLI_str_replace_char(gpu_name, '\n', ' '); + BLI_str_replace_char(gpu_name, '\r', ' '); + return gpu_name; +} + +void gpu_platform_init(void) +{ + if (GPG.initialized) { + return; + } + +#ifdef _WIN32 + GPG.os = GPU_OS_WIN; +#elif defined(__APPLE__) + GPG.os = GPU_OS_MAC; +#else + GPG.os = GPU_OS_UNIX; +#endif + + const char *vendor = (const char *)glGetString(GL_VENDOR); + const char *renderer = (const char *)glGetString(GL_RENDERER); + const char *version = (const char *)glGetString(GL_VERSION); + + if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) { + GPG.device = GPU_DEVICE_ATI; + GPG.driver = GPU_DRIVER_OFFICIAL; + } + else if (strstr(vendor, "NVIDIA")) { + GPG.device = GPU_DEVICE_NVIDIA; + GPG.driver = GPU_DRIVER_OFFICIAL; + } + else if (strstr(vendor, "Intel") || + /* src/mesa/drivers/dri/intel/intel_context.c */ + strstr(renderer, "Mesa DRI Intel") || strstr(renderer, "Mesa DRI Mobile Intel")) { + GPG.device = GPU_DEVICE_INTEL; + GPG.driver = GPU_DRIVER_OFFICIAL; + + if (strstr(renderer, "UHD Graphics") || + /* Not UHD but affected by the same bugs. */ + strstr(renderer, "HD Graphics 530") || strstr(renderer, "Kaby Lake GT2")) { + GPG.device |= GPU_DEVICE_INTEL_UHD; + } + } + else if ((strstr(renderer, "Mesa DRI R")) || + (strstr(renderer, "Radeon") && strstr(vendor, "X.Org")) || + (strstr(renderer, "AMD") && strstr(vendor, "X.Org")) || + (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) || + (strstr(renderer, "Gallium ") && strstr(renderer, " on AMD "))) { + GPG.device = GPU_DEVICE_ATI; + GPG.driver = GPU_DRIVER_OPENSOURCE; + } + else if (strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) { + GPG.device = GPU_DEVICE_NVIDIA; + GPG.driver = GPU_DRIVER_OPENSOURCE; + } + else if (strstr(vendor, "Mesa")) { + GPG.device = GPU_DEVICE_SOFTWARE; + GPG.driver = GPU_DRIVER_SOFTWARE; + } + else if (strstr(vendor, "Microsoft")) { + GPG.device = GPU_DEVICE_SOFTWARE; + GPG.driver = GPU_DRIVER_SOFTWARE; + } + else if (strstr(renderer, "Apple Software Renderer")) { + GPG.device = GPU_DEVICE_SOFTWARE; + GPG.driver = GPU_DRIVER_SOFTWARE; + } + else if (strstr(renderer, "llvmpipe")) { + GPG.device = GPU_DEVICE_SOFTWARE; + GPG.driver = GPU_DRIVER_SOFTWARE; + } + else { + printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n"); + printf("Detected OpenGL configuration:\n"); + printf("Vendor: %s\n", vendor); + printf("Renderer: %s\n", renderer); + GPG.device = GPU_DEVICE_ANY; + GPG.driver = GPU_DRIVER_ANY; + } + + /* Detect support level */ + if (!GLEW_VERSION_3_3) { + GPG.support_level = GPU_SUPPORT_LEVEL_UNSUPPORTED; + } + else { + for (int index = 0; GPU_PLATFORM_SUPPORT_TESTS[index].support_level != -1; index++) { + GPUPlatformSupportTest *test = &GPU_PLATFORM_SUPPORT_TESTS[index]; + if (gpu_platform_support_match(test, vendor, renderer, version)) { + GPG.support_level = test->support_level; + break; + } + } + } + GPG.support_key = gpu_platform_create_key(GPG.support_level, vendor, renderer, version); + GPG.gpu_name = gpu_platform_create_gpu_name(vendor, renderer, version); + GPG.initialized = true; +} + +void gpu_platform_exit(void) +{ + MEM_SAFE_FREE(GPG.support_key); + MEM_SAFE_FREE(GPG.gpu_name); +} diff --git a/source/blender/gpu/intern/gpu_private.h b/source/blender/gpu/intern/gpu_private.h index b9af8f1b38c..7846bff87f4 100644 --- a/source/blender/gpu/intern/gpu_private.h +++ b/source/blender/gpu/intern/gpu_private.h @@ -22,6 +22,10 @@ #define __GPU_PRIVATE_H__ /* call this before running any of the functions below */ +void gpu_platform_init(void); +void gpu_platform_exit(void); + +/* call this before running any of the functions below */ void gpu_extensions_init(void); void gpu_extensions_exit(void); diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 015df078228..5df73d1a0c6 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -36,6 +36,7 @@ #include "DNA_space_types.h" #include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_matrix.h" #include "GPU_shader.h" #include "GPU_texture.h" diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index a54d90f37f5..497fc13a2c8 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -38,6 +38,7 @@ #include "GPU_extensions.h" #include "GPU_glew.h" #include "GPU_framebuffer.h" +#include "GPU_platform.h" #include "GPU_texture.h" #include "gpu_context_private.h" diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index ddd0ddb46da..ebb9e1106d6 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -69,6 +69,7 @@ set(SRC intern/wm_operators.c intern/wm_panel_type.c intern/wm_playanim.c + intern/wm_platform_support.c intern/wm_splash_screen.c intern/wm_stereo.c intern/wm_subwindow.c diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 70d83153840..c8c35ba1bfc 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -99,6 +99,7 @@ #include "wm.h" #include "wm_files.h" #include "wm_window.h" +#include "wm_platform_support.h" #include "ED_anim_api.h" #include "ED_armature.h" @@ -314,6 +315,10 @@ void WM_init(bContext *C, int argc, const char **argv) #endif WM_init_opengl(G_MAIN); + if (!WM_platform_support_perform_checks()) { + exit(-1); + } + UI_init(); } diff --git a/source/blender/windowmanager/intern/wm_platform_support.c b/source/blender/windowmanager/intern/wm_platform_support.c new file mode 100644 index 00000000000..9ed6f9f4299 --- /dev/null +++ b/source/blender/windowmanager/intern/wm_platform_support.c @@ -0,0 +1,216 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup wm + */ +#include "wm_platform_support.h" +#include "wm_window_private.h" + +#include <string.h> + +#include "BLI_sys_types.h" +#include "BLI_dynstr.h" +#include "BLI_path_util.h" +#include "BLI_fileops.h" +#include "BLI_string.h" +#include "BLI_linklist.h" + +#include "BLT_translation.h" + +#include "BKE_appdir.h" +#include "BKE_global.h" + +#include "GPU_platform.h" + +#include "GHOST_C-api.h" + +#define WM_PLATFORM_SUPPORT_TEXT_SIZE 1024 + +/* Check if user has already approved the given platform_support_key. */ +static bool wm_platform_support_check_approval(const char *platform_support_key, bool update) +{ + const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); + bool result = false; + + if (G.factory_startup) { + return result; + } + + if (cfgdir) { + char filepath[FILE_MAX]; + BLI_make_file_string("/", filepath, cfgdir, BLENDER_PLATFORM_SUPPORT_FILE); + LinkNode *lines = BLI_file_read_as_lines(filepath); + for (LinkNode *line_node = lines; line_node; line_node = line_node->next) { + char *line = line_node->link; + if (STREQ(line, platform_support_key)) { + result = true; + break; + } + } + + if (!result && update) { + FILE *fp = BLI_fopen(filepath, "a"); + if (fp) { + fprintf(fp, "%s\n", platform_support_key); + fclose(fp); + } + } + + BLI_file_free_lines(lines); + } + return result; +} + +static void wm_platform_support_create_link(char *link) +{ + DynStr *ds = BLI_dynstr_new(); + + BLI_dynstr_append(ds, "https://docs.blender.org/manual/en/dev/troubleshooting/gpu/"); +#if defined(_WIN32) + BLI_dynstr_append(ds, "windows/"); +#elif defined(__APPLE__) + BLI_dynstr_append(ds, "apple/"); +#else /* UNIX */ + BLI_dynstr_append(ds, "linux/"); +#endif + + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) { + BLI_dynstr_append(ds, "intel.html"); + } + else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) { + BLI_dynstr_append(ds, "nvidia.html"); + } + else if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) { + BLI_dynstr_append(ds, "amd.html"); + } + else { + BLI_dynstr_append(ds, "unknown.html"); + } + + BLI_assert(BLI_dynstr_get_len(ds) < WM_PLATFORM_SUPPORT_TEXT_SIZE); + BLI_dynstr_get_cstring_ex(ds, link); + BLI_dynstr_free(ds); +} + +bool WM_platform_support_perform_checks() +{ + char title[WM_PLATFORM_SUPPORT_TEXT_SIZE]; + char message[WM_PLATFORM_SUPPORT_TEXT_SIZE]; + char link[WM_PLATFORM_SUPPORT_TEXT_SIZE]; + + bool result = true; + + eGPUSupportLevel support_level = GPU_platform_support_level(); + const char *platform_key = GPU_platform_support_level_key(); + + /* check if previous check matches the current check. Don't update the approval when running in + * `background`. this could have been triggered by installing addons via installers. */ + if (support_level != GPU_SUPPORT_LEVEL_UNSUPPORTED && !G.factory_startup && + wm_platform_support_check_approval(platform_key, !G.background)) { + /* if it matches the user has confirmed and whishes to use it */ + return result; + } + + /* update the message and link based on the found support level */ + GHOST_DialogOptions dialog_options = 0; + + switch (support_level) { + default: + case GPU_SUPPORT_LEVEL_SUPPORTED: + break; + + case GPU_SUPPORT_LEVEL_LIMITED: { + size_t slen = 0; + STR_CONCAT(title, slen, "Blender - "); + STR_CONCAT( + title, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Limited Platform Support")); + slen = 0; + STR_CONCAT( + message, + slen, + CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, + "Your graphics card or driver has limited support. It may work, but with " + "issues.")); + + /* TODO: Extra space is needed for the split function in GHOST_SystemX11. We should change + * the behavior in GHOST_SystemX11. */ + STR_CONCAT(message, slen, "\n \n"); + STR_CONCAT(message, + slen, + CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, + "Press help to see if the support can be improved.")); + STR_CONCAT(message, slen, "\n \n"); + STR_CONCAT(message, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Graphics card:\n")); + STR_CONCAT(message, slen, GPU_platform_gpu_name()); + + dialog_options = GHOST_DialogWarning; + break; + } + + case GPU_SUPPORT_LEVEL_UNSUPPORTED: { + size_t slen = 0; + STR_CONCAT(title, slen, "Blender - "); + STR_CONCAT( + title, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Platform Unsupported")); + slen = 0; + STR_CONCAT(message, + slen, + CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, + "Your graphics card or driver is not supported.")); + + STR_CONCAT(message, slen, "\n \n"); + STR_CONCAT(message, + slen, + CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, + "Press help to see if the support can be improved.")); + + STR_CONCAT(message, slen, "\n \n"); + STR_CONCAT(message, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Graphics card:\n")); + STR_CONCAT(message, slen, GPU_platform_gpu_name()); + STR_CONCAT(message, slen, "\n \n"); + + STR_CONCAT(message, + slen, + CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "The program will now close.")); + dialog_options = GHOST_DialogError; + result = false; + break; + } + } + wm_platform_support_create_link(link); + + bool show_message = ELEM( + support_level, GPU_SUPPORT_LEVEL_LIMITED, GPU_SUPPORT_LEVEL_UNSUPPORTED); + + /* We are running in the background print the message in the console. */ + if ((G.background || G.debug & G_DEBUG) && show_message) { + printf("%s\n\n%s\n%s\n", title, message, link); + } + if (G.background) { + /* don't show the messagebox when running in background mode. Printing to + * console is enough. */ + result = true; + } + else if (show_message) { + WM_ghost_show_message_box(title, message, link, dialog_options); + } + + return result; +}
\ No newline at end of file diff --git a/source/blender/windowmanager/intern/wm_platform_support.h b/source/blender/windowmanager/intern/wm_platform_support.h new file mode 100644 index 00000000000..a8e20f6bcdf --- /dev/null +++ b/source/blender/windowmanager/intern/wm_platform_support.h @@ -0,0 +1,30 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup wm + */ +#ifndef __WM_PLATFORM_SUPPORT_H__ +#define __WM_PLATFORM_SUPPORT_H__ + +#include "BLI_sys_types.h" + +bool WM_platform_support_perform_checks(void); + +#endif diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 1ae95917c99..ac10f9489a2 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -61,7 +61,9 @@ #include "wm.h" #include "wm_draw.h" #include "wm_files.h" +#include "wm_platform_support.h" #include "wm_window.h" +#include "wm_window_private.h" #include "wm_event_system.h" #include "ED_anim_api.h" @@ -78,7 +80,7 @@ #include "GPU_batch.h" #include "GPU_batch_presets.h" #include "GPU_draw.h" -#include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_framebuffer.h" #include "GPU_init_exit.h" #include "GPU_immediate.h" @@ -2431,4 +2433,12 @@ void WM_opengl_context_release(void *context) GHOST_ReleaseOpenGLContext((GHOST_ContextHandle)context); } +void WM_ghost_show_message_box(const char *title, + const char *message, + const char *link, + GHOST_DialogOptions dialog_options) +{ + BLI_assert(g_system); + GHOST_ShowMessageBox(g_system, title, message, link, dialog_options); +} /** \} */ diff --git a/source/blender/windowmanager/intern/wm_window_private.h b/source/blender/windowmanager/intern/wm_window_private.h new file mode 100644 index 00000000000..189b77721cf --- /dev/null +++ b/source/blender/windowmanager/intern/wm_window_private.h @@ -0,0 +1,40 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup wm + */ +#ifndef __WM_WINDOW_PRIVATE_H__ +#define __WM_WINDOW_PRIVATE_H__ + +#include "BLI_sys_types.h" +#include "GHOST_Types.h" + +/* *************** Message box *************** */ +/* `WM_ghost_show_message_box` is implemented in `wm_windows.c` it is + * defined here as it was implemented to be used for showing + * a message to the user when the platform is not (fully) supported. + * + * In all other cases this message box should not be used. */ +void WM_ghost_show_message_box(const char *title, + const char *message, + const char *link, + GHOST_DialogOptions dialog_options); + +#endif |