Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen Bakker <j.bakker@atmind.nl>2019-10-03 17:21:23 +0300
committerJeroen Bakker <j.bakker@atmind.nl>2019-10-04 17:23:39 +0300
commit56dd7feb06bff69dce11d72828a6091eb48adebe (patch)
treeae85f524f067e9e7ec706f8b48973233f011840d
parent45745f7862beb8baaf060d66ca97513d5dd9d848 (diff)
GPU: Platform Support Level
Adds a check when starting blender if your platform is supported. We use a blacklist as drivers are updated more regular then blender (stable releases). The mechanism detects if the support level changed or has been validated by the user previously. Changes can happen due to users updating their drivers, but also when we change the support level in our code base. When the user has seen the limited support level message it is saved in the user config. It would be better to have a system specific config section, but currently not clear what could benefit from that. When the platform is unsupported or has limited support a dialog box will appear including a link to our user manual describing what to do. **Windows** Windows uses the MessageBox that is provided by the windows kernel. **X11** We use a very lowlevel messagebox for X11. It is very limited in use and can be fine tuned when needed. **SDL/APPLE** There is no implementation for SDL or APPLE at this moment as the platform support feature targets mostly Windows users. Reviewed By: brecht Differential Revision: https://developer.blender.org/D5955
-rw-r--r--intern/ghost/GHOST_C-api.h16
-rw-r--r--intern/ghost/GHOST_ISystem.h17
-rw-r--r--intern/ghost/GHOST_Types.h5
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp19
-rw-r--r--intern/ghost/intern/GHOST_System.h15
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm3
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp50
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h12
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp210
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h11
-rw-r--r--source/blender/blenkernel/BKE_appdir.h1
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_occlusion.c1
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c1
-rw-r--r--source/blender/editors/screen/screen_draw.c2
-rw-r--r--source/blender/editors/space_node/drawnode.c2
-rw-r--r--source/blender/gpu/CMakeLists.txt2
-rw-r--r--source/blender/gpu/GPU_extensions.h28
-rw-r--r--source/blender/gpu/GPU_platform.h75
-rw-r--r--source/blender/gpu/intern/gpu_batch.c1
-rw-r--r--source/blender/gpu/intern/gpu_draw.c1
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c90
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c5
-rw-r--r--source/blender/gpu/intern/gpu_platform.c246
-rw-r--r--source/blender/gpu/intern/gpu_private.h4
-rw-r--r--source/blender/gpu/intern/gpu_shader.c1
-rw-r--r--source/blender/gpu/intern/gpu_texture.c1
-rw-r--r--source/blender/windowmanager/CMakeLists.txt1
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c5
-rw-r--r--source/blender/windowmanager/intern/wm_platform_support.c216
-rw-r--r--source/blender/windowmanager/intern/wm_platform_support.h30
-rw-r--r--source/blender/windowmanager/intern/wm_window.c12
-rw-r--r--source/blender/windowmanager/intern/wm_window_private.h40
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