From 0db9d3a27b05dcc66196b0e2df77c257b4f6156d Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sun, 16 Mar 2025 16:11:21 +0000 Subject: [PATCH] [idd] CDebug: implement new debug print class and write to a file --- idd/LGIdd/CD3D11Device.cpp | 2 +- idd/LGIdd/CD3D12CommandQueue.cpp | 2 +- idd/LGIdd/CD3D12Device.cpp | 2 +- idd/LGIdd/CDebug.cpp | 199 ++++++++++++++++++++++++++ idd/LGIdd/{Debug.h => CDebug.h} | 49 ++++++- idd/LGIdd/CFrameBufferResource.cpp | 2 +- idd/LGIdd/CIVSHMEM.cpp | 2 +- idd/LGIdd/CIndirectDeviceContext.cpp | 2 +- idd/LGIdd/CIndirectMonitorContext.cpp | 2 +- idd/LGIdd/CInteropResource.cpp | 3 +- idd/LGIdd/CInteropResourcePool.cpp | 2 +- idd/LGIdd/CPlatformInfo.cpp | 2 +- idd/LGIdd/CSwapChainProcessor.cpp | 4 +- idd/LGIdd/Debug.cpp | 108 -------------- idd/LGIdd/Device.cpp | 2 +- idd/LGIdd/LGIdd.vcxproj | 4 +- idd/LGIdd/LGIdd.vcxproj.filters | 4 +- 17 files changed, 260 insertions(+), 131 deletions(-) create mode 100644 idd/LGIdd/CDebug.cpp rename idd/LGIdd/{Debug.h => CDebug.h} (51%) delete mode 100644 idd/LGIdd/Debug.cpp diff --git a/idd/LGIdd/CD3D11Device.cpp b/idd/LGIdd/CD3D11Device.cpp index e1683743..a4b68c6e 100644 --- a/idd/LGIdd/CD3D11Device.cpp +++ b/idd/LGIdd/CD3D11Device.cpp @@ -19,7 +19,7 @@ */ #include "CD3D11Device.h" -#include "Debug.h" +#include "CDebug.h" HRESULT CD3D11Device::Init() { diff --git a/idd/LGIdd/CD3D12CommandQueue.cpp b/idd/LGIdd/CD3D12CommandQueue.cpp index 53346d67..4f5412fe 100644 --- a/idd/LGIdd/CD3D12CommandQueue.cpp +++ b/idd/LGIdd/CD3D12CommandQueue.cpp @@ -1,5 +1,5 @@ #include "CD3D12CommandQueue.h" -#include "Debug.h" +#include "CDebug.h" bool CD3D12CommandQueue::Init(ID3D12Device3 * device, D3D12_COMMAND_LIST_TYPE type, const WCHAR* name) { diff --git a/idd/LGIdd/CD3D12Device.cpp b/idd/LGIdd/CD3D12Device.cpp index d98b41a8..eb773b09 100644 --- a/idd/LGIdd/CD3D12Device.cpp +++ b/idd/LGIdd/CD3D12Device.cpp @@ -1,5 +1,5 @@ #include "CD3D12Device.h" -#include "Debug.h" +#include "CDebug.h" CD3D12Device::CD3D12Device(LUID adapterLuid) : m_adapterLuid(adapterLuid), diff --git a/idd/LGIdd/CDebug.cpp b/idd/LGIdd/CDebug.cpp new file mode 100644 index 00000000..babe1826 --- /dev/null +++ b/idd/LGIdd/CDebug.cpp @@ -0,0 +1,199 @@ +/** + * Looking Glass + * Copyright © 2017-2025 The Looking Glass Authors + * https://looking-glass.io + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include +#include + +#include "CDebug.h" + +CDebug g_debug; + +CDebug::CDebug() +{ + // don't redirect the debug output if running under a debugger + if (IsDebuggerPresent()) + return; + + // get the system temp directory + char tempPath[MAX_PATH]; + DWORD pathLen = GetTempPathA(sizeof(tempPath), tempPath); + if (pathLen == 0) + { + DBGPRINT_HR(GetLastError(), "Failed to get the temp path"); + return; + } + + std::string folder = tempPath; + std::string baseName = "looking-glass-idd"; + std::string ext = ".txt"; + std::string logFile = folder + baseName + ext; + + + //rotate out old logs + DeleteFileA((folder + baseName + ".5" + ext).c_str()); + for (int i = 4; i >= 0; --i) + { + std::string oldPath; + std::string newPath; + + if (i == 0) + { + oldPath = logFile; + newPath = folder + baseName + ".1" + ext; + } + else + { + oldPath = folder + baseName + "." + std::to_string(i) + ext; + newPath = folder + baseName + "." + std::to_string(i + 1) + ext; + } + + MoveFileA(oldPath.c_str(), newPath.c_str()); + } + + /// open the new log file + std::ofstream stream(logFile, std::ios::out | std::ios::trunc); + if (!stream.is_open()) + { + DBGPRINT_HR(GetLastError(), "Failed to open the log file %s", logFile.c_str()); + return; + } + else + DBGPRINT("Logging to: %s", logFile.c_str()); + + m_stream = std::move(stream); +} + +void CDebug::Log(CDebug::Level level, const char * function, int line, const char * fmt, ...) +{ + if (level < 0 || level >= LEVEL_MAX) + level = LEVEL_NONE; + + static const char* fmtTemplate = "[%s] %40s:%-4d | "; + const char* levelStr = m_levelStr[level]; + + va_list args; + va_start(args, fmt); + + int length = 0; + length = _scprintf(fmtTemplate, levelStr, function, line); + length += _vscprintf(fmt, args); + length += 2; + + /* Depending on the size of the format string, allocate space on the stack or the heap. */ + PCHAR buffer; + buffer = (PCHAR)_malloca(length); + if (!buffer) + { + va_end(args); + return; + } + + /* Populate the buffer with the contents of the format string. */ + StringCbPrintfA(buffer, length, fmtTemplate, levelStr, function, line); + + size_t offset = 0; + StringCbLengthA(buffer, length, &offset); + StringCbVPrintfA(&buffer[offset], length - offset, fmt, args); + va_end(args); + + buffer[length-2] = '\n'; + buffer[length-1] = '\0'; + + Write(buffer); + + _freea(buffer); +} + +void CDebug::LogHR(CDebug::Level level, HRESULT hr, const char * function, int line, const char * fmt, ...) +{ + if (level < 0 || level >= LEVEL_MAX) + level = LEVEL_NONE; + + char * hrBuffer; + if (!FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + hr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (char*)&hrBuffer, + 1024, + NULL + )) + { + DBGPRINT("FormatMessage failed with code 0x%08x", GetLastError()); + return; + } + + // Remove trailing CRLF in hrBuffer + size_t len = strlen(hrBuffer); + while (len && (hrBuffer[len - 1] == '\n' || hrBuffer[len - 1] == '\r')) + hrBuffer[--len] = '\0'; + + static const char* fmtTemplate = "[%s] %40s:%-4d | "; + const char* levelStr = m_levelStr[level]; + + va_list args; + va_start(args, fmt); + + int length = 0; + length = _scprintf(fmtTemplate, levelStr, function, line); + length += _vscprintf(fmt, args); + length += 2 + 4 + (int)strlen(hrBuffer) + 1; + + /* Depending on the size of the format string, allocate space on the stack or the heap. */ + PCHAR buffer; + buffer = (PCHAR)_malloca(length); + if (!buffer) + { + va_end(args); + return; + } + + /* Populate the buffer with the contents of the format string. */ + StringCbPrintfA(buffer, length, fmtTemplate, levelStr, function, line); + + size_t offset = 0; + StringCbLengthA(buffer, length, &offset); + StringCbVPrintfA(&buffer[offset], length - offset, fmt, args); + va_end(args); + + /* append the formatted error */ + StringCbLengthA(buffer, length, &offset); + StringCbPrintfA(&buffer[offset], length - offset, " (%s)\n", hrBuffer); + + Write(buffer); + + _freea(buffer); + LocalFree(hrBuffer); +} + +void CDebug::Write(const char * line) +{ + if (m_stream.is_open()) + { + m_stream << line; + m_stream.flush(); + } + else + OutputDebugStringA(line); +} \ No newline at end of file diff --git a/idd/LGIdd/Debug.h b/idd/LGIdd/CDebug.h similarity index 51% rename from idd/LGIdd/Debug.h rename to idd/LGIdd/CDebug.h index 56d8a919..bf070454 100644 --- a/idd/LGIdd/Debug.h +++ b/idd/LGIdd/CDebug.h @@ -21,12 +21,51 @@ #pragma once #include -#include +#include +#include + +class CDebug +{ + private: + std::ofstream m_stream; + void Write(const char * line); + + public: + CDebug(); + + enum Level + { + LEVEL_NONE = 0, + LEVEL_INFO, + LEVEL_WARN, + LEVEL_ERROR, + LEVEL_TRACE, + LEVEL_FIXME, + LEVEL_FATAL, + + LEVEL_MAX + }; + + void Log(CDebug::Level level, const char * function, int line, const char * fmt, ...); + void LogHR(CDebug::Level level, HRESULT hr, const char* function, int line, const char* fmt, ...); + + private: + const char* m_levelStr[LEVEL_MAX] = + { + " ", + "I", + "W", + "E", + "T", + "!", + "F" + }; +}; + +extern CDebug g_debug; -VOID _DBGPRINT(PCSTR kszFunction, INT iLineNumber, LPCSTR kszDebugFormatString, ...); #define DBGPRINT(kszDebugFormatString, ...) \ - _DBGPRINT(__FUNCTION__, __LINE__, kszDebugFormatString "\n", __VA_ARGS__) + g_debug.Log(CDebug::LEVEL_INFO, __FUNCTION__, __LINE__, kszDebugFormatString, __VA_ARGS__) -VOID _DBGPRINT_HR(PCSTR kwszFunction, INT iLineNumber, LPCSTR kszDebugFormatString, HRESULT status, ...); #define DBGPRINT_HR(status, kszDebugFormatString, ...) \ - _DBGPRINT_HR(__FUNCTION__, __LINE__, kszDebugFormatString "\n", status, __VA_ARGS__) + g_debug.LogHR(CDebug::LEVEL_INFO, status, __FUNCTION__, __LINE__, kszDebugFormatString, __VA_ARGS__) diff --git a/idd/LGIdd/CFrameBufferResource.cpp b/idd/LGIdd/CFrameBufferResource.cpp index 9ab46278..72964dc3 100644 --- a/idd/LGIdd/CFrameBufferResource.cpp +++ b/idd/LGIdd/CFrameBufferResource.cpp @@ -1,6 +1,6 @@ #include "CFrameBufferResource.h" #include "CSwapChainProcessor.h" -#include "Debug.h" +#include "CDebug.h" bool CFrameBufferResource::Init(CSwapChainProcessor * swapChain, uint8_t * base, size_t size) { diff --git a/idd/LGIdd/CIVSHMEM.cpp b/idd/LGIdd/CIVSHMEM.cpp index 34983cb5..85c6b741 100644 --- a/idd/LGIdd/CIVSHMEM.cpp +++ b/idd/LGIdd/CIVSHMEM.cpp @@ -25,7 +25,7 @@ #include #include -#include "Debug.h" +#include "CDebug.h" #include "ivshmem/ivshmem.h" CIVSHMEM::CIVSHMEM() diff --git a/idd/LGIdd/CIndirectDeviceContext.cpp b/idd/LGIdd/CIndirectDeviceContext.cpp index f54ed95a..a792bfae 100644 --- a/idd/LGIdd/CIndirectDeviceContext.cpp +++ b/idd/LGIdd/CIndirectDeviceContext.cpp @@ -22,7 +22,7 @@ #include "CIndirectMonitorContext.h" #include "CPlatformInfo.h" -#include "Debug.h" +#include "CDebug.h" #include diff --git a/idd/LGIdd/CIndirectMonitorContext.cpp b/idd/LGIdd/CIndirectMonitorContext.cpp index 9043ad10..ea2ab4a5 100644 --- a/idd/LGIdd/CIndirectMonitorContext.cpp +++ b/idd/LGIdd/CIndirectMonitorContext.cpp @@ -20,7 +20,7 @@ #include "CIndirectMonitorContext.h" #include "CPlatformInfo.h" -#include "Debug.h" +#include "CDebug.h" CIndirectMonitorContext::CIndirectMonitorContext(_In_ IDDCX_MONITOR monitor, CIndirectDeviceContext * device) : m_monitor(monitor), diff --git a/idd/LGIdd/CInteropResource.cpp b/idd/LGIdd/CInteropResource.cpp index a17d798c..5ea73711 100644 --- a/idd/LGIdd/CInteropResource.cpp +++ b/idd/LGIdd/CInteropResource.cpp @@ -1,6 +1,5 @@ #include "CInteropResource.h" - -#include "Debug.h" +#include "CDebug.h" bool CInteropResource::Init(std::shared_ptr dx11Device, std::shared_ptr dx12Device, ComPtr srcTex) { diff --git a/idd/LGIdd/CInteropResourcePool.cpp b/idd/LGIdd/CInteropResourcePool.cpp index de8a2a33..88924de1 100644 --- a/idd/LGIdd/CInteropResourcePool.cpp +++ b/idd/LGIdd/CInteropResourcePool.cpp @@ -1,5 +1,5 @@ #include "CInteropResourcePool.h" -#include "Debug.h" +#include "CDebug.h" void CInteropResourcePool::Init(std::shared_ptr dx11Device, std::shared_ptr dx12Device) { diff --git a/idd/LGIdd/CPlatformInfo.cpp b/idd/LGIdd/CPlatformInfo.cpp index b3b4fcd8..1a85516f 100644 --- a/idd/LGIdd/CPlatformInfo.cpp +++ b/idd/LGIdd/CPlatformInfo.cpp @@ -20,7 +20,7 @@ #include "CPlatformInfo.h" -#include "Debug.h" +#include "CDebug.h" #include size_t CPlatformInfo::m_pageSize = 0; diff --git a/idd/LGIdd/CSwapChainProcessor.cpp b/idd/LGIdd/CSwapChainProcessor.cpp index eb0b66d4..93b70c1c 100644 --- a/idd/LGIdd/CSwapChainProcessor.cpp +++ b/idd/LGIdd/CSwapChainProcessor.cpp @@ -21,7 +21,7 @@ #include "CSwapChainProcessor.h" #include -#include "Debug.h" +#include "CDebug.h" #define LOCK(lock) \ while (InterlockedCompareExchange((volatile LONG*)&(lock), 1, 0) != 0) {}; @@ -111,7 +111,7 @@ void CSwapChainProcessor::SwapChainThreadCore() hr = IddCxSwapChainSetDevice(m_hSwapChain, &setDevice); if (FAILED(hr)) { - DBGPRINT("IddCxSwapChainSetDevice Failed (%08x)", hr); + DBGPRINT_HR(hr, "IddCxSwapChainSetDevice Failed"); return; } diff --git a/idd/LGIdd/Debug.cpp b/idd/LGIdd/Debug.cpp deleted file mode 100644 index 3b399947..00000000 --- a/idd/LGIdd/Debug.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Looking Glass - * Copyright © 2017-2025 The Looking Glass Authors - * https://looking-glass.io - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include - -#include "Debug.h" - -/* credit: https://stackoverflow.com/questions/29049686/is-there-a-better-way-to-pass-formatted-output-to-outputdebugstring */ -VOID _DBGPRINT(PCSTR kwszFunction, INT iLineNumber, LPCSTR kszDebugFormatString, ...) -{ - INT cbFormatString = 0; - va_list args; - PCHAR szDebugString = NULL; - size_t stOffset = 0; - - va_start(args, kszDebugFormatString); - - cbFormatString = _scprintf("[%s:%d] ", kwszFunction, iLineNumber); - cbFormatString += _vscprintf(kszDebugFormatString, args); - cbFormatString += 2; - - /* Depending on the size of the format string, allocate space on the stack or the heap. */ - szDebugString = (PCHAR)_malloca(cbFormatString); - if (!szDebugString) - return; - - /* Populate the buffer with the contents of the format string. */ - StringCbPrintfA(szDebugString, cbFormatString, "[%s:%d] ", kwszFunction, iLineNumber); - StringCbLengthA(szDebugString, cbFormatString, &stOffset); - StringCbVPrintfA(&szDebugString[stOffset], cbFormatString - stOffset, kszDebugFormatString, args); - - OutputDebugStringA(szDebugString); - - _freea(szDebugString); - va_end(args); -} - -VOID _DBGPRINT_HR(PCSTR kwszFunction, INT iLineNumber, LPCSTR kszDebugFormatString, HRESULT status, ...) -{ - char * buffer; - if (!FormatMessageA( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - status, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (char*)&buffer, - 1024, - NULL - )) - { - DBGPRINT("FormatMessage failed with code 0x%08x", GetLastError()); - return; - } - - INT cbFormatString = 0; - va_list args; - PCHAR szDebugString = NULL; - size_t stOffset = 0; - - va_start(args, kszDebugFormatString); - - cbFormatString = _scprintf("[%s:%d] ", kwszFunction, iLineNumber); - cbFormatString += _vscprintf(kszDebugFormatString, args); - cbFormatString += 2 + 4 + (int)strlen(buffer); - - /* Depending on the size of the format string, allocate space on the stack or the heap. */ - szDebugString = (PCHAR)_malloca(cbFormatString); - if (!szDebugString) - { - va_end(args); - return; - } - - /* Populate the buffer with the contents of the format string. */ - StringCbPrintfA(szDebugString, cbFormatString, "[%s:%d] ", kwszFunction, iLineNumber); - StringCbLengthA(szDebugString, cbFormatString, &stOffset); - StringCbVPrintfA(&szDebugString[stOffset], cbFormatString - stOffset, kszDebugFormatString, args); - - /* append the formatted error */ - StringCbLengthA(szDebugString, cbFormatString, &stOffset); - StringCbPrintfA(&szDebugString[stOffset], cbFormatString - stOffset, " (%s)", buffer); - - OutputDebugStringA(szDebugString); - - _freea(szDebugString); - va_end(args); - - LocalFree(buffer); -} \ No newline at end of file diff --git a/idd/LGIdd/Device.cpp b/idd/LGIdd/Device.cpp index 2f562663..5a404502 100644 --- a/idd/LGIdd/Device.cpp +++ b/idd/LGIdd/Device.cpp @@ -29,7 +29,7 @@ #include #include -#include "Debug.h" +#include "CDebug.h" #include "CIndirectDeviceContext.h" #include "CIndirectMonitorContext.h" diff --git a/idd/LGIdd/LGIdd.vcxproj b/idd/LGIdd/LGIdd.vcxproj index 9862731f..dfea3b3c 100644 --- a/idd/LGIdd/LGIdd.vcxproj +++ b/idd/LGIdd/LGIdd.vcxproj @@ -49,7 +49,7 @@ - + @@ -65,7 +65,7 @@ - + diff --git a/idd/LGIdd/LGIdd.vcxproj.filters b/idd/LGIdd/LGIdd.vcxproj.filters index 37730af6..829f699f 100644 --- a/idd/LGIdd/LGIdd.vcxproj.filters +++ b/idd/LGIdd/LGIdd.vcxproj.filters @@ -51,7 +51,7 @@ Header Files - + Header Files @@ -98,7 +98,7 @@ Source Files - + Source Files