mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Improve error handling in vulkan
so it doesn't assert & shows a message box with the error and some tips
This commit is contained in:
parent
dff876d58c
commit
870ea8566e
|
@ -8,8 +8,9 @@
|
|||
#include <SDL_video.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct SBackendCapabilites;
|
||||
|
@ -23,9 +24,55 @@ enum EDebugGFXModes
|
|||
DEBUG_GFX_MODE_ALL,
|
||||
};
|
||||
|
||||
enum ERunCommandReturnTypes
|
||||
{
|
||||
RUN_COMMAND_COMMAND_HANDLED = 0,
|
||||
RUN_COMMAND_COMMAND_UNHANDLED,
|
||||
RUN_COMMAND_COMMAND_WARNING,
|
||||
RUN_COMMAND_COMMAND_ERROR,
|
||||
};
|
||||
|
||||
enum EGFXErrorType
|
||||
{
|
||||
GFX_ERROR_TYPE_NONE = 0,
|
||||
GFX_ERROR_TYPE_INIT,
|
||||
GFX_ERROR_TYPE_OUT_OF_MEMORY_IMAGE,
|
||||
GFX_ERROR_TYPE_OUT_OF_MEMORY_BUFFER,
|
||||
GFX_ERROR_TYPE_OUT_OF_MEMORY_STAGING,
|
||||
GFX_ERROR_TYPE_RENDER_RECORDING,
|
||||
GFX_ERROR_TYPE_RENDER_CMD_FAILED,
|
||||
GFX_ERROR_TYPE_RENDER_SUBMIT_FAILED,
|
||||
GFX_ERROR_TYPE_SWAP_FAILED,
|
||||
GFX_ERROR_TYPE_UNKNOWN,
|
||||
};
|
||||
|
||||
enum EGFXWarningType
|
||||
{
|
||||
GFX_WARNING_TYPE_NONE = 0,
|
||||
GFX_WARNING_TYPE_INIT_FAILED,
|
||||
GFX_WARNING_LOW_ON_MEMORY,
|
||||
GFX_WARNING_MISSING_EXTENSION,
|
||||
GFX_WARNING_TYPE_UNKNOWN,
|
||||
};
|
||||
|
||||
struct SGFXErrorContainer
|
||||
{
|
||||
EGFXErrorType m_ErrorType = EGFXErrorType::GFX_ERROR_TYPE_NONE;
|
||||
std::vector<std::string> m_vErrors;
|
||||
};
|
||||
|
||||
struct SGFXWarningContainer
|
||||
{
|
||||
EGFXWarningType m_WarningType = EGFXWarningType::GFX_WARNING_TYPE_NONE;
|
||||
std::vector<std::string> m_vWarnings;
|
||||
};
|
||||
|
||||
class CCommandProcessorFragment_GLBase
|
||||
{
|
||||
protected:
|
||||
SGFXErrorContainer m_Error;
|
||||
SGFXWarningContainer m_Warning;
|
||||
|
||||
static size_t TexFormatToImageColorChannelCount(int TexFormat);
|
||||
static void *Resize(const unsigned char *pData, int Width, int Height, int NewWidth, int NewHeight, int BPP);
|
||||
|
||||
|
@ -35,11 +82,16 @@ protected:
|
|||
|
||||
public:
|
||||
virtual ~CCommandProcessorFragment_GLBase() = default;
|
||||
virtual bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand) = 0;
|
||||
virtual ERunCommandReturnTypes RunCommand(const CCommandBuffer::SCommand *pBaseCommand) = 0;
|
||||
|
||||
virtual void StartCommands(size_t CommandCount, size_t EstimatedRenderCallCount) {}
|
||||
virtual void EndCommands() {}
|
||||
|
||||
const SGFXErrorContainer &GetError() { return m_Error; }
|
||||
virtual void ErroneousCleanup() {}
|
||||
|
||||
const SGFXWarningContainer &GetWarning() { return m_Warning; }
|
||||
|
||||
enum
|
||||
{
|
||||
CMD_PRE_INIT = CCommandBuffer::CMDGROUP_PLATFORM_GL,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <engine/client/backend_sdl.h>
|
||||
|
||||
bool CCommandProcessorFragment_Null::RunCommand(const CCommandBuffer::SCommand *pBaseCommand)
|
||||
ERunCommandReturnTypes CCommandProcessorFragment_Null::RunCommand(const CCommandBuffer::SCommand *pBaseCommand)
|
||||
{
|
||||
switch(pBaseCommand->m_Cmd)
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ bool CCommandProcessorFragment_Null::RunCommand(const CCommandBuffer::SCommand *
|
|||
Cmd_TextTexture_Update(static_cast<const CCommandBuffer::SCommand_TextTexture_Update *>(pBaseCommand));
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
return ERunCommandReturnTypes::RUN_COMMAND_COMMAND_HANDLED;
|
||||
}
|
||||
|
||||
bool CCommandProcessorFragment_Null::Cmd_Init(const SCommand_Init *pCommand)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
class CCommandProcessorFragment_Null : public CCommandProcessorFragment_GLBase
|
||||
{
|
||||
bool GetPresentedImageData(uint32_t &Width, uint32_t &Height, uint32_t &Format, std::vector<uint8_t> &vDstData) override { return false; };
|
||||
bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand) override;
|
||||
ERunCommandReturnTypes RunCommand(const CCommandBuffer::SCommand *pBaseCommand) override;
|
||||
bool Cmd_Init(const SCommand_Init *pCommand);
|
||||
virtual void Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand);
|
||||
virtual void Cmd_TextTextures_Create(const CCommandBuffer::SCommand_TextTextures_Create *pCommand);
|
||||
|
|
|
@ -1059,7 +1059,7 @@ CCommandProcessorFragment_OpenGL::CCommandProcessorFragment_OpenGL()
|
|||
m_HasShaders = false;
|
||||
}
|
||||
|
||||
bool CCommandProcessorFragment_OpenGL::RunCommand(const CCommandBuffer::SCommand *pBaseCommand)
|
||||
ERunCommandReturnTypes CCommandProcessorFragment_OpenGL::RunCommand(const CCommandBuffer::SCommand *pBaseCommand)
|
||||
{
|
||||
switch(pBaseCommand->m_Cmd)
|
||||
{
|
||||
|
@ -1125,10 +1125,10 @@ bool CCommandProcessorFragment_OpenGL::RunCommand(const CCommandBuffer::SCommand
|
|||
case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER: Cmd_RenderQuadContainer(static_cast<const CCommandBuffer::SCommand_RenderQuadContainer *>(pBaseCommand)); break;
|
||||
case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER_EX: Cmd_RenderQuadContainerEx(static_cast<const CCommandBuffer::SCommand_RenderQuadContainerEx *>(pBaseCommand)); break;
|
||||
case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER_SPRITE_MULTIPLE: Cmd_RenderQuadContainerAsSpriteMultiple(static_cast<const CCommandBuffer::SCommand_RenderQuadContainerAsSpriteMultiple *>(pBaseCommand)); break;
|
||||
default: return false;
|
||||
default: return ERunCommandReturnTypes::RUN_COMMAND_COMMAND_UNHANDLED;
|
||||
}
|
||||
|
||||
return true;
|
||||
return ERunCommandReturnTypes::RUN_COMMAND_COMMAND_HANDLED;
|
||||
}
|
||||
|
||||
// ------------ CCommandProcessorFragment_OpenGL2
|
||||
|
|
|
@ -128,7 +128,7 @@ public:
|
|||
CCommandProcessorFragment_OpenGL();
|
||||
virtual ~CCommandProcessorFragment_OpenGL() = default;
|
||||
|
||||
bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand) override;
|
||||
ERunCommandReturnTypes RunCommand(const CCommandBuffer::SCommand *pBaseCommand) override;
|
||||
};
|
||||
|
||||
class CCommandProcessorFragment_OpenGL2 : public CCommandProcessorFragment_OpenGL
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,11 +5,13 @@
|
|||
#endif
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_messagebox.h>
|
||||
|
||||
#include <base/math.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <engine/shared/config.h>
|
||||
#include <engine/shared/localization.h>
|
||||
|
||||
#include <base/tl/threading.h>
|
||||
|
||||
|
@ -72,7 +74,8 @@ void CGraphicsBackend_Threaded::ThreadFunc(void *pUser)
|
|||
}
|
||||
}
|
||||
|
||||
CGraphicsBackend_Threaded::CGraphicsBackend_Threaded()
|
||||
CGraphicsBackend_Threaded::CGraphicsBackend_Threaded(TTranslateFunc &&TranslateFunc) :
|
||||
m_TranslateFunc(std::move(TranslateFunc))
|
||||
{
|
||||
m_pBuffer = nullptr;
|
||||
m_pProcessor = nullptr;
|
||||
|
@ -97,6 +100,7 @@ void CGraphicsBackend_Threaded::StopProcessor()
|
|||
m_Shutdown = true;
|
||||
{
|
||||
std::unique_lock<std::mutex> Lock(m_BufferSwapMutex);
|
||||
m_Warning = m_pProcessor->GetWarning();
|
||||
m_BufferSwapCond.notify_all();
|
||||
}
|
||||
thread_wait(m_pThread);
|
||||
|
@ -106,13 +110,27 @@ void CGraphicsBackend_Threaded::RunBuffer(CCommandBuffer *pBuffer)
|
|||
{
|
||||
#ifdef CONF_WEBASM
|
||||
// run everything single threaded for now, context binding in a thread seems to not work as of now
|
||||
RunBufferSingleThreadedUnsafe(pBuffer);
|
||||
if(!m_pProcessor->HasError())
|
||||
{
|
||||
RunBufferSingleThreadedUnsafe(pBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessError();
|
||||
}
|
||||
#else
|
||||
WaitForIdle();
|
||||
std::unique_lock<std::mutex> Lock(m_BufferSwapMutex);
|
||||
m_pBuffer = pBuffer;
|
||||
m_BufferInProcess.store(true, std::memory_order_relaxed);
|
||||
m_BufferSwapCond.notify_all();
|
||||
if(!m_pProcessor->HasError())
|
||||
{
|
||||
m_pBuffer = pBuffer;
|
||||
m_BufferInProcess.store(true, std::memory_order_relaxed);
|
||||
m_BufferSwapCond.notify_all();
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessError();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -132,6 +150,28 @@ void CGraphicsBackend_Threaded::WaitForIdle()
|
|||
m_BufferSwapCond.wait(Lock, [this]() { return m_pBuffer == nullptr; });
|
||||
}
|
||||
|
||||
void CGraphicsBackend_Threaded::ProcessError()
|
||||
{
|
||||
const auto &Error = m_pProcessor->GetError();
|
||||
std::string VerboseStr;
|
||||
for(const auto &ErrStr : Error.m_vErrors)
|
||||
VerboseStr.append(std::string(m_TranslateFunc(ErrStr.c_str(), "")) + "\n");
|
||||
const auto CreatedMsgBox = TryCreateMsgBox(true, "Graphics Assertion", VerboseStr.c_str());
|
||||
// check if error msg can be shown, then assert
|
||||
dbg_assert(!CreatedMsgBox, VerboseStr.c_str());
|
||||
}
|
||||
|
||||
bool CGraphicsBackend_Threaded::GetWarning(std::vector<std::string> &WarningStrings)
|
||||
{
|
||||
if(HasWarning())
|
||||
{
|
||||
m_Warning.m_WarningType = GFX_WARNING_TYPE_NONE;
|
||||
WarningStrings = m_Warning.m_vWarnings;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------ CCommandProcessorFragment_General
|
||||
|
||||
void CCommandProcessorFragment_General::Cmd_Signal(const CCommandBuffer::SCommand_Signal *pCommand)
|
||||
|
@ -223,14 +263,84 @@ bool CCommandProcessorFragment_SDL::RunCommand(const CCommandBuffer::SCommand *p
|
|||
|
||||
// ------------ CCommandProcessor_SDL_GL
|
||||
|
||||
void CCommandProcessor_SDL_GL::HandleError()
|
||||
{
|
||||
auto &Error = GetError();
|
||||
switch(Error.m_ErrorType)
|
||||
{
|
||||
case GFX_ERROR_TYPE_INIT:
|
||||
Error.m_vErrors.emplace_back(Localizable("Failed during initialization. Try to change gfx_backend to OpenGL or Vulkan from settings_ddnet.cfg in the config directory and try again."));
|
||||
break;
|
||||
case GFX_ERROR_TYPE_OUT_OF_MEMORY_IMAGE:
|
||||
[[fallthrough]];
|
||||
case GFX_ERROR_TYPE_OUT_OF_MEMORY_BUFFER:
|
||||
[[fallthrough]];
|
||||
case GFX_ERROR_TYPE_OUT_OF_MEMORY_STAGING:
|
||||
Error.m_vErrors.emplace_back(Localizable("Out of VRAM. Try removing custom assets (skins, entities etc.), especially with high resolution."));
|
||||
break;
|
||||
case GFX_ERROR_TYPE_RENDER_RECORDING:
|
||||
Error.m_vErrors.emplace_back(Localizable("An error during command recording occurred. Try to update your GPU drivers."));
|
||||
break;
|
||||
case GFX_ERROR_TYPE_RENDER_CMD_FAILED:
|
||||
Error.m_vErrors.emplace_back(Localizable("A render command failed. Try to update your GPU drivers."));
|
||||
break;
|
||||
case GFX_ERROR_TYPE_RENDER_SUBMIT_FAILED:
|
||||
Error.m_vErrors.emplace_back(Localizable("Submitting the render commands failed. Try to update your GPU drivers."));
|
||||
break;
|
||||
case GFX_ERROR_TYPE_SWAP_FAILED:
|
||||
Error.m_vErrors.emplace_back(Localizable("Failed to swap framebuffers. Try to update your GPU drivers."));
|
||||
break;
|
||||
case GFX_ERROR_TYPE_UNKNOWN:
|
||||
[[fallthrough]];
|
||||
default:
|
||||
Error.m_vErrors.emplace_back(Localizable("Unknown error. Try to change gfx_backend to OpenGL or Vulkan from settings_ddnet.cfg in the config directory and try again."));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CCommandProcessor_SDL_GL::HandleWarning()
|
||||
{
|
||||
auto &Warn = GetWarning();
|
||||
switch(Warn.m_WarningType)
|
||||
{
|
||||
case GFX_WARNING_TYPE_INIT_FAILED:
|
||||
Warn.m_vWarnings.emplace_back(Localizable("Could not initialize the given graphics backend, reverting to the default backend now."));
|
||||
break;
|
||||
case GFX_WARNING_MISSING_EXTENSION:
|
||||
// ignore this warning for now
|
||||
return;
|
||||
case GFX_WARNING_LOW_ON_MEMORY:
|
||||
// ignore this warning for now
|
||||
return;
|
||||
default:
|
||||
dbg_msg("gfx", "unhandled warning %d", (int)Warn.m_WarningType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CCommandProcessor_SDL_GL::RunBuffer(CCommandBuffer *pBuffer)
|
||||
{
|
||||
m_pGLBackend->StartCommands(pBuffer->m_CommandCount, pBuffer->m_RenderCallCount);
|
||||
|
||||
for(CCommandBuffer::SCommand *pCommand = pBuffer->Head(); pCommand; pCommand = pCommand->m_pNext)
|
||||
{
|
||||
if(m_pGLBackend->RunCommand(pCommand))
|
||||
auto Res = m_pGLBackend->RunCommand(pCommand);
|
||||
if(Res == ERunCommandReturnTypes::RUN_COMMAND_COMMAND_HANDLED)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if(Res == ERunCommandReturnTypes::RUN_COMMAND_COMMAND_ERROR)
|
||||
{
|
||||
m_Error = m_pGLBackend->GetError();
|
||||
HandleError();
|
||||
return;
|
||||
}
|
||||
else if(Res == ERunCommandReturnTypes::RUN_COMMAND_COMMAND_WARNING)
|
||||
{
|
||||
m_Warning = m_pGLBackend->GetWarning();
|
||||
HandleWarning();
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_SDL.RunCommand(pCommand))
|
||||
continue;
|
||||
|
@ -299,6 +409,21 @@ CCommandProcessor_SDL_GL::~CCommandProcessor_SDL_GL()
|
|||
delete m_pGLBackend;
|
||||
}
|
||||
|
||||
SGFXErrorContainer &CCommandProcessor_SDL_GL::GetError()
|
||||
{
|
||||
return m_Error;
|
||||
}
|
||||
|
||||
void CCommandProcessor_SDL_GL::ErroneousCleanup()
|
||||
{
|
||||
return m_pGLBackend->ErroneousCleanup();
|
||||
}
|
||||
|
||||
SGFXWarningContainer &CCommandProcessor_SDL_GL::GetWarning()
|
||||
{
|
||||
return m_Warning;
|
||||
}
|
||||
|
||||
// ------------ CGraphicsBackend_SDL_GL
|
||||
|
||||
static bool BackendInitGlew(EBackendType BackendType, int &GlewMajor, int &GlewMinor, int &GlewPatch)
|
||||
|
@ -641,6 +766,14 @@ void CGraphicsBackend_SDL_GL::ClampDriverVersion(EBackendType BackendType)
|
|||
}
|
||||
}
|
||||
|
||||
bool CGraphicsBackend_SDL_GL::TryCreateMsgBox(bool AsError, const char *pTitle, const char *pMsg)
|
||||
{
|
||||
m_pProcessor->ErroneousCleanup();
|
||||
SDL_DestroyWindow(m_pWindow);
|
||||
SDL_ShowSimpleMessageBox(AsError ? SDL_MESSAGEBOX_ERROR : SDL_MESSAGEBOX_WARNING, pTitle, pMsg, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CGraphicsBackend_SDL_GL::IsModernAPI(EBackendType BackendType)
|
||||
{
|
||||
if(BackendType == BACKEND_TYPE_OPENGL)
|
||||
|
@ -838,7 +971,8 @@ void CGraphicsBackend_SDL_GL::GetCurrentVideoMode(CVideoMode &CurMode, int HiDPI
|
|||
DisplayToVideoMode(&CurMode, &DPMode, HiDPIScale, DPMode.refresh_rate);
|
||||
}
|
||||
|
||||
CGraphicsBackend_SDL_GL::CGraphicsBackend_SDL_GL()
|
||||
CGraphicsBackend_SDL_GL::CGraphicsBackend_SDL_GL(TTranslateFunc &&TranslateFunc) :
|
||||
CGraphicsBackend_Threaded(std::move(TranslateFunc))
|
||||
{
|
||||
mem_zero(m_aErrorString, std::size(m_aErrorString));
|
||||
}
|
||||
|
@ -1473,4 +1607,4 @@ TGLBackendReadPresentedImageData &CGraphicsBackend_SDL_GL::GetReadPresentedImage
|
|||
return m_ReadPresentedImageDataFunc;
|
||||
}
|
||||
|
||||
IGraphicsBackend *CreateGraphicsBackend() { return new CGraphicsBackend_SDL_GL; }
|
||||
IGraphicsBackend *CreateGraphicsBackend(TTranslateFunc &&TranslateFunc) { return new CGraphicsBackend_SDL_GL(std::move(TranslateFunc)); }
|
||||
|
|
|
@ -5,14 +5,18 @@
|
|||
|
||||
#include <base/detect.h>
|
||||
|
||||
#include "engine/graphics.h"
|
||||
#include "graphics_threaded.h"
|
||||
#include <engine/graphics.h>
|
||||
|
||||
#include <engine/client/graphics_threaded.h>
|
||||
|
||||
#include <engine/client/backend/backend_base.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
#if defined(CONF_PLATFORM_MACOS)
|
||||
#include <objc/objc-runtime.h>
|
||||
|
@ -42,26 +46,55 @@ public:
|
|||
// basic threaded backend, abstract, missing init and shutdown functions
|
||||
class CGraphicsBackend_Threaded : public IGraphicsBackend
|
||||
{
|
||||
private:
|
||||
TTranslateFunc m_TranslateFunc;
|
||||
SGFXWarningContainer m_Warning;
|
||||
|
||||
public:
|
||||
// constructed on the main thread, the rest of the functions is run on the render thread
|
||||
class ICommandProcessor
|
||||
{
|
||||
public:
|
||||
virtual ~ICommandProcessor() {}
|
||||
virtual ~ICommandProcessor() = default;
|
||||
virtual void RunBuffer(CCommandBuffer *pBuffer) = 0;
|
||||
|
||||
virtual SGFXErrorContainer &GetError() = 0;
|
||||
virtual void ErroneousCleanup() = 0;
|
||||
|
||||
virtual SGFXWarningContainer &GetWarning() = 0;
|
||||
|
||||
bool HasError()
|
||||
{
|
||||
return GetError().m_ErrorType != GFX_ERROR_TYPE_NONE;
|
||||
}
|
||||
|
||||
bool HasWarning()
|
||||
{
|
||||
return GetWarning().m_WarningType != GFX_WARNING_TYPE_NONE;
|
||||
}
|
||||
};
|
||||
|
||||
CGraphicsBackend_Threaded();
|
||||
CGraphicsBackend_Threaded(TTranslateFunc &&TranslateFunc);
|
||||
|
||||
void RunBuffer(CCommandBuffer *pBuffer) override;
|
||||
void RunBufferSingleThreadedUnsafe(CCommandBuffer *pBuffer) override;
|
||||
bool IsIdle() const override;
|
||||
void WaitForIdle() override;
|
||||
|
||||
void ProcessError();
|
||||
|
||||
protected:
|
||||
void StartProcessor(ICommandProcessor *pProcessor);
|
||||
void StopProcessor();
|
||||
|
||||
bool HasWarning()
|
||||
{
|
||||
return m_Warning.m_WarningType != GFX_WARNING_TYPE_NONE;
|
||||
}
|
||||
|
||||
// returns true if the error msg was shown
|
||||
virtual bool TryCreateMsgBox(bool AsError, const char *pTitle, const char *pMsg) = 0;
|
||||
|
||||
private:
|
||||
ICommandProcessor *m_pProcessor;
|
||||
std::mutex m_BufferSwapMutex;
|
||||
|
@ -73,6 +106,9 @@ private:
|
|||
void *m_pThread;
|
||||
|
||||
static void ThreadFunc(void *pUser);
|
||||
|
||||
public:
|
||||
bool GetWarning(std::vector<std::string> &WarningStrings) override;
|
||||
};
|
||||
|
||||
// takes care of implementation independent operations
|
||||
|
@ -152,16 +188,27 @@ public:
|
|||
// command processor implementation, uses the fragments to combine into one processor
|
||||
class CCommandProcessor_SDL_GL : public CGraphicsBackend_Threaded::ICommandProcessor
|
||||
{
|
||||
class CCommandProcessorFragment_GLBase *m_pGLBackend;
|
||||
CCommandProcessorFragment_GLBase *m_pGLBackend;
|
||||
CCommandProcessorFragment_SDL m_SDL;
|
||||
CCommandProcessorFragment_General m_General;
|
||||
|
||||
EBackendType m_BackendType;
|
||||
|
||||
SGFXErrorContainer m_Error;
|
||||
SGFXWarningContainer m_Warning;
|
||||
|
||||
public:
|
||||
CCommandProcessor_SDL_GL(EBackendType BackendType, int GLMajor, int GLMinor, int GLPatch);
|
||||
virtual ~CCommandProcessor_SDL_GL();
|
||||
void RunBuffer(CCommandBuffer *pBuffer) override;
|
||||
|
||||
SGFXErrorContainer &GetError() override;
|
||||
void ErroneousCleanup() override;
|
||||
|
||||
SGFXWarningContainer &GetWarning() override;
|
||||
|
||||
void HandleError();
|
||||
void HandleWarning();
|
||||
};
|
||||
|
||||
static constexpr size_t gs_GPUInfoStringSize = 256;
|
||||
|
@ -196,8 +243,11 @@ class CGraphicsBackend_SDL_GL : public CGraphicsBackend_Threaded
|
|||
static EBackendType DetectBackend();
|
||||
static void ClampDriverVersion(EBackendType BackendType);
|
||||
|
||||
protected:
|
||||
bool TryCreateMsgBox(bool AsError, const char *pTitle, const char *pMsg) override;
|
||||
|
||||
public:
|
||||
CGraphicsBackend_SDL_GL();
|
||||
CGraphicsBackend_SDL_GL(TTranslateFunc &&TranslateFunc);
|
||||
int Init(const char *pName, int *pScreen, int *pWidth, int *pHeight, int *pRefreshRate, int *pFsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight, int *pCurrentWidth, int *pCurrentHeight, class IStorage *pStorage) override;
|
||||
int Shutdown() override;
|
||||
|
||||
|
|
|
@ -794,6 +794,17 @@ void CGraphics_Threaded::KickCommandBuffer()
|
|||
{
|
||||
m_pBackend->RunBuffer(m_pCommandBuffer);
|
||||
|
||||
std::vector<std::string> WarningStrings;
|
||||
if(m_pBackend->GetWarning(WarningStrings))
|
||||
{
|
||||
SWarning NewWarning;
|
||||
std::string WarningStr;
|
||||
for(const auto &WarnStr : WarningStrings)
|
||||
WarningStr.append((WarnStr + "\n"));
|
||||
str_copy(NewWarning.m_aWarningMsg, WarningStr.c_str());
|
||||
m_vWarnings.emplace_back(NewWarning);
|
||||
}
|
||||
|
||||
// swap buffer
|
||||
m_CurrentCommandBuffer ^= 1;
|
||||
m_pCommandBuffer = m_apCommandBuffers[m_CurrentCommandBuffer];
|
||||
|
@ -2830,7 +2841,7 @@ int CGraphics_Threaded::Init()
|
|||
m_FirstFreeBufferObjectIndex = -1;
|
||||
m_FirstFreeQuadContainer = -1;
|
||||
|
||||
m_pBackend = CreateGraphicsBackend();
|
||||
m_pBackend = CreateGraphicsBackend(Localize);
|
||||
if(InitWindow() != 0)
|
||||
return -1;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <engine/shared/config.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
constexpr int CMD_BUFFER_DATA_BUFFER_SIZE = 1024 * 1024 * 2;
|
||||
|
@ -714,7 +715,7 @@ public:
|
|||
INITFLAG_DESKTOP_FULLSCREEN = 1 << 5,
|
||||
};
|
||||
|
||||
virtual ~IGraphicsBackend() {}
|
||||
virtual ~IGraphicsBackend() = default;
|
||||
|
||||
virtual int Init(const char *pName, int *pScreen, int *pWidth, int *pHeight, int *pRefreshRate, int *pFsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight, int *pCurrentWidth, int *pCurrentHeight, class IStorage *pStorage) = 0;
|
||||
virtual int Shutdown() = 0;
|
||||
|
@ -770,6 +771,8 @@ public:
|
|||
|
||||
// be aware that this function should only be called from the graphics thread, and even then you should really know what you are doing
|
||||
virtual TGLBackendReadPresentedImageData &GetReadPresentedImageDataFuncUnsafe() = 0;
|
||||
|
||||
virtual bool GetWarning(std::vector<std::string> &WarningStrings) = 0;
|
||||
};
|
||||
|
||||
class CGraphics_Threaded : public IEngineGraphics
|
||||
|
@ -1313,6 +1316,7 @@ public:
|
|||
TGLBackendReadPresentedImageData &GetReadPresentedImageDataFuncUnsafe() override;
|
||||
};
|
||||
|
||||
extern IGraphicsBackend *CreateGraphicsBackend();
|
||||
typedef std::function<const char *(const char *, const char *)> TTranslateFunc;
|
||||
extern IGraphicsBackend *CreateGraphicsBackend(TTranslateFunc &&TranslateFunc);
|
||||
|
||||
#endif // ENGINE_CLIENT_GRAPHICS_THREADED_H
|
||||
|
|
|
@ -1090,7 +1090,11 @@ void CMenus::PopupConfirm(const char *pTitle, const char *pMessage, const char *
|
|||
|
||||
void CMenus::PopupWarning(const char *pTopic, const char *pBody, const char *pButton, std::chrono::nanoseconds Duration)
|
||||
{
|
||||
dbg_msg(pTopic, "%s", pBody);
|
||||
// no multiline support for console
|
||||
std::string BodyStr = pBody;
|
||||
while(BodyStr.find('\n') != std::string::npos)
|
||||
BodyStr.replace(BodyStr.find('\n'), 1, " ");
|
||||
dbg_msg(pTopic, "%s", BodyStr.c_str());
|
||||
|
||||
// reset active item
|
||||
UI()->SetActiveItem(nullptr);
|
||||
|
|
Loading…
Reference in a new issue