diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ba5c985..44e5fb70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,7 @@ option(WITH_OPENGL_LEGACY "Compile with OpenGL legacy renderer" ON) option(WITH_UART "Compile with libserialport" ON) option(WITH_OPENVR "Compile with OpenVR" ON) option(WITH_ZMQ "Compile with cppzmq" OFF) +option(WITH_CRASHPAD "Compile with crashpad" OFF) option(USE_LTO "Use link-time optimization" OFF) set(SOURCES @@ -206,6 +207,16 @@ else() set_source_files_properties("imgui/imgui_impl_opengl2.cpp" PROPERTIES SKIP_PRECOMPILE_HEADERS TRUE) endif() +if (WITH_CRASHPAD) + add_definitions(-DWITH_CRASHPAD) + set(SOURCES ${SOURCES} "crashreporter.cpp") + if (WIN32) + include_directories("ref/crashpad/include" "ref/crashpad/include/mini_chromium") + else() + include_directories("ref/crashpad/crashpad" "ref/crashpad/crashpad/third_party/mini_chromium/mini_chromium") + endif() +endif() + if (WITH_UART) add_definitions(-DWITH_UART) set(SOURCES ${SOURCES} "uart.cpp") @@ -365,8 +376,20 @@ if (USE_LTO) endif() if (WITH_OPENVR) - include_directories(${OPENVR_INCLUDE_DIR}) - target_link_libraries(${PROJECT_NAME} ${OPENVR_LIBRARY}) + include_directories(${OPENVR_INCLUDE_DIR}) + target_link_libraries(${PROJECT_NAME} ${OPENVR_LIBRARY}) +endif() + +if (WITH_CRASHPAD) + if (WIN32) + target_link_libraries(${PROJECT_NAME} "${CMAKE_SOURCE_DIR}/ref/crashpad/lib_md/base.lib") + target_link_libraries(${PROJECT_NAME} "${CMAKE_SOURCE_DIR}/ref/crashpad/lib_md/client.lib") + target_link_libraries(${PROJECT_NAME} "${CMAKE_SOURCE_DIR}/ref/crashpad/lib_md/util.lib") + else() + target_link_libraries(${PROJECT_NAME} "${CMAKE_SOURCE_DIR}/ref/crashpad/crashpad/out/Default/obj/client/libclient.a") + target_link_libraries(${PROJECT_NAME} "${CMAKE_SOURCE_DIR}/ref/crashpad/crashpad/out/Default/obj/util/libutil.a") + target_link_libraries(${PROJECT_NAME} "${CMAKE_SOURCE_DIR}/ref/crashpad/crashpad/out/Default/obj/third_party/mini_chromium/mini_chromium/base/libbase.a") + endif() endif() find_package(glfw3 REQUIRED) diff --git a/PyInt.cpp b/PyInt.cpp index cd8bd2d4..12b79429 100644 --- a/PyInt.cpp +++ b/PyInt.cpp @@ -147,6 +147,9 @@ void render_task::cancel() { // initializes the module. returns true on success auto python_taskqueue::init() -> bool { + crashreport_add_info("python.threadedupload", Global.python_threadedupload ? "yes" : "no"); + crashreport_add_info("python.uploadmain", Global.python_uploadmain ? "yes" : "no"); + #ifdef _WIN32 if (sizeof(void*) == 8) Py_SetPythonHome("python64"); diff --git a/application.cpp b/application.cpp index 3a4f3c94..96a5e353 100644 --- a/application.cpp +++ b/application.cpp @@ -54,7 +54,6 @@ extern "C" GLFWAPI HWND glfwGetWin32Window( GLFWwindow* window ); } -LONG CALLBACK unhandled_handler( ::EXCEPTION_POINTERS* e ); LRESULT APIENTRY WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); extern HWND Hwnd; extern WNDPROC BaseWindowProc; @@ -105,6 +104,77 @@ void eu07_application::queue_screenshot() m_screenshot_queued = true; } +int eu07_application::run_crashgui() +{ + bool autoup = false; + + while (!glfwWindowShouldClose(m_windows.front())) + { + glfwPollEvents(); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + ui_layer::begin_ui_frame_internal(); + + bool y, n; + + if (Global.asLang == "pl") { + ImGui::Begin(u8"Raportowanie błędów", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoResize); + ImGui::TextUnformatted(u8"Podczas ostatniego uruchomienia symulatora wystąpił błąd.\nWysłać raport o błędzie do deweloperów?\n"); + ImGui::TextUnformatted((u8"Usługa udostępniana przez " + crashreport_get_provider() + "\n").c_str()); + y = ImGui::Button(u8"Tak", ImVec2S(60, 0)); ImGui::SameLine(); + ImGui::Checkbox(u8"W przyszłości przesyłaj raporty o błędach automatycznie", &autoup); + + ImGui::SameLine(); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::TextUnformatted(u8"W celu wyłączenia tej funkcji będzie trzeba skasować plik crashdumps/autoupload_enabled.conf"); + ImGui::EndTooltip(); + } + + ImGui::NewLine(); + n = ImGui::Button(u8"Nie", ImVec2S(60, 0)); + ImGui::End(); + } else { + ImGui::Begin("Crash reporting", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoResize); + ImGui::TextUnformatted("Crash occurred during last launch of the simulator.\nSend crash report to developers?\n"); + ImGui::TextUnformatted(("Service provided by " + crashreport_get_provider() + "\n").c_str()); + y = ImGui::Button("Yes", ImVec2S(60, 0)); ImGui::SameLine(); + ImGui::Checkbox("In future send crash reports automatically", &autoup); + + ImGui::SameLine(); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::TextUnformatted("To disable this feature remove file crashdumps/autoupload_enabled.conf"); + ImGui::EndTooltip(); + } + + ImGui::NewLine(); + n = ImGui::Button("No", ImVec2S(60, 0)); + ImGui::End(); + } + + ui_layer::render_internal(); + glfwSwapBuffers(m_windows.front()); + + if (y) { + crashreport_upload_accept(); + if (autoup) + crashreport_set_autoupload(); + return 0; + } + + if (n) { + crashreport_upload_reject(); + return 0; + } + } + return -1; +} + int eu07_application::init( int Argc, char *Argv[] ) { @@ -119,7 +189,10 @@ eu07_application::init( int Argc, char *Argv[] ) { WriteLog( "Starting MaSzyna rail vehicle simulator (release: " + Global.asVersion + ")" ); WriteLog( "For online documentation and additional files refer to: http://eu07.pl" ); WriteLog( "Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, " - "ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others\n" ); + "ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others" ); + + if (!crashreport_get_provider().empty()) + WriteLog("Crashdump analysis provided by " + crashreport_get_provider() + "\n"); { WriteLog( "// settings" ); @@ -130,22 +203,32 @@ eu07_application::init( int Argc, char *Argv[] ) { WriteLog( "// startup" ); - if( ( result = init_locale() ) != 0 ) { + if( ( result = init_glfw() ) != 0 ) { return result; } - if( ( result = init_glfw() ) != 0 ) { + if( ( result = init_ogl() ) != 0 ) { + return result; + } + if( ( result = init_ui() ) != 0 ) { + return result; + } + if (crashreport_is_pending()) { // run crashgui as early as possible + if ( ( result = run_crashgui() ) != 0 ) + return result; + } + if( ( result = init_locale() ) != 0 ) { return result; } if( ( result = init_gfx() ) != 0 ) { return result; } - init_callbacks(); if( ( result = init_audio() ) != 0 ) { return result; } if( ( result = init_data() ) != 0 ) { return result; } + crashreport_add_info("python_enabled", Global.python_enabled ? "yes" : "no"); if( Global.python_enabled ) { m_taskqueue.init(); } @@ -625,9 +708,6 @@ eu07_application::init_debug() { state = _control87( state & ~( _EM_ZERODIVIDE | _EM_INVALID ), _MCW_EM ); */ #endif -#ifdef _WIN32 - ::SetUnhandledExceptionFilter( unhandled_handler ); -#endif } void @@ -744,6 +824,8 @@ eu07_application::init_glfw() { glfwWindowHint( GLFW_SAMPLES, 1 << Global.iMultisampling ); } + crashreport_add_info("gfxrenderer", Global.GfxRenderer); + if( Global.GfxRenderer == "default" ) { Global.bUseVBO = true; // activate core profile for opengl 3.3 renderer @@ -853,8 +935,7 @@ eu07_application::init_callbacks() { } int -eu07_application::init_gfx() { - +eu07_application::init_ogl() { if (!Global.gfx_usegles) { if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) @@ -872,6 +953,21 @@ eu07_application::init_gfx() { } } + return 0; +} + +int +eu07_application::init_ui() { + if( false == ui_layer::init( m_windows.front() ) ) { + return -1; + } + init_callbacks(); + return 0; +} + +int +eu07_application::init_gfx() { + if( Global.GfxRenderer == "default" ) { // default render path GfxRenderer = gfx_renderer_factory::get_instance()->create("modern"); @@ -890,9 +986,6 @@ eu07_application::init_gfx() { if( false == GfxRenderer->Init( m_windows.front() ) ) { return -1; } - if( false == ui_layer::init( m_windows.front() ) ) { - return -1; - } for (const global_settings::extraviewport_config &conf : Global.extra_viewports) if (!GfxRenderer->AddViewport(conf)) diff --git a/application.h b/application.h index 25f34b15..9c06865e 100644 --- a/application.h +++ b/application.h @@ -103,11 +103,14 @@ private: int init_locale(); int init_glfw(); void init_callbacks(); + int init_ogl(); + int init_ui(); int init_gfx(); int init_audio(); int init_data(); int init_modes(); bool init_network(); + int run_crashgui(); // members bool m_screenshot_queued = false; diff --git a/appveyor.yml b/appveyor.yml index 6e6a4565..772bee08 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,6 +7,12 @@ build_script: git clone "https://github.com/chriskohlhoff/asio" --depth 1 --branch asio-1-16-1 -q + curl -o crashpad86.zip "http://get.backtrace.io/crashpad/builds/release/x86/crashpad-2020-07-01-release-x86-558c9614e3819179f30b92541450f5ac643afce5.zip" + + 7z x crashpad86.zip + + move crashpad-2020-07-01-release-x86-558c9614e3819179f30b92541450f5ac643afce5 crashpad + cd .. mkdir build @@ -17,12 +23,28 @@ build_script: cd x86 - cmake ../.. -T v141_xp + cmake ../.. -T v141_xp -DWITH_CRASHPAD=ON cmake --build . --config RelWithDebInfo cd .. + cd .. + + cd ref + + move crashpad crashpad_ + + curl -o crashpad64.zip "http://get.backtrace.io/crashpad/builds/release/x86-64/crashpad-2020-07-01-release-x64-558c9614e3819179f30b92541450f5ac643afce5.zip" + + 7z x crashpad64.zip + + move crashpad-2020-07-01-release-x64-558c9614e3819179f30b92541450f5ac643afce5 crashpad + + cd .. + + cd build + mkdir x64 cd x64 @@ -35,11 +57,15 @@ build_script: 7z a eu07_x86_bin.zip ./x86/bin/RelWithDebInfo/*.exe - 7z a eu07_x86_pdb.zip ./x86/pdb/RelWithDebInfo/*.pdb - 7z a eu07_x64_bin.zip ./x64/bin/RelWithDebInfo/*.exe - 7z a eu07_x64_pdb.zip ./x64/pdb/RelWithDebInfo/*.pdb + 7z a package86.zip ./x86/pdb/RelWithDebInfo/*.pdb + + 7z a package64.zip ./x64/bin/RelWithDebInfo/*.exe ./x64/pdb/RelWithDebInfo/*.pdb + + curl -Infile "package86.zip" -ContentType "application/octet-stream" -Method Post -uri "https://eu07.sp.backtrace.io:6098/post?format=symbols&token=4eeba9395fae661927e23679fc36f2237416ec056ef75399e894d597ad518c6c" + + curl -Infile "package64.zip" -ContentType "application/octet-stream" -Method Post -uri "https://eu07.sp.backtrace.io:6098/post?format=symbols&token=4eeba9395fae661927e23679fc36f2237416ec056ef75399e894d597ad518c6c" test: off deploy: off artifacts: @@ -50,7 +76,3 @@ artifacts: - path: shaders name: shaders type: zip -- path: build/eu07_x86_pdb.zip - name: symbols_x86 -- path: build/eu07_x64_pdb.zip - name: symbols_x64 diff --git a/audiorenderer.cpp b/audiorenderer.cpp index 9468e471..8723e478 100644 --- a/audiorenderer.cpp +++ b/audiorenderer.cpp @@ -524,8 +524,12 @@ openal_renderer::init_caps() { ::alcGetIntegerv( m_device, ALC_MINOR_VERSION, 1, &versionminor ); auto const oalversion { std::to_string( versionmajor ) + "." + std::to_string( versionminor ) }; + std::string al_renderer((char *)::alcGetString( m_device, ALC_DEVICE_SPECIFIER )); + crashreport_add_info("openal_renderer", al_renderer); + crashreport_add_info("openal_version", oalversion); + WriteLog( - "Audio Renderer: " + std::string { (char *)::alcGetString( m_device, ALC_DEVICE_SPECIFIER ) } + "Audio Renderer: " + al_renderer + " OpenAL Version: " + oalversion ); WriteLog( "Supported extensions: " + std::string{ (char *)::alcGetString( m_device, ALC_EXTENSIONS ) } ); diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8de66042..033f0e29 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -141,13 +141,23 @@ jobs: - script: | cd ref git clone "https://github.com/chriskohlhoff/asio" --depth 1 --branch asio-1-12-2 -q + curl -o crashpad.zip "http://get.backtrace.io/crashpad/builds/release/x86-64/crashpad-2020-07-01-release-x64-558c9614e3819179f30b92541450f5ac643afce5.zip" + unzip crashpad.zip + move crashpad-2020-07-01-release-x64-558c9614e3819179f30b92541450f5ac643afce5 crashpad displayName: 'Download extra dependencies' - script: | mkdir build cd build - cmake .. -A x64 -DUSE_LTO=ON + cmake .. -A x64 -DUSE_LTO=ON -DWITH_CRASHPAD=ON cmake --build . --config RelWithDebInfo displayName: 'Build' + - script: | + cd build + 7z a package.zip .\bin\RelWithDebInfo\*.exe .\pdb\RelWithDebInfo\*.pdb + curl --data-binary @package.zip -H "Expect:" "https://eu07.sp.backtrace.io:6098/post?format=symbols&token=4eeba9395fae661927e23679fc36f2237416ec056ef75399e894d597ad518c6c" + del .\bin\RelWithDebInfo\*.iobj + del .\bin\RelWithDebInfo\*.ipdb + displayName: 'Upload symbols' - task: PublishBuildArtifacts@1 inputs: pathtoPublish: 'build/bin' @@ -178,13 +188,23 @@ jobs: - script: | cd ref git clone "https://github.com/chriskohlhoff/asio" --depth 1 --branch asio-1-12-2 -q + curl -o crashpad.zip "http://get.backtrace.io/crashpad/builds/release/x86/crashpad-2020-07-01-release-x86-558c9614e3819179f30b92541450f5ac643afce5.zip" + unzip crashpad.zip + move crashpad-2020-07-01-release-x86-558c9614e3819179f30b92541450f5ac643afce5 crashpad displayName: 'Download extra dependencies' - script: | mkdir build cd build - cmake .. -A Win32 -T v141_xp -DUSE_LTO=ON + cmake .. -A Win32 -T v141_xp -DUSE_LTO=ON -DWITH_CRASHPAD=ON cmake --build . --config RelWithDebInfo displayName: 'Build' + - script: | + cd build + 7z a package.zip .\pdb\RelWithDebInfo\*.pdb + curl --data-binary @package.zip -H "Expect:" "https://eu07.sp.backtrace.io:6098/post?format=symbols&token=4eeba9395fae661927e23679fc36f2237416ec056ef75399e894d597ad518c6c" + del .\bin\RelWithDebInfo\*.iobj + del .\bin\RelWithDebInfo\*.ipdb + displayName: 'Upload symbols' - task: PublishBuildArtifacts@1 inputs: pathtoPublish: 'build/bin' diff --git a/crashreporter.cpp b/crashreporter.cpp new file mode 100644 index 00000000..e6f6efc4 --- /dev/null +++ b/crashreporter.cpp @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "version_info.h" + +#if defined __has_attribute +# if __has_attribute (init_priority) +# define INITPRIO_CLASS __attribute__ ((init_priority (5000))) +# endif +#endif + +#ifndef INITPRIO_CLASS +# ifdef _MSC_VER +#pragma init_seg(lib) +# endif +#endif + +#ifndef INITPRIO_CLASS +# define INITPRIO_CLASS +#endif + +class crash_reporter +{ + crashpad::CrashpadClient client; + std::unique_ptr database; + +public: + std::string provider = ""; + bool autoupload = false; + + crash_reporter(); + void set_autoupload(); + void upload_reject(); + void upload_accept(); + bool upload_pending(); +}; + +crash_reporter::crash_reporter() +{ +#ifdef _WIN32 + if (!std::filesystem::exists("crashdumps/crashpad_handler.exe")) + return; +#else + if (!std::filesystem::exists("crashdumps/crashpad_handler")) + return; +#endif + + autoupload = std::filesystem::exists("crashdumps/autoupload_enabled.conf"); + + std::string url, token, prov; + + std::ifstream conf("crashdumps/crashpad.conf"); + + std::string line, param, value; + while (std::getline(conf, line)) { + std::istringstream linestream(line); + + if (!std::getline(linestream, param, '=')) + continue; + if (!std::getline(linestream, value, '=')) + continue; + + if (param == "URL") + url = value; + else if (param == "TOKEN") + token = value; + else if (param == "PROVIDER") + prov = value; + } + + if (token.empty()) + return; + if (url.empty()) + return; + if (prov.empty()) + return; + +#ifdef _WIN32 + base::FilePath db(L"crashdumps"); + base::FilePath handler(L"crashdumps/crashpad_handler.exe"); +#else + base::FilePath db("crashdumps"); + base::FilePath handler("crashdumps/crashpad_handler"); +#endif + + std::map annotations; + annotations["git_hash"] = GIT_HASH; + annotations["src_date"] = SRC_DATE; + annotations["format"] = "minidump"; + annotations["token"] = token; + + std::vector arguments; + arguments.push_back("--no-rate-limit"); + + database = crashpad::CrashReportDatabase::Initialize(db); + + if (database == nullptr || database->GetSettings() == NULL) + return; + + std::vector reports; + database->GetCompletedReports(&reports); + for (auto const &report : reports) + if (report.uploaded) + database->DeleteReport(report.uuid); + + database->GetSettings()->SetUploadsEnabled(autoupload); + + if (!client.StartHandler(handler, db, db, url, annotations, arguments, true, true)) + return; + + provider = prov; +} + +void crash_reporter::set_autoupload() +{ + autoupload = true; + database->GetSettings()->SetUploadsEnabled(true); + std::ofstream flag("crashdumps/autoupload_enabled.conf"); + flag << "y" << std::endl; + flag.close(); +} + +void crash_reporter::upload_accept() +{ + std::vector reports; + database->GetCompletedReports(&reports); + for (auto const &report : reports) + if (!report.uploaded) + database->RequestUpload(report.uuid); +} + +void crash_reporter::upload_reject() +{ + std::vector reports; + database->GetCompletedReports(&reports); + for (auto const &report : reports) + if (!report.uploaded) + database->DeleteReport(report.uuid); +} + +bool crash_reporter::upload_pending() +{ + if (autoupload) + return false; + + std::vector reports; + database->GetCompletedReports(&reports); + for (auto const &report : reports) + if (!report.uploaded && !report.upload_explicitly_requested) + return true; + + return false; +} + +crash_reporter crash_reporter_inst INITPRIO_CLASS; + +const std::string& crashreport_get_provider() +{ + return crash_reporter_inst.provider; +} + +void crashreport_add_info(const char *name, const std::string &value) +{ + char *copy = new char[value.size() + 1]; + strcpy(copy, value.c_str()); + + crashpad::Annotation *annotation = new crashpad::Annotation(crashpad::Annotation::Type::kString, name, copy); + annotation->SetSize(value.size() + 1); +} + +void crashreport_set_autoupload() +{ + crash_reporter_inst.set_autoupload(); +} + +bool crashreport_is_pending() +{ + if (crash_reporter_inst.provider.empty()) + return false; + return crash_reporter_inst.upload_pending(); +} + +void crashreport_upload_reject() +{ + crash_reporter_inst.upload_reject(); +} + +void crashreport_upload_accept() +{ + crash_reporter_inst.upload_accept(); +} diff --git a/crashreporter.h b/crashreporter.h new file mode 100644 index 00000000..f7e9461e --- /dev/null +++ b/crashreporter.h @@ -0,0 +1,15 @@ +#ifdef WITH_CRASHPAD +void crashreport_add_info(const char *name, const std::string &value); +const std::string& crashreport_get_provider(); +void crashreport_set_autoupload(); +bool crashreport_is_pending(); +void crashreport_upload_reject(); +void crashreport_upload_accept(); +#else +#define crashreport_add_info(a,b) +#define crashreport_get_provider() (std::string("")) +#define crashreport_set_autoupload() +#define crashreport_is_pending() (false) +#define crashreport_upload_reject() +#define crashreport_upload_accept() +#endif diff --git a/drivermode.cpp b/drivermode.cpp index 3f63266c..9b1ba73a 100644 --- a/drivermode.cpp +++ b/drivermode.cpp @@ -801,7 +801,6 @@ driver_mode::OnKeyDown(int cKey) { switch (cKey) { case GLFW_KEY_F4: { - if( Global.shiftState ) { ExternalView(); } // with Shift, cycle through external views else { InOutKey(); } // without, step out of the cab or return to it break; diff --git a/opengl33renderer.cpp b/opengl33renderer.cpp index b0cf47be..e13915a2 100644 --- a/opengl33renderer.cpp +++ b/opengl33renderer.cpp @@ -171,8 +171,10 @@ bool opengl33_renderer::Init(GLFWwindow *Window) default_viewport.window = m_window; default_viewport.draw_range = 1.0f; - if (Global.vr) + if (Global.vr) { vr = vr_interface_factory::get_instance()->create(Global.vr_backend); + crashreport_add_info("vr_backend", Global.vr_backend); + } if (vr) { glm::ivec2 target_size = vr->get_target_size(); @@ -4637,10 +4639,20 @@ void opengl33_renderer::Update_Lights(light_array &Lights) bool opengl33_renderer::Init_caps() { + std::string gl_renderer((char *)glGetString(GL_RENDERER)); + std::string gl_vendor((char *)glGetString(GL_VENDOR)); + std::string gl_version((char *)glGetString(GL_VERSION)); + + crashreport_add_info("gl_renderer", gl_renderer); + crashreport_add_info("gl_vendor", gl_vendor); + crashreport_add_info("gl_version", gl_version); + crashreport_add_info("gl_use_vao", gl::vao::use_vao ? "yes" : "no"); + crashreport_add_info("gfx.skippipeline", Global.gfx_skippipeline ? "yes" : "no"); + WriteLog("MaSzyna OpenGL Renderer"); - WriteLog("Renderer: " + std::string((char *)glGetString(GL_RENDERER))); - WriteLog("Vendor: " + std::string((char *)glGetString(GL_VENDOR))); - WriteLog("GL version: " + std::string((char *)glGetString(GL_VERSION))); + WriteLog("Renderer: " + gl_renderer); + WriteLog("Vendor: " + gl_vendor); + WriteLog("GL version: " + gl_version); WriteLog("--------"); @@ -4657,6 +4669,8 @@ bool opengl33_renderer::Init_caps() if (!Global.gfx_usegles) { + crashreport_add_info("gl_family", "desktop"); + if (!GLAD_GL_VERSION_3_3) { ErrorLog("requires OpenGL >= 3.3!"); @@ -4683,6 +4697,8 @@ bool opengl33_renderer::Init_caps() } else { + crashreport_add_info("gl_family", "gles"); + if (!GLAD_GL_ES_VERSION_3_0) { ErrorLog("requires OpenGL ES >= 3.0!"); diff --git a/openglrenderer.cpp b/openglrenderer.cpp index 09af4783..a5f5ac95 100644 --- a/openglrenderer.cpp +++ b/openglrenderer.cpp @@ -4336,12 +4336,19 @@ opengl_renderer::Disable_Lights() { bool opengl_renderer::Init_caps() { - std::string oglversion = ( (char *)glGetString( GL_VERSION ) ); + std::string gl_renderer((char *)glGetString(GL_RENDERER)); + std::string gl_vendor((char *)glGetString(GL_VENDOR)); + std::string gl_version((char *)glGetString(GL_VERSION)); + + crashreport_add_info("gl_renderer", gl_renderer); + crashreport_add_info("gl_vendor", gl_vendor); + crashreport_add_info("gl_version", gl_version); + crashreport_add_info("gl_mode", Global.bUseVBO ? "vbo" : "dl"); WriteLog( - "Gfx Renderer: " + std::string( (char *)glGetString( GL_RENDERER ) ) - + " Vendor: " + std::string( (char *)glGetString( GL_VENDOR ) ) - + " OpenGL Version: " + oglversion ); + "Gfx Renderer: " + gl_renderer + + " Vendor: " + gl_vendor + + " OpenGL Version: " + gl_version ); #ifdef EU07_USEIMGUIIMPLOPENGL2 if( !GLAD_GL_VERSION_1_5 ) { diff --git a/simulationstateserializer.cpp b/simulationstateserializer.cpp index 359cb86b..948d8bee 100644 --- a/simulationstateserializer.cpp +++ b/simulationstateserializer.cpp @@ -33,6 +33,8 @@ namespace simulation { std::shared_ptr state_serializer::deserialize_begin( std::string const &Scenariofile ) { + crashreport_add_info("scenario", Scenariofile); + // TODO: move initialization to separate routine so we can reuse it SafeDelete( Region ); Region = new scene::basic_region(); diff --git a/stdafx.h b/stdafx.h index 8b2da436..5eb6d325 100644 --- a/stdafx.h +++ b/stdafx.h @@ -112,4 +112,6 @@ int const null_handle = 0; #include "imgui/imgui.h" #define ImVec2S(a, b) ImVec2(a * Global.ui_scale, b * Global.ui_scale) +#include "crashreporter.h" + #endif diff --git a/translation.cpp b/translation.cpp index 0c708dae..9653c7cd 100644 --- a/translation.cpp +++ b/translation.cpp @@ -26,6 +26,8 @@ void locale::init() return; } + crashreport_add_info("translation", Global.asLang); + while (parse_translation(stream)); WriteLog("translation: " + std::to_string(lang_mapping.size()) + " strings loaded"); diff --git a/uilayer.cpp b/uilayer.cpp index 0f77f016..d677bba1 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -242,12 +242,14 @@ bool ui_layer::init(GLFWwindow *Window) ImGui_ImplGlfw_InitForOpenGL(m_window, false); #ifdef EU07_USEIMGUIIMPLOPENGL2 + crashreport_add_info("imgui_ver", "gl2"); ImGui_ImplOpenGL2_Init(); #else + crashreport_add_info("imgui_ver", "gl3"); if (Global.gfx_usegles) ImGui_ImplOpenGL3_Init("#version 300 es\nprecision highp float;"); else - ImGui_ImplOpenGL3_Init("#version 330 core"); + ImGui_ImplOpenGL3_Init("#version 330 core"); #endif return true; @@ -335,16 +337,26 @@ void ui_layer::render() render_(); gl::buffer::unbind(gl::buffer::ARRAY_BUFFER); + render_internal(); +} + +void ui_layer::render_internal() +{ ImGui::Render(); #ifdef EU07_USEIMGUIIMPLOPENGL2 - ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); + ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); #else - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); #endif } void ui_layer::begin_ui_frame() +{ + begin_ui_frame_internal(); +} + +void ui_layer::begin_ui_frame_internal() { #ifdef EU07_USEIMGUIIMPLOPENGL2 ImGui_ImplOpenGL2_NewFrame(); diff --git a/uilayer.h b/uilayer.h index 004199dd..d481d384 100644 --- a/uilayer.h +++ b/uilayer.h @@ -115,10 +115,14 @@ public: // draws requested UI elements void render(); + static void + render_internal(); // begins new UI frame // (this is separate from render() to allow for debug GUI outside of proper UI framework) void begin_ui_frame(); + static void + begin_ui_frame_internal(); // static void diff --git a/version_info.h.in b/version_info.h.in index 37c59191..e77d0b17 100644 --- a/version_info.h.in +++ b/version_info.h.in @@ -1 +1,3 @@ #define VERSION_INFO "EU07 (cmake), @GIT_HASH@ (committed at @SRC_DATE@)" +#define GIT_HASH "@GIT_HASH@" +#define SRC_DATE "@SRC_DATE@" diff --git a/windows.cpp b/windows.cpp index a6bafa56..a919d848 100644 --- a/windows.cpp +++ b/windows.cpp @@ -3,7 +3,6 @@ #include "utilities.h" #pragma warning (disable: 4091) -#include extern "C" { @@ -11,48 +10,6 @@ __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; } -LONG CALLBACK unhandled_handler(::EXCEPTION_POINTERS* e) -{ - auto hDbgHelp = ::LoadLibraryA("dbghelp"); - if (hDbgHelp == nullptr) - return EXCEPTION_CONTINUE_SEARCH; - auto pMiniDumpWriteDump = (decltype(&MiniDumpWriteDump))::GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); - if (pMiniDumpWriteDump == nullptr) - return EXCEPTION_CONTINUE_SEARCH; - - char name[MAX_PATH]; - { - auto nameEnd = name + ::GetModuleFileNameA(::GetModuleHandleA(0), name, MAX_PATH); - ::SYSTEMTIME t; - ::GetLocalTime(&t); - wsprintfA(nameEnd - strlen(".exe"), - "_crashdump_%4d%02d%02d_%02d%02d%02d.dmp", - t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); - } - - auto hFile = ::CreateFileA(name, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - if (hFile == INVALID_HANDLE_VALUE) - return EXCEPTION_CONTINUE_SEARCH; - - ::MINIDUMP_EXCEPTION_INFORMATION exceptionInfo; - exceptionInfo.ThreadId = ::GetCurrentThreadId(); - exceptionInfo.ExceptionPointers = e; - exceptionInfo.ClientPointers = FALSE; - - auto dumped = pMiniDumpWriteDump( - ::GetCurrentProcess(), - ::GetCurrentProcessId(), - hFile, - ::MINIDUMP_TYPE(::MiniDumpWithIndirectlyReferencedMemory | ::MiniDumpScanMemory), - e ? &exceptionInfo : nullptr, - nullptr, - nullptr); - - ::CloseHandle(hFile); - - return EXCEPTION_CONTINUE_SEARCH; -} - HWND Hwnd; WNDPROC BaseWindowProc; PCOPYDATASTRUCT pDane;