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:
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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]",
|
||||
|
||||
@@ -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
|
||||
|
||||
100
source/blender/gpu/dummy/dummy_backend.hh
Normal file
100
source/blender/gpu/dummy/dummy_backend.hh
Normal 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
|
||||
32
source/blender/gpu/dummy/dummy_batch.hh
Normal file
32
source/blender/gpu/dummy/dummy_batch.hh
Normal 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
|
||||
51
source/blender/gpu/dummy/dummy_context.hh
Normal file
51
source/blender/gpu/dummy/dummy_context.hh
Normal 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
|
||||
61
source/blender/gpu/dummy/dummy_framebuffer.hh
Normal file
61
source/blender/gpu/dummy/dummy_framebuffer.hh
Normal 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
|
||||
40
source/blender/gpu/dummy/dummy_vertex_buffer.hh
Normal file
40
source/blender/gpu/dummy/dummy_vertex_buffer.hh
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user