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:
-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