GPU: Add Dummy Backend For Unsupported Platforms

With the introduction of metal and vulkan we use a different
GPU backend selection which broke the dialog box for unsupported
platforms.

Blender asserted and segfaulted before the dialog was being shown
to the user.

This patch solves this by introducing a dummy GPU backend in case no
GPU backend was supported by OpenGL, Metal and Vulkan Backend.

It also adds the showMessageBox to GHOST_SystemCocoa.

Related to #110335

Pull Request: https://projects.blender.org/blender/blender/pulls/110919
This commit is contained in:
Jeroen Bakker
2023-08-15 14:15:12 +02:00
parent 7875074532
commit dd4ab50065
12 changed files with 389 additions and 8 deletions

View File

@@ -267,6 +267,22 @@ class GHOST_SystemCocoa : public GHOST_System {
*/
GHOST_TSuccess handleKeyEvent(void *eventPtr);
/**
* Show a system message box
* \param title: The title of the message box.
* \param message: The message to display.
* \param help_label: Help button label.
* \param continue_label: Continue button label.
* \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 *help_label,
const char *continue_label,
const char *link,
GHOST_DialogOptions dialog_options) const;
protected:
/**
* Initializes the system.

View File

@@ -2013,3 +2013,46 @@ void GHOST_SystemCocoa::putClipboard(const char *buffer, bool selection) const
[pasteBoard setString:textToCopy forType:NSPasteboardTypeString];
}
}
GHOST_TSuccess GHOST_SystemCocoa::showMessageBox(const char *title,
const char *message,
const char *help_label,
const char *continue_label,
const char *link,
GHOST_DialogOptions dialog_options) const
{
@autoreleasepool {
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
[alert setAccessoryView:[[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 500, 0)] autorelease]];
NSString *titleString = [NSString stringWithCString:title];
NSString *messageString = [NSString stringWithCString:message];
NSString *continueString = [NSString stringWithCString:continue_label];
NSString *helpString = [NSString stringWithCString:help_label];
if (dialog_options & GHOST_DialogError) {
[alert setAlertStyle:NSAlertStyleCritical];
}
else if (dialog_options & GHOST_DialogWarning) {
[alert setAlertStyle:NSAlertStyleWarning];
}
else {
[alert setAlertStyle:NSAlertStyleInformational];
}
[alert setMessageText:titleString];
[alert setInformativeText:messageString];
[alert addButtonWithTitle:continueString];
if (link && strlen(link)) {
[alert addButtonWithTitle:helpString];
}
NSModalResponse response = [alert runModal];
if (response == NSAlertSecondButtonReturn) {
NSString *linkString = [NSString stringWithCString:link];
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:linkString]];
}
}
return GHOST_kSuccess;
}

View File

@@ -2588,8 +2588,9 @@ GHOST_TSuccess GHOST_SystemWin32::showMessageBox(const char *title,
config.pszWindowTitle = L"Blender";
config.pszMainInstruction = title_16;
config.pszContent = message_16;
config.pButtons = (link) ? buttons : buttons + 1;
config.cButtons = (link) ? 2 : 1;
const bool has_link = link && strlen(link);
config.pButtons = has_link ? buttons : buttons + 1;
config.cButtons = has_link ? 2 : 1;
TaskDialogIndirect(&config, &nButtonPressed, nullptr, nullptr);
switch (nButtonPressed) {

View File

@@ -2429,6 +2429,8 @@ GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title,
XSelectInput(m_display, window, ExposureMask | ButtonPressMask | ButtonReleaseMask);
XMapWindow(m_display, window);
const bool has_link = link && strlen(link);
while (true) {
XNextEvent(m_display, &e);
if (e.type == Expose) {
@@ -2442,7 +2444,7 @@ GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title,
int(strlen(text_splitted[i])));
}
dialog_data.drawButton(m_display, window, buttonBorderGC, buttonGC, 1, continue_label);
if (strlen(link)) {
if (has_link) {
dialog_data.drawButton(m_display, window, buttonBorderGC, buttonGC, 2, help_label);
}
}
@@ -2451,7 +2453,7 @@ GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title,
break;
}
if (dialog_data.isInsideButton(e, 2)) {
if (strlen(link)) {
if (has_link) {
string cmd = "xdg-open \"" + string(link) + "\"";
if (system(cmd.c_str()) != 0) {
GHOST_PRINTF("GHOST_SystemX11::showMessageBox: Unable to run system command [%s]",

View File

@@ -5,6 +5,7 @@
set(INC
.
intern
dummy
metal
opengl
vulkan
@@ -142,6 +143,12 @@ set(SRC
intern/gpu_uniform_buffer_private.hh
intern/gpu_vertex_buffer_private.hh
intern/gpu_vertex_format_private.h
dummy/dummy_backend.hh
dummy/dummy_batch.hh
dummy/dummy_context.hh
dummy/dummy_framebuffer.hh
dummy/dummy_vertex_buffer.hh
)
set(OPENGL_SRC

View File

@@ -0,0 +1,100 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*/
#pragma once
#include "gpu_backend.hh"
#include "gpu_capabilities_private.hh"
#include "gpu_platform_private.hh"
#include "dummy_batch.hh"
#include "dummy_context.hh"
#include "dummy_framebuffer.hh"
#include "dummy_vertex_buffer.hh"
namespace blender::gpu {
class DummyBackend : public GPUBackend {
public:
DummyBackend()
{
GPG.init(GPU_DEVICE_ANY,
GPU_OS_ANY,
GPU_DRIVER_ANY,
GPU_SUPPORT_LEVEL_UNSUPPORTED,
GPU_BACKEND_NONE,
"Unknown",
"",
"");
}
void delete_resources() override {}
void samplers_update() override {}
void compute_dispatch(int /*groups_x_len*/, int /*groups_y_len*/, int /*groups_z_len*/) override
{
}
void compute_dispatch_indirect(StorageBuf * /*indirect_buf*/) override {}
Context *context_alloc(void * /*ghost_window*/, void * /*ghost_context*/) override
{
return new DummyContext;
}
Batch *batch_alloc() override
{
return new DummyBatch;
}
DrawList *drawlist_alloc(int /*list_length*/) override
{
return nullptr;
}
Fence *fence_alloc() override
{
return nullptr;
}
FrameBuffer *framebuffer_alloc(const char *name) override
{
return new DummyFrameBuffer(name);
}
IndexBuf *indexbuf_alloc() override
{
return nullptr;
}
PixelBuffer *pixelbuf_alloc(uint /*size*/) override
{
return nullptr;
}
QueryPool *querypool_alloc() override
{
return nullptr;
}
Shader *shader_alloc(const char * /*name*/) override
{
return nullptr;
}
Texture *texture_alloc(const char * /*name*/) override
{
return nullptr;
}
UniformBuf *uniformbuf_alloc(int /*size*/, const char * /*name*/) override
{
return nullptr;
}
StorageBuf *storagebuf_alloc(int /*size*/,
GPUUsageType /*usage*/,
const char * /*name*/) override
{
return nullptr;
}
VertBuf *vertbuf_alloc() override
{
return new DummyVertexBuffer;
}
void render_begin() override {}
void render_end() override {}
void render_step() override {}
};
} // namespace blender::gpu

View File

@@ -0,0 +1,32 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*/
#pragma once
#include "gpu_batch_private.hh"
namespace blender::gpu {
class DummyBatch : public Batch {
public:
void draw(int /*vertex_first*/,
int /*vertex_count*/,
int /*instance_first*/,
int /*instance_count*/) override
{
}
void draw_indirect(GPUStorageBuf * /*indirect_buf*/, intptr_t /*offset*/) override {}
void multi_draw_indirect(GPUStorageBuf * /*indirect_buf*/,
int /*count*/,
intptr_t /*offset*/,
intptr_t /*stride*/) override
{
}
};
} // namespace blender::gpu

View File

@@ -0,0 +1,51 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*/
#pragma once
#include "gpu_context_private.hh"
#include "dummy_framebuffer.hh"
namespace blender::gpu {
class DummyContext : public Context {
public:
DummyContext()
{
back_left = active_fb = new DummyFrameBuffer("DummyFramebuffer");
}
void activate() override {}
void deactivate() override {}
void begin_frame() override {}
void end_frame() override {}
void flush() override {}
void finish() override {}
void memory_statistics_get(int * /*total_mem*/, int * /*free_mem*/) override {}
void debug_group_begin(const char *, int) override {}
void debug_group_end() override {}
bool debug_capture_begin() override
{
return false;
}
void debug_capture_end() override {}
void *debug_capture_scope_create(const char * /*name*/) override
{
return nullptr;
}
bool debug_capture_scope_begin(void * /*scope*/) override
{
return false;
}
void debug_capture_scope_end(void * /*scope*/) override {}
};
} // namespace blender::gpu

View File

@@ -0,0 +1,61 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*/
#pragma once
#include "gpu_framebuffer_private.hh"
namespace blender::gpu {
class DummyFrameBuffer : public FrameBuffer {
public:
DummyFrameBuffer(const char *name) : FrameBuffer(name) {}
void bind(bool /*enabled_srgb*/) override {}
bool check(char /*err_out*/[256]) override
{
return true;
}
void clear(eGPUFrameBufferBits /*buffers*/,
const float /*clear_color*/[4],
float /*clear_depth*/,
uint /*clear_stencil*/) override
{
}
void clear_multi(const float (*/*clear_color*/)[4]) override {}
void clear_attachment(GPUAttachmentType /*type*/,
eGPUDataFormat /*data_format*/,
const void * /*clear_value*/) override
{
}
void attachment_set_loadstore_op(GPUAttachmentType /*type*/,
eGPULoadOp /*load_action*/,
eGPUStoreOp /*store_action*/) override
{
}
void read(eGPUFrameBufferBits /*planes*/,
eGPUDataFormat /*format*/,
const int /*area*/[4],
int /*channel_len*/,
int /*slot*/,
void * /*r_data*/) override
{
}
void blit_to(eGPUFrameBufferBits /*planes*/,
int /*src_slot*/,
FrameBuffer * /*dst*/,
int /*dst_slot*/,
int /*dst_offset_x*/,
int /*dst_offset_y*/) override
{
}
};
} // namespace blender::gpu

View File

@@ -0,0 +1,40 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*/
#pragma once
#include "gpu_vertex_buffer_private.hh"
namespace blender::gpu {
class DummyVertexBuffer : public VertBuf {
public:
void bind_as_ssbo(uint /*binding*/) override {}
void bind_as_texture(uint /*binding*/) override {}
void wrap_handle(uint64_t /*handle*/) override {}
void update_sub(uint /*start*/, uint /*len*/, const void * /*data*/) override {}
void read(void * /*data*/) const override {}
protected:
void acquire_data() override
{
MEM_SAFE_FREE(data);
data = (uchar *)MEM_mallocN(sizeof(uchar) * this->size_alloc_get(), __func__);
}
void resize_data() override {}
void release_data() override
{
MEM_SAFE_FREE(data);
}
void upload_data() override {}
void duplicate_data(VertBuf * /*dst*/) override {}
};
} // namespace blender::gpu

View File

@@ -35,6 +35,7 @@
#ifdef WITH_METAL_BACKEND
# include "mtl_backend.hh"
#endif
#include "dummy_backend.hh"
#include <mutex>
#include <vector>
@@ -291,6 +292,8 @@ static bool gpu_backend_supported()
#else
return false;
#endif
case GPU_BACKEND_NONE:
return true;
default:
BLI_assert(false && "No backend specified");
return false;
@@ -326,6 +329,9 @@ static void gpu_backend_create()
g_backend = new MTLBackend;
break;
#endif
case GPU_BACKEND_NONE:
g_backend = new DummyBackend;
break;
default:
BLI_assert(0);
break;

View File

@@ -159,11 +159,22 @@ bool WM_platform_support_perform_checks()
STR_CONCAT(
title, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Platform Unsupported"));
slen = 0;
#ifdef __APPLE__
STR_CONCAT(message,
slen,
CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER,
"Your graphics card or macOS version is not supported."));
STR_CONCAT(message, slen, "\n \n");
STR_CONCAT(message,
slen,
CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER,
"Upgrading to the latest macOS version may improve Blender support"));
#else
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,
@@ -174,6 +185,7 @@ bool WM_platform_support_perform_checks()
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());
#endif
STR_CONCAT(message, slen, "\n \n");
STR_CONCAT(message,
@@ -184,10 +196,16 @@ bool WM_platform_support_perform_checks()
break;
}
}
wm_platform_support_create_link(link);
bool backend_detected = GPU_backend_get_type() != GPU_BACKEND_NONE;
bool show_message = ELEM(
support_level, GPU_SUPPORT_LEVEL_LIMITED, GPU_SUPPORT_LEVEL_UNSUPPORTED);
bool show_continue = backend_detected;
bool show_link = backend_detected;
link[0] = '\0';
if (show_link) {
wm_platform_support_create_link(link);
}
/* We are running in the background print the message in the console. */
if ((G.background || G.debug & G_DEBUG) && show_message) {
@@ -199,8 +217,12 @@ bool WM_platform_support_perform_checks()
result = true;
}
else if (show_message) {
WM_ghost_show_message_box(
title, message, "Find Latest Drivers", "Continue Anyway", link, dialog_options);
WM_ghost_show_message_box(title,
message,
"Find Latest Drivers",
show_continue ? "Continue Anyway" : "Exit",
link,
dialog_options);
}
return result;