From e27e89b57d46a2582183762afcb34aca7f9f0a1b Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 21 May 2017 12:03:12 +0200 Subject: [PATCH 1/6] - Make sure a hung worker thread always crashes the application --- src/swrenderer/drawers/r_thread.cpp | 17 ++++++++++++++++- src/swrenderer/scene/r_scene.cpp | 16 +++++++++++++++- src/win32/i_main.cpp | 7 +++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/swrenderer/drawers/r_thread.cpp b/src/swrenderer/drawers/r_thread.cpp index f6dae7d900..57d86ab9b4 100644 --- a/src/swrenderer/drawers/r_thread.cpp +++ b/src/swrenderer/drawers/r_thread.cpp @@ -33,6 +33,11 @@ #include "r_thread.h" #include "swrenderer/r_memory.h" #include "swrenderer/r_renderthread.h" +#include + +#ifdef WIN32 +void PeekThreadedErrorPane(); +#endif CVAR(Bool, r_multithreaded, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); @@ -73,10 +78,20 @@ void DrawerThreads::Execute(DrawerCommandQueuePtr commands) void DrawerThreads::WaitForWorkers() { + using namespace std::chrono_literals; + // Wait for workers to finish auto queue = Instance(); std::unique_lock end_lock(queue->end_mutex); - queue->end_condition.wait(end_lock, [&]() { return queue->tasks_left == 0; }); + if (!queue->end_condition.wait_for(end_lock, 5s, [&]() { return queue->tasks_left == 0; })) + { +#ifdef WIN32 + PeekThreadedErrorPane(); +#endif + // Invoke the crash reporter so that we can capture the call stack of whatever the hung worker thread is doing + int *threadCrashed = nullptr; + *threadCrashed = 0xdeadbeef; + } end_lock.unlock(); // Clean up diff --git a/src/swrenderer/scene/r_scene.cpp b/src/swrenderer/scene/r_scene.cpp index 5109cb82c7..5948a5c4ab 100644 --- a/src/swrenderer/scene/r_scene.cpp +++ b/src/swrenderer/scene/r_scene.cpp @@ -57,6 +57,11 @@ #include "swrenderer/r_memory.h" #include "swrenderer/r_renderthread.h" #include "swrenderer/things/r_playersprite.h" +#include + +#ifdef WIN32 +void PeekThreadedErrorPane(); +#endif EXTERN_CVAR(Bool, r_shadercolormaps) EXTERN_CVAR(Int, r_clearbuffer) @@ -217,9 +222,18 @@ namespace swrenderer // Wait for everyone to finish: if (Threads.size() > 1) { + using namespace std::chrono_literals; std::unique_lock end_lock(end_mutex); finished_threads++; - end_condition.wait(end_lock, [&]() { return finished_threads == Threads.size(); }); + if (!end_condition.wait_for(end_lock, 5s, [&]() { return finished_threads == Threads.size(); })) + { +#ifdef WIN32 + PeekThreadedErrorPane(); +#endif + // Invoke the crash reporter so that we can capture the call stack of whatever the hung worker thread is doing + int *threadCrashed = nullptr; + *threadCrashed = 0xdeadbeef; + } finished_threads = 0; } diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 4ae1595ef3..d6d2461857 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -821,6 +821,13 @@ void ShowErrorPane(const char *text) } } +void PeekThreadedErrorPane() +{ + // Allow SendMessage from another thread to call its message handler so that it can display the crash dialog + MSG msg; + PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE); +} + //========================================================================== // // DoMain From be2cfddb1701548281202fa5c75148587ba053a4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 21 May 2017 12:05:46 +0200 Subject: [PATCH 2/6] - handle the case where SBARINFO only contains a mugshot definition and fall back to the current statusbarclass if creating an SBARINFO-based statusbar fails. --- src/g_statusbar/sbarinfo.cpp | 3 +-- src/g_statusbar/shared_sbar.cpp | 9 +++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/g_statusbar/sbarinfo.cpp b/src/g_statusbar/sbarinfo.cpp index 1846ecbc69..d048ffc0e4 100644 --- a/src/g_statusbar/sbarinfo.cpp +++ b/src/g_statusbar/sbarinfo.cpp @@ -1576,8 +1576,7 @@ DEFINE_ACTION_FUNCTION(DSBarInfo, GetProtrusion) DBaseStatusBar *CreateCustomStatusBar(int scriptno) { auto script = SBarInfoScript[scriptno]; - if (script == NULL) - I_FatalError("Tried to create a status bar with no script!"); + if (script == nullptr) return nullptr; auto sbar = (DBaseStatusBar*)PClass::FindClass("SBarInfoWrapper")->CreateNew(); auto core = new DSBarInfo(sbar, script); diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index 4b2b1e727b..2710c5156d 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -303,6 +303,15 @@ void ST_CreateStatusBar(bool bTitleLevel) { StatusBar = CreateCustomStatusBar(SCRIPT_DEFAULT); } + // SBARINFO failed so try the current statusbarclass again. + if (StatusBar == nullptr) + { + auto cls = PClass::FindClass(gameinfo.statusbarclass); + if (cls != nullptr) + { + StatusBar = (DBaseStatusBar *)cls->CreateNew(); + } + } } if (StatusBar == nullptr) { From fc0855fac7a26ba37ac9aa0d7e2f573e48bc72df Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 21 May 2017 12:36:34 +0200 Subject: [PATCH 3/6] - fixed size of particles in the hardware renderer. From the look of it the scale was changed in the software renderer several years back but the hardware renderer never got adjusted for it. This also adds a bit of compensation to round particles so that they get rendered a bit larger than square ones. --- src/gl/scene/gl_sprite.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index 629f8acb91..c491bb33e5 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -1185,10 +1185,11 @@ void GLSprite::ProcessParticle (particle_t *particle, sector_t *sector)//, int s y = particle->Pos.Y; z = particle->Pos.Z; - float scalefac=particle->size/4.0f; - // [BB] The smooth particles are smaller than the other ones. Compensate for this here. - if (gl_particles_style==2) - scalefac *= 1.7; + float factor; + if (gl_particles_style == 1) factor = 1.3f / 7.f; + else if (gl_particles_style == 2) factor = 2.5f / 7.f; + else factor = 1 / 7.f; + float scalefac=particle->size * factor; float viewvecX = GLRenderer->mViewVector.X; float viewvecY = GLRenderer->mViewVector.Y; From 7bc5573baabcde11195a95ad819ca9b89ba578d3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 21 May 2017 12:45:49 +0200 Subject: [PATCH 4/6] - call P_FindParticleSubsectors before rendering a save picture in OpenGL. This entry point was the only one missing that call. --- src/gl/scene/gl_scene.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 19c605a5c0..aed9f8f609 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -933,6 +933,7 @@ void GLSceneDrawer::WriteSavePic (player_t *player, FileWriter *file, int width, { GL_IRECT bounds; + P_FindParticleSubsectors(); // make sure that all recently spawned particles have a valid subsector. bounds.left=0; bounds.top=0; bounds.width=width; From 42e62d90053cffd89dd9e7133c92ec0cc8315773 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 21 May 2017 21:30:46 +0200 Subject: [PATCH 5/6] - fixed: Harmony requires special scaling treatment for the fullscreen HUD's icons. --- wadsrc/static/iwadinfo.txt | 6 +- .../static/mapinfo/{hacxharm.txt => hacx.txt} | 0 wadsrc/static/mapinfo/harmony.txt | 8 ++ wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/statusbar/harm_sbar.txt | 108 ++++++++++++++++++ 5 files changed, 120 insertions(+), 3 deletions(-) rename wadsrc/static/mapinfo/{hacxharm.txt => hacx.txt} (100%) create mode 100644 wadsrc/static/mapinfo/harmony.txt create mode 100644 wadsrc/static/zscript/statusbar/harm_sbar.txt diff --git a/wadsrc/static/iwadinfo.txt b/wadsrc/static/iwadinfo.txt index 458e846c36..6dc584a586 100644 --- a/wadsrc/static/iwadinfo.txt +++ b/wadsrc/static/iwadinfo.txt @@ -39,7 +39,7 @@ IWad Autoname = "harmony" Game = "Doom" Config = "Harmony" - Mapinfo = "mapinfo/hacxharm.txt" + Mapinfo = "mapinfo/harmony.txt" MustContain = "MAP01", "0HAWK01", "0CARA3", "0NOSE1" BannerColors = "6e b4 d6", "45 4f 7e" } @@ -50,7 +50,7 @@ IWad Game = "Doom" Config = "Hacx" Autoname = "hacx.hacx2" - Mapinfo = "mapinfo/hacxharm.txt" + Mapinfo = "mapinfo/hacx.txt" MustContain = "MAP01", "HACX-E" BannerColors = "ff ff ff", "00 88 22" } @@ -61,7 +61,7 @@ IWad Game = "Doom" Config = "Hacx" Autoname = "hacx.hacx1" - Mapinfo = "mapinfo/hacxharm.txt" + Mapinfo = "mapinfo/hacx.txt" MustContain = "MAP01", "HACX-R" BannerColors = "00 00 a8", "a8 a8 a8" } diff --git a/wadsrc/static/mapinfo/hacxharm.txt b/wadsrc/static/mapinfo/hacx.txt similarity index 100% rename from wadsrc/static/mapinfo/hacxharm.txt rename to wadsrc/static/mapinfo/hacx.txt diff --git a/wadsrc/static/mapinfo/harmony.txt b/wadsrc/static/mapinfo/harmony.txt new file mode 100644 index 0000000000..b96689c9f6 --- /dev/null +++ b/wadsrc/static/mapinfo/harmony.txt @@ -0,0 +1,8 @@ +include "mapinfo/doom2.txt" + +gameinfo +{ + cursorpic = "cursor" + statusbarclass = "HarmonyStatusBar" +} + diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index d26794f6e7..1cabc49753 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -37,6 +37,7 @@ version "2.5" #include "zscript/statusbar/heretic_sbar.txt" #include "zscript/statusbar/hexen_sbar.txt" #include "zscript/statusbar/strife_sbar.txt" +#include "zscript/statusbar/harm_sbar.txt" #include "zscript/statusbar/sbarinfowrapper.txt" #include "zscript/inventory/inventory.txt" diff --git a/wadsrc/static/zscript/statusbar/harm_sbar.txt b/wadsrc/static/zscript/statusbar/harm_sbar.txt new file mode 100644 index 0000000000..42a30f2fc3 --- /dev/null +++ b/wadsrc/static/zscript/statusbar/harm_sbar.txt @@ -0,0 +1,108 @@ +class HarmonyStatusBar : DoomStatusBar +{ + int scalestate; + + override void Init() + { + Super.Init(); + + // This is for detecting the DECORATEd version of the mod which sets proper scaling for the HUD related textures. + let tex = TexMan.CheckForTexture("MEDIA0", TexMan.Type_Sprite); + if (tex.isValid()) + { + int size = TexMan.GetSize(tex); + Vector2 ssize = TexMan.GetScaledSize(tex); + if (ssize.X ~== size) scalestate = 1; + else scalestate = 0; + } + else scalestate = 1; + } + + override void Draw (int state, double TicFrac) + { + if (!scalestate) + { + Super.Draw(state, TicFrac); + return; + } + + BaseStatusBar.Draw (state, TicFrac); + + if (state == HUD_StatusBar) + { + BeginStatusBar(); + DrawMainBar (TicFrac); + } + else if (state == HUD_Fullscreen) + { + BeginHUD(); + DrawFullScreenStuff (); + } + } + + protected void DrawFullScreenStuff () + { + Vector2 iconbox = (40, 20); + // Draw health + DrawImage("MEDIA0", (20, -2), scale:(0.3, 0.3)); + DrawString(mHUDFont, FormatNumber(CPlayer.health, 3), (44, -20)); + + let armor = CPlayer.mo.FindInventory("BasicArmor"); + if (armor != null && armor.Amount > 0) + { + DrawInventoryIcon(armor, (20, -22), scale:(0.3, 0.3)); + DrawString(mHUDFont, FormatNumber(armor.Amount, 3), (44, -40)); + } + Inventory ammotype1, ammotype2; + [ammotype1, ammotype2] = GetCurrentAmmo(); + int invY = -20; + if (ammotype1 != null) + { + DrawInventoryIcon(ammotype1, (-14, -4), scale:(0.3, 0.3)); + DrawString(mHUDFont, FormatNumber(ammotype1.Amount, 3), (-30, -20), DI_TEXT_ALIGN_RIGHT); + invY -= 20; + } + if (ammotype2 != null && ammotype2 != ammotype1) + { + DrawInventoryIcon(ammotype2, (-14, invY + 17), scale:(0.3, 0.3)); + DrawString(mHUDFont, FormatNumber(ammotype2.Amount, 3), (-30, invY), DI_TEXT_ALIGN_RIGHT); + invY -= 20; + } + if (!isInventoryBarVisible() && !level.NoInventoryBar && CPlayer.mo.InvSel != null) + { + DrawInventoryIcon(CPlayer.mo.InvSel, (-14, invY + 17)); + DrawString(mHUDFont, FormatNumber(CPlayer.mo.InvSel.Amount, 3), (-30, invY), DI_TEXT_ALIGN_RIGHT); + } + if (deathmatch) + { + DrawString(mHUDFont, FormatNumber(CPlayer.FragCount, 3), (-3, 1), DI_TEXT_ALIGN_RIGHT, Font.CR_GOLD); + } + + // Draw the keys. This does not use a special draw function like SBARINFO because the specifics will be different for each mod + // so it's easier to copy or reimplement the following piece of code instead of trying to write a complicated all-encompassing solution. + Vector2 keypos = (-10, 2); + int rowc = 0; + double roww = 0; + for(let i = CPlayer.mo.Inv; i != null; i = i.Inv) + { + if (i is "Key" && i.Icon.IsValid()) + { + DrawTexture(i.Icon, keypos, DI_SCREEN_RIGHT_TOP|DI_ITEM_LEFT_TOP); + Vector2 size = TexMan.GetScaledSize(i.Icon); + keypos.Y += size.Y + 2; + roww = max(roww, size.X); + if (++rowc == 3) + { + keypos.Y = 2; + keypos.X -= roww + 2; + roww = 0; + rowc = 0; + } + } + } + if (isInventoryBarVisible()) + { + DrawInventoryBar(diparms, (0, 0), 7, DI_SCREEN_CENTER_BOTTOM, HX_SHADOW); + } + } +} From bdfc42182f08f2a979fac81ae1aaf5d518c71d54 Mon Sep 17 00:00:00 2001 From: svdijk Date: Sun, 21 May 2017 21:43:48 +0200 Subject: [PATCH 6/6] OPLsynth: Default to center panning. --- src/sound/oplsynth/musicblock.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sound/oplsynth/musicblock.cpp b/src/sound/oplsynth/musicblock.cpp index c2e23b0dc7..daea5ea2d2 100644 --- a/src/sound/oplsynth/musicblock.cpp +++ b/src/sound/oplsynth/musicblock.cpp @@ -36,6 +36,7 @@ musicBlock::musicBlock () { memset (this, 0, sizeof(*this)); + for(auto &oplchannel : oplchannels) oplchannel.Panning = 64; // default to center panning. for(auto &voice : voices) voice.index = ~0u; // mark all free. }