diff --git a/EventsForStackTrace.txt b/EventsForStackTrace.txt new file mode 100644 index 0000000..e09f83e --- /dev/null +++ b/EventsForStackTrace.txt @@ -0,0 +1,2 @@ +CSwitch+PagefaultHard +Profile diff --git a/LibOVR/Include/Extras/OVR_CAPI_Util.h b/LibOVR/Include/Extras/OVR_CAPI_Util.h index ec6b8d5..9c7dafd 100644 --- a/LibOVR/Include/Extras/OVR_CAPI_Util.h +++ b/LibOVR/Include/Extras/OVR_CAPI_Util.h @@ -137,14 +137,14 @@ OVR_PUBLIC_FUNCTION(ovrMatrix4f) ovrMatrix4f_OrthoSubProjection(ovrMatrix4f proj /// Computes offset eye poses based on headPose returned by ovrTrackingState. /// /// \param[in] headPose Indicates the HMD position and orientation to use for the calculation. -/// \param[in] HmdToEyeOffset Can be ovrEyeRenderDesc.HmdToEyeOffset returned from +/// \param[in] hmdToEyeOffset Can be ovrEyeRenderDesc.HmdToEyeOffset returned from /// ovr_GetRenderDesc. For monoscopic rendering, use a vector that is the average /// of the two vectors for both eyes. /// \param[out] outEyePoses If outEyePoses are used for rendering, they should be passed to /// ovr_SubmitFrame in ovrLayerEyeFov::RenderPose or ovrLayerEyeFovDepth::RenderPose. /// OVR_PUBLIC_FUNCTION(void) ovr_CalcEyePoses(ovrPosef headPose, - const ovrVector3f HmdToEyeOffset[2], + const ovrVector3f hmdToEyeOffset[2], ovrPosef outEyePoses[2]); @@ -158,17 +158,17 @@ OVR_PUBLIC_FUNCTION(void) ovr_CalcEyePoses(ovrPosef headPose, /// \param[in] hmd Specifies an ovrSession previously returned by ovr_Create. /// \param[in] frameIndex Specifies the targeted frame index, or 0 to refer to one frame after /// the last time ovr_SubmitFrame was called. -/// \param[in] HmdToEyeOffset Can be ovrEyeRenderDesc.HmdToEyeOffset returned from -/// ovr_GetRenderDesc. For monoscopic rendering, use a vector that is the average -/// of the two vectors for both eyes. /// \param[in] latencyMarker Specifies that this call is the point in time where /// the "App-to-Mid-Photon" latency timer starts from. If a given ovrLayer /// provides "SensorSampleTimestamp", that will override the value stored here. +/// \param[in] hmdToEyeOffset Can be ovrEyeRenderDesc.HmdToEyeOffset returned from +/// ovr_GetRenderDesc. For monoscopic rendering, use a vector that is the average +/// of the two vectors for both eyes. /// \param[out] outEyePoses The predicted eye poses. /// \param[out] outSensorSampleTime The time when this function was called. May be NULL, in which case it is ignored. /// OVR_PUBLIC_FUNCTION(void) ovr_GetEyePoses(ovrSession session, long long frameIndex, ovrBool latencyMarker, - const ovrVector3f HmdToEyeOffset[2], + const ovrVector3f hmdToEyeOffset[2], ovrPosef outEyePoses[2], double* outSensorSampleTime); diff --git a/LibOVR/Include/Extras/OVR_Math.h b/LibOVR/Include/Extras/OVR_Math.h index 5ae570d..c182ed5 100644 --- a/LibOVR/Include/Extras/OVR_Math.h +++ b/LibOVR/Include/Extras/OVR_Math.h @@ -1754,7 +1754,7 @@ public: : Rotation(s.Rotation), Translation(s.Translation) { // Ensure normalized rotation if converting from float to double - if (sizeof(T) > sizeof(Math::OtherFloatType)) + if (sizeof(T) > sizeof(typename Math::OtherFloatType)) Rotation.Normalize(); } diff --git a/LibOVR/Include/OVR_CAPI.h b/LibOVR/Include/OVR_CAPI.h index ec23c35..b1ec3cc 100644 --- a/LibOVR/Include/OVR_CAPI.h +++ b/LibOVR/Include/OVR_CAPI.h @@ -687,6 +687,11 @@ typedef enum ovrTextureMiscFlags_ /// call. This flag requires that RenderTarget binding also be specified. ovrTextureMisc_AllowGenerateMips = 0x0002, + /// Texture swap chain contains protected content, and requires + /// HDCP connection in order to display to HMD. Also prevents + /// mirroring or other redirection of any frame containing this contents + ovrTextureMisc_ProtectedContent = 0x0004, + ovrTextureMisc_EnumSize = 0x7fffffff ///< \internal Force type int32_t. } ovrTextureFlags; @@ -695,7 +700,7 @@ typedef enum ovrTextureMiscFlags_ /// \see ovr_CreateTextureSwapChainDX /// \see ovr_CreateTextureSwapChainGL /// -typedef struct +typedef struct ovrTextureSwapChainDesc_ { ovrTextureType Type; ovrTextureFormat Format; @@ -705,7 +710,7 @@ typedef struct int MipLevels; int SampleCount; ///< Current only supported on depth textures ovrBool StaticImage; ///< Not buffered in a chain. For images that don't change - unsigned int MiscFlags; ///< ovrTextureMiscFlags + unsigned int MiscFlags; ///< ovrTextureFlags unsigned int BindFlags; ///< ovrTextureBindFlags. Not used for GL. } ovrTextureSwapChainDesc; @@ -714,12 +719,12 @@ typedef struct /// \see ovr_CreateMirrorTextureDX /// \see ovr_CreateMirrorTextureGL /// -typedef struct +typedef struct ovrMirrorTextureDesc_ { ovrTextureFormat Format; int Width; int Height; - unsigned int MiscFlags; ///< ovrTextureMiscFlags + unsigned int MiscFlags; ///< ovrTextureFlags } ovrMirrorTextureDesc; typedef struct ovrTextureSwapChainData* ovrTextureSwapChain; @@ -987,8 +992,8 @@ extern "C" { /// Initializes LibOVR /// /// Initialize LibOVR for application usage. This includes finding and loading the LibOVRRT -/// shared library. No LibOVR API functions, other than ovr_GetLastErrorInfo, can be called -/// unless ovr_Initialize succeeds. A successful call to ovr_Initialize must be eventually +/// shared library. No LibOVR API functions, other than ovr_GetLastErrorInfo and ovr_Detect, can +/// be called unless ovr_Initialize succeeds. A successful call to ovr_Initialize must be eventually /// followed by a call to ovr_Shutdown. ovr_Initialize calls are idempotent. /// Calling ovr_Initialize twice does not require two matching calls to ovr_Shutdown. /// If already initialized, the return value is ovr_Success. @@ -1696,6 +1701,14 @@ OVR_PUBLIC_FUNCTION(void) ovr_DestroyMirrorTexture(ovrSession session, ovrMirror /// \param[in] pixelsPerDisplayPixel Specifies the ratio of the number of render target pixels /// to display pixels at the center of distortion. 1.0 is the default value. Lower /// values can improve performance, higher values give improved quality. +/// +/// Example code +/// \code{.cpp} +/// ovrHmdDesc hmdDesc = ovr_GetHmdDesc(session); +/// ovrSizei eyeSizeLeft = ovr_GetFovTextureSize(session, ovrEye_Left, hmdDesc.DefaultEyeFov[ovrEye_Left], 1.0f); +/// ovrSizei eyeSizeRight = ovr_GetFovTextureSize(session, ovrEye_Right, hmdDesc.DefaultEyeFov[ovrEye_Right], 1.0f); +/// \endcode +/// /// \return Returns the texture width and height size. /// OVR_PUBLIC_FUNCTION(ovrSizei) ovr_GetFovTextureSize(ovrSession session, ovrEyeType eye, ovrFovPort fov, diff --git a/LibOVR/Include/OVR_CAPI_D3D.h b/LibOVR/Include/OVR_CAPI_D3D.h index 5c6e94e..50806bc 100644 --- a/LibOVR/Include/OVR_CAPI_D3D.h +++ b/LibOVR/Include/OVR_CAPI_D3D.h @@ -67,8 +67,8 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_CreateTextureSwapChainDX(ovrSession session, /// /// Example code /// \code{.cpp} -/// ovr_GetTextureSwapChainBuffer(session, chain, 0, IID_ID3D11Texture2D, &d3d11Texture); -/// ovr_GetTextureSwapChainBuffer(session, chain, 1, IID_PPV_ARGS(&dxgiResource)); +/// ovr_GetTextureSwapChainBufferDX(session, chain, 0, IID_ID3D11Texture2D, &d3d11Texture); +/// ovr_GetTextureSwapChainBufferDX(session, chain, 1, IID_PPV_ARGS(&dxgiResource)); /// \endcode /// OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainBufferDX(ovrSession session, @@ -102,6 +102,21 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainBufferDX(ovrSession sessio /// compositor continues to treat is as sRGB. Failure to do so will cause the compositor to apply unexpected gamma conversions leading to /// gamma-curve artifacts. /// +/// +/// Example code +/// \code{.cpp} +/// ovrMirrorTexture mirrorTexture = nullptr; +/// ovrMirrorTextureDesc mirrorDesc = {}; +/// mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; +/// mirrorDesc.Width = mirrorWindowWidth; +/// mirrorDesc.Height = mirrorWindowHeight; +/// ovrResult result = ovr_CreateMirrorTextureDX(session, d3d11Device, &mirrorDesc, &mirrorTexture); +/// [...] +/// // Destroy the texture when done with it. +/// ovr_DestroyMirrorTexture(session, mirrorTexture); +/// mirrorTexture = nullptr; +/// \endcode +/// /// \see ovr_GetMirrorTextureBufferDX /// \see ovr_DestroyMirrorTexture /// @@ -120,6 +135,15 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_CreateMirrorTextureDX(ovrSession session, /// \return Returns an ovrResult indicating success or failure. In the case of failure, use /// ovr_GetLastErrorInfo to get more information. /// +/// Example code +/// \code{.cpp} +/// ID3D11Texture2D* d3d11Texture = nullptr; +/// ovr_GetMirrorTextureBufferDX(session, mirrorTexture, IID_PPV_ARGS(&d3d11Texture)); +/// d3d11DeviceContext->CopyResource(d3d11TextureBackBuffer, d3d11Texture); +/// d3d11Texture->Release(); +/// dxgiSwapChain->Present(0, 0); +/// \endcode +/// OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetMirrorTextureBufferDX(ovrSession session, ovrMirrorTexture mirrorTexture, IID iid, diff --git a/LibOVR/Include/OVR_ErrorCode.h b/LibOVR/Include/OVR_ErrorCode.h index b392d49..ed0be0e 100755 --- a/LibOVR/Include/OVR_ErrorCode.h +++ b/LibOVR/Include/OVR_ErrorCode.h @@ -91,6 +91,7 @@ typedef enum ovrErrorType_ ovrError_InvalidHeadsetOrientation = -1011, ///< The headset was in an invalid orientation for the requested operation (e.g. vertically oriented during ovr_RecenterPose). ovrError_ClientSkippedDestroy = -1012, ///< The client failed to call ovr_Destroy on an active session before calling ovr_Shutdown. Or the client crashed. ovrError_ClientSkippedShutdown = -1013, ///< The client failed to call ovr_Shutdown or the client crashed. + ovrError_ServiceDeadlockDetected = -1014, ///< The service watchdog discovered a deadlock. /* Audio error range, reserved for Audio errors. */ ovrError_AudioReservedBegin = -2000, ///< First Audio error. @@ -150,10 +151,17 @@ typedef enum ovrErrorType_ ovrError_BootloaderDeviceDetected = -4102, ///< A bootloader HMD is detected by the service. ovrError_TrackerCalibrationError = -4103, ///< The sensor calibration is missing or incorrect. ovrError_ControllerFirmwareMismatch = -4104, ///< The controller firmware is out of date and is unacceptable. + ovrError_DevManDeviceDetected = -4105, ///< A DeviceManagement mode HMD is detected by the service. + ovrError_RebootedBootloaderDevice = -4106, ///< Had to reboot bootloader device, which succeeded. + ovrError_FailedRebootBootloaderDev = -4107, ///< Had to reboot bootloader device, which failed. Device is stuck in bootloader mode. ovrError_IMUTooManyLostSamples = -4200, ///< Too many lost IMU samples. ovrError_IMURateError = -4201, ///< IMU rate is outside of the expected range. ovrError_FeatureReportFailure = -4202, ///< A feature report has failed. + ovrError_HMDWirelessTimeout = -4203, ///< HMD wireless interface never returned from busy state. + + ovrError_BootloaderAssertLog = -4300, ///< HMD Bootloader Assert Log was not empty. + ovrError_AppAssertLog = -4301, ///< HMD App Assert Log was not empty. /* Synchronization errors */ ovrError_Incomplete = -5000, ///< Requested async work not yet complete. @@ -165,8 +173,10 @@ typedef enum ovrErrorType_ ovrError_TextureSwapChainInvalid = -6002, ///< The ovrTextureSwapChain is in an incomplete or inconsistent state. Ensure ovr_CommitTextureSwapChain was called at least once first. ovrError_GraphicsDeviceReset = -6003, ///< Graphics device has been reset (TDR, etc...) ovrError_DisplayRemoved = -6004, ///< HMD removed from the display adapter - ovrError_ApplicationInvisible = -6005, ///< Application declared itself as an invisible type and is not allowed to submit frames. - ovrError_Disallowed = -6006, ///< The given request is disallowed under the current conditions. + ovrError_ContentProtectionNotAvailable = -6005,/// 1 1 - 3 - 2 + 4 + 0 0 diff --git a/LibOVRKernel/Src/Kernel/OVR_Allocator.cpp b/LibOVRKernel/Src/Kernel/OVR_Allocator.cpp index 9aaf20c..c26beeb 100644 --- a/LibOVRKernel/Src/Kernel/OVR_Allocator.cpp +++ b/LibOVRKernel/Src/Kernel/OVR_Allocator.cpp @@ -25,8 +25,10 @@ limitations under the License. ************************************************************************************/ #include "OVR_Allocator.h" +#ifndef MICRO_OVR #include "OVR_DebugHelp.h" #include "Kernel/OVR_Std.h" +#endif #include #include #include @@ -62,6 +64,11 @@ limitations under the License. #include #include #include + +# if defined(__APPLE__) +# include // malloc_size() +# endif + #endif // This will cause an assertion to trip whenever an allocation occurs outside of our @@ -159,6 +166,7 @@ namespace OVR { bad_alloc::bad_alloc(const char* description) OVR_NOEXCEPT { +#ifndef MICRO_OVR if(description) OVR_strlcpy(Description, description, sizeof(Description)); else @@ -186,6 +194,7 @@ bad_alloc::bad_alloc(const char* description) OVR_NOEXCEPT } OVR_strlcat(Description, addressDescription, sizeof(Description)); +#endif } @@ -400,7 +409,9 @@ void Allocator::SetLeakTracking(bool enabled) if (enabled) { +#ifndef MICRO_OVR SymbolLookup::Initialize(); +#endif } IsLeakTracking = enabled; @@ -451,10 +462,13 @@ static uint32_t PointerHash(const void* p) #define OVR_HASH_MASK (OVR_HASH_SIZE - 1) static TrackedAlloc* AllocHashMap[OVR_HASH_SIZE] = {nullptr}; +#ifndef MICRO_OVR static SymbolLookup Symbols; +#endif void Allocator::trackAlloc(void* p, size_t size) { +#ifndef MICRO_OVR if (!p || !IsLeakTracking) return; @@ -490,6 +504,7 @@ void Allocator::trackAlloc(void* p, size_t size) head->pPrev = tracked; } AllocHashMap[key] = tracked; +#endif } void Allocator::untrackAlloc(void* p) @@ -532,6 +547,7 @@ void Allocator::untrackAlloc(void* p) int Allocator::DumpMemory() { +#ifndef MICRO_OVR const bool symbolLookupWasInitialized = SymbolLookup::IsInitialized(); const bool symbolLookupAvailable = SymbolLookup::Initialize(); @@ -637,11 +653,14 @@ int Allocator::DumpMemory() SymbolLookup::Shutdown(); return reportedLeakCount; +#else + return 0; +#endif } - +#ifndef MICRO_OVR //------------------------------------------------------------------------ // ***** DebugPageAllocator @@ -1244,6 +1263,7 @@ void DebugPageAllocator::FreePageMemory(void* pPageMemory, size_t /*blockSize*/) #endif } +#endif // MICRO_OVR } // namespace OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_DebugHelp.cpp b/LibOVRKernel/Src/Kernel/OVR_DebugHelp.cpp index 475b1ad..bbaea5e 100644 --- a/LibOVRKernel/Src/Kernel/OVR_DebugHelp.cpp +++ b/LibOVRKernel/Src/Kernel/OVR_DebugHelp.cpp @@ -25,6 +25,7 @@ limitations under the License. #include "OVR_UTF8Util.h" #include "OVR_Atomic.h" #include "OVR_SysFile.h" +#include "OVR_Log.h" #include "Util/Util_SystemGUI.h" #include @@ -3540,68 +3541,129 @@ void ExceptionHandler::WriteReport(const char* reportType) WriteReportLine("\nDisplay adapter list\n"); + // helper function to properly init & clear variants + struct VariantHelper + { + VariantHelper() + { + ::VariantInit(&var); // must init before use + } + ~VariantHelper() + { + ::VariantClear(&var); // must clear after use to avoid leaks + } + + const BSTR getBSTR() const // return a value or default empty string + { + if ( ( var.vt == VT_BSTR ) && var.bstrVal ) + return var.bstrVal; + return L""; + } + + uint32_t getLVal() const // return a value or default 0 + { + if ( var.vt == VT_I4 ) + return var.lVal; + return 0; + } + + VARIANT* getVARIANT() // convenience function for passing to Get() + { + return &var; + } + + private : + VARIANT var; + }; + for(unsigned i = 0; SUCCEEDED(hr) && uReturned; i++) { char sString[256]; - VARIANT var; if(i > 0) WriteReportLine("\n"); WriteReportLineF("Info for display adapter %u\n", i); - hr = pObj->Get(L"Name", 0, &var, nullptr, nullptr); - if(SUCCEEDED(hr)) { - WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, sString, sizeof(sString), nullptr, nullptr); - WriteReportLineF("Display Adapter Name: %s\n", sString); + VariantHelper v; + hr = pObj->Get(L"Name", 0, v.getVARIANT(), nullptr, nullptr); + if(SUCCEEDED(hr)) + { + + WideCharToMultiByte(CP_ACP, 0, v.getBSTR(), -1, sString, sizeof(sString), nullptr, nullptr); + WriteReportLineF("Display Adapter Name: %s\n", sString); + } + } + { + VariantHelper v; + hr = pObj->Get(L"AdapterRAM", 0, v.getVARIANT(), nullptr, nullptr); + if(SUCCEEDED(hr)) + { + uint32_t value( v.getLVal() ); + + WriteReportLineF("Display Adapter RAM: %u %s\n", + (value > (1024*1024*1024) ? value/(1024*1024*1024) : value/(1024*1024)), (value > (1024*1024*1024) ? "GiB" : "MiB")); + } + } + { + VariantHelper v; + hr = pObj->Get(L"DeviceID", 0, v.getVARIANT(), nullptr, nullptr); + if(SUCCEEDED(hr)) + { + WideCharToMultiByte(CP_ACP, 0, v.getBSTR(), -1, sString, sizeof(sString), nullptr, nullptr); + WriteReportLineF("Display Adapter DeviceID: %s\n", sString); + } + } + { + VariantHelper v; + hr = pObj->Get(L"DriverVersion", 0, v.getVARIANT(), nullptr, nullptr); + if(SUCCEEDED(hr)) + { + WideCharToMultiByte(CP_ACP, 0, v.getBSTR(), -1, sString, sizeof(sString), nullptr, nullptr); + WriteReportLineF("Display Adapter DriverVersion: %s\n", sString); + } } - hr = pObj->Get(L"AdapterRAM", 0, &var, nullptr, nullptr); - if(SUCCEEDED(hr)) { - WriteReportLineF("Display Adapter RAM: %u %s\n", - ((uint32_t)var.lVal > (1024*1024*1024) ? (uint32_t)var.lVal/(1024*1024*1024) : (uint32_t)var.lVal/(1024*1024)), ((uint32_t)var.lVal > (1024*1024*1024) ? "GiB" : "MiB")); + VariantHelper v; + hr = pObj->Get(L"DriverDate", 0, v.getVARIANT(), nullptr, nullptr); + if(SUCCEEDED(hr)) + { + std::wstring val( v.getBSTR() ); // may return empty string + + while( val.size() < 8 ) // make at least 8 chars long to simplify below code + { + val += L" "; + } + + // http://technet.microsoft.com/en-us/library/ee156576.aspx + wchar_t year[5] = { val[0], val[1], val[2], val[3], 0 }; + wchar_t month[3] = { val[4], val[5], 0 }; + wchar_t monthDay[3] = { val[6], val[7], 0 }; + + WriteReportLineF("Display Adapter DriverDate (US format): %ls/%ls/%ls\n", month, monthDay, year); + } + } + { + VariantHelper v; + // VideoProcessor + hr = pObj->Get(L"VideoProcessor", 0, v.getVARIANT(), nullptr, nullptr); + if(SUCCEEDED(hr)) + { + WideCharToMultiByte(CP_ACP, 0, v.getBSTR(), -1, sString, sizeof(sString), nullptr, nullptr); + WriteReportLineF("Display Adapter VideoProcessor %s\n", sString); + } } - hr = pObj->Get(L"DeviceID", 0, &var, nullptr, nullptr); - if(SUCCEEDED(hr)) { - WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, sString, sizeof(sString), nullptr, nullptr); - WriteReportLineF("Display Adapter DeviceID: %s\n", sString); - } - - hr = pObj->Get(L"DriverVersion", 0, &var, nullptr, nullptr); - if(SUCCEEDED(hr)) - { - WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, sString, sizeof(sString), nullptr, nullptr); - WriteReportLineF("Display Adapter DriverVersion: %s\n", sString); - } - - hr = pObj->Get(L"DriverDate", 0, &var, nullptr, nullptr); - if(SUCCEEDED(hr)) - { - // http://technet.microsoft.com/en-us/library/ee156576.aspx - wchar_t year[5] = { var.bstrVal[0], var.bstrVal[1], var.bstrVal[2], var.bstrVal[3], 0 }; - wchar_t month[3] = { var.bstrVal[4], var.bstrVal[5], 0 }; - wchar_t monthDay[3] = { var.bstrVal[6], var.bstrVal[7], 0 }; - - WriteReportLineF("Display Adapter DriverDate (US format): %ls/%ls/%ls\n", month, monthDay, year); - } - - // VideoProcessor - hr = pObj->Get(L"VideoProcessor", 0, &var, nullptr, nullptr); - if(SUCCEEDED(hr)) - { - WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, sString, sizeof(sString), nullptr, nullptr); - WriteReportLineF("Display Adapter VideoProcessor %s\n", sString); - } - - hr = pObj->Get(L"VideoModeDescription", 0, &var, nullptr, nullptr); - if(SUCCEEDED(hr)) - { - WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, sString, sizeof(sString), nullptr, nullptr); - WriteReportLineF("Display Adapter VideoModeDescription: %s\n", sString); + VariantHelper v; + hr = pObj->Get(L"VideoModeDescription", 0, v.getVARIANT(), nullptr, nullptr); + if(SUCCEEDED(hr)) + { + WideCharToMultiByte(CP_ACP, 0, v.getBSTR(), -1, sString, sizeof(sString), nullptr, nullptr); + WriteReportLineF("Display Adapter VideoModeDescription: %s\n", sString); + } } pObj->Release(); @@ -4270,7 +4332,7 @@ void ExceptionHandler::WriteMiniDump() OVR_ASSERT(false); BOOL result = pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, - (MINIDUMP_TYPE)miniDumpFlags, &minidumpExceptionInfo, + (MINIDUMP_TYPE)miniDumpFlags, pExceptionPointers ? &minidumpExceptionInfo : nullptr, (CONST PMINIDUMP_USER_STREAM_INFORMATION)nullptr, &minidumpCallbackInfo); CloseHandle(hFile); hFile = 0; @@ -4441,20 +4503,14 @@ void ExceptionHandler::ReportDeadlock(const char* threadName, const char* organizationName, const char* applicationName) { + if (!organizationName || !organizationName[0]) + organizationName = "Oculus"; + if (!applicationName || !applicationName[0]) + applicationName = "DefaultApp"; + ExceptionHandler handler; - if (!organizationName || !organizationName[0] || - !applicationName || !applicationName[0]) - { - char tempPath[OVR_MAX_PATH]; - GetCrashDumpDirectory(tempPath, OVR_ARRAY_COUNT(tempPath)); - OVR_strlcat(tempPath, "Deadlock Report (%s).txt", OVR_ARRAY_COUNT(tempPath)); - handler.SetExceptionPaths(tempPath); - } - else - { - handler.SetPathsFromNames(organizationName, applicationName, "Deadlock Report (%s).txt"); - } + handler.SetPathsFromNames(organizationName, applicationName, "Deadlock Report (%s).txt", "Deadlock Minidump (%s).mdmp"); OVR_snprintf(handler.exceptionInfo.exceptionDescription, sizeof(handler.exceptionInfo.exceptionDescription), @@ -4463,6 +4519,7 @@ void ExceptionHandler::ReportDeadlock(const char* threadName, handler.exceptionInfo.timeVal = time(nullptr); handler.exceptionInfo.time = *gmtime(&handler.exceptionInfo.timeVal); handler.WriteReport("Deadlock"); + handler.WriteMiniDump(); } diff --git a/LibOVRKernel/Src/Kernel/OVR_Log.h b/LibOVRKernel/Src/Kernel/OVR_Log.h index 3c49c71..eb84f8e 100644 --- a/LibOVRKernel/Src/Kernel/OVR_Log.h +++ b/LibOVRKernel/Src/Kernel/OVR_Log.h @@ -26,6 +26,28 @@ limitations under the License. #ifndef OVR_Log_h #define OVR_Log_h +#ifdef MICRO_OVR + +namespace OVR { +template void LogText(Args&&...) {} +template void LogError(Args&&...) {} +template void LogDebug(Args&&...) {} +} + +#define OVR_DEBUG_LOG(args) do {} while(0); +#define OVR_DEBUG_LOG_TEXT(args) do {} while(0); +#define OVR_ASSERT_LOG(c, args) do {} while(0) + +namespace ovrlog { + struct Channel{ + templateChannel(Args&&...){} + template void LogTrace(Args&&...){} + template void LogWarningF(Args&&...){} + }; +} + +#else + #include "OVR_Types.h" #include "OVR_Std.h" #include "OVR_String.h" @@ -135,4 +157,6 @@ namespace ovrlog { } // namespace ovrlog +#endif // MICRO_OVR + #endif // OVR_Log_h diff --git a/LibOVRKernel/Src/Kernel/OVR_System.cpp b/LibOVRKernel/Src/Kernel/OVR_System.cpp index 4dbdbb6..86dbf02 100644 --- a/LibOVRKernel/Src/Kernel/OVR_System.cpp +++ b/LibOVRKernel/Src/Kernel/OVR_System.cpp @@ -29,6 +29,7 @@ limitations under the License. #include "OVR_Threads.h" #include "OVR_Timer.h" #include "OVR_DebugHelp.h" +#include "OVR_Log.h" #include #if defined(_MSC_VER) @@ -45,6 +46,7 @@ limitations under the License. namespace OVR { +ovrlog::Channel SystemLog("System"); //----------------------------------------------------------------------------- @@ -131,8 +133,6 @@ void System::Init() if (++System_Init_Count == 1) { - ovrlog::OutputWorker::GetInstance()->Start(); - Timer::initializeTimerSystem(); } else @@ -149,18 +149,24 @@ void System::Destroy() if (--System_Init_Count == 0) { + SystemLog.LogInfo("Graceful shutdown: OnThreadDestroy"); + // Invoke all of the post-finish callbacks (normal case) for (SystemSingletonInternal *listener = SystemShutdownListenerList; listener; listener = listener->NextShutdownSingleton) { listener->OnThreadDestroy(); } + SystemLog.LogInfo("Graceful shutdown: FinishAllThreads"); + #ifdef OVR_ENABLE_THREADS // Wait for all threads to finish; this must be done so that memory // allocator and all destructors finalize correctly. Thread::FinishAllThreads(); #endif + SystemLog.LogInfo("Graceful shutdown: OnSystemDestroy"); + // Invoke all of the post-finish callbacks (normal case) for (SystemSingletonInternal* next, *listener = SystemShutdownListenerList; listener; listener = next) { @@ -172,17 +178,20 @@ void System::Destroy() SystemShutdownListenerList = nullptr; Timer::shutdownTimerSystem(); - - ovrlog::OutputWorker::GetInstance()->Stop(); } else { - OVR_DEBUG_LOG(("[System] Destroy recursively called; depth = %d", System_Init_Count)); + SystemLog.LogDebug("Destroy recursively called; depth = ", System_Init_Count); } GetSSILock().DoLock(); ShuttingDown = false; GetSSILock().Unlock(); + + SystemLog.LogInfo("Graceful shutdown: Stopping logger"); + + // Prevent memory leak reports + ovrlog::ShutdownLogging(); } // Returns 'true' if system was properly initialized. @@ -197,12 +206,9 @@ void System::CheckForAllocatorLeaks() if (Allocator::IsTrackingLeaks()) { int ovrLeakCount = Allocator::DumpMemory(); + (void)ovrLeakCount; OVR_ASSERT(ovrLeakCount == 0); - if (ovrLeakCount == 0) - { - OVR_DEBUG_LOG(("[System] No OVR object leaks detected.")); - } } } diff --git a/LibOVRKernel/Src/Kernel/OVR_System.h b/LibOVRKernel/Src/Kernel/OVR_System.h index 783c278..066714a 100644 --- a/LibOVRKernel/Src/Kernel/OVR_System.h +++ b/LibOVRKernel/Src/Kernel/OVR_System.h @@ -30,7 +30,6 @@ limitations under the License. #define OVR_System_h #include "OVR_Allocator.h" -#include "OVR_Log.h" #include "OVR_Atomic.h" namespace OVR { diff --git a/LibOVRKernel/Src/Util/Util_Watchdog.cpp b/LibOVRKernel/Src/Util/Util_Watchdog.cpp index 073bd25..e5f5d26 100644 --- a/LibOVRKernel/Src/Util/Util_Watchdog.cpp +++ b/LibOVRKernel/Src/Util/Util_Watchdog.cpp @@ -42,7 +42,8 @@ OVR_DEFINE_SINGLETON(OVR::Util::WatchDogObserver); namespace OVR { namespace Util { -const int DefaultThreshhold = 60000; // milliseconds +// Watchdog class default threshold before announcing a long cycle +const int DefaultThreshholdMsec = 60000; // milliseconds //----------------------------------------------------------------------------- @@ -61,21 +62,17 @@ static uint32_t GetFastMsTime() //----------------------------------------------------------------------------- // WatchDogObserver -static bool ExitingOnDeadlock = false; - -bool WatchDogObserver::IsExitingOnDeadlock() -{ - return ExitingOnDeadlock; -} - -void WatchDogObserver::SetExitingOnDeadlock(bool enabled) -{ - ExitingOnDeadlock = enabled; -} +static ovrlog::Channel Logger("Watchdog"); WatchDogObserver::WatchDogObserver() : + ListLock(), + DogList(), IsReporting(false), - Logger("Watchdog") + TerminationEvent(), + DeadlockSeen(false), + AutoTerminateOnDeadlock(true), + ApplicationName(), + OrganizationName() { Start(); @@ -100,72 +97,116 @@ void WatchDogObserver::OnSystemDestroy() Release(); } +void WatchDogObserver::OnDeadlock(const String& deadlockedThreadName) +{ + // If is reporting deadlock details: + if (IsReporting) + { + if (SymbolLookup::Initialize()) + { + // Static to avoid putting 32 KB on the stack. This is only called once, so it's safe. + static SymbolLookup symbolLookup; + String threadListOutput, moduleListOutput; + symbolLookup.ReportThreadCallstacks(threadListOutput); + symbolLookup.ReportModuleInformation(moduleListOutput); + + Logger.LogWarning("---DEADLOCK STATE---\n\n", threadListOutput.ToCStr(), "\n\n", + moduleListOutput.ToCStr(), "\n---END OF DEADLOCK STATE---"); + } + + ExceptionHandler::ReportDeadlock(deadlockedThreadName, OrganizationName, ApplicationName); + } + + // Disable reporting after the first deadlock report. + DeadlockSeen = true; + + Logger.LogError("Deadlock detected in thread '", deadlockedThreadName.ToCStr(), "'"); + + if (AutoTerminateOnDeadlock) + { + Logger.LogError("Waiting ", TerminationDelayMsec, " msec until deadlock termination"); + + if (!TerminationEvent.Wait(TerminationDelayMsec)) + { + ::TerminateProcess(GetCurrentProcess(), 0xd00ddead); + } + + Logger.LogError("Deadlock termination aborted - Graceful shutdown"); + } +} + int WatchDogObserver::Run() { - OVR_DEBUG_LOG(("[WatchDogObserver] Starting")); - SetThreadName("WatchDog"); - while (!TerminationEvent.Wait(WakeupInterval)) + Logger.LogDebug("Starting watchdog thread"); + + // Milliseconds between checks + static const int kWakeupIntervalMsec = 4000; // 4 seconds + + // Number of consecutive long cycles before the watchdog dumps a minidump + static const int kLongCycleTimeLimitMsec = 60000; // 1 minute + static const int kMaxConsecutiveLongCycles = kLongCycleTimeLimitMsec / kWakeupIntervalMsec; + + // By counting consecutive long cycles instead of using a timeout, we prevent false positives + // from debugger breakpoints and sleep/resume of the OS. + int ConsecutiveLongCycles = 0; // Number of long cycles seen in a row + + // While not requested to terminate: + while (!TerminationEvent.Wait(kWakeupIntervalMsec)) { - Lock::Locker locker(&ListLock); + bool sawLongCycle = false; + String deadlockedThreadName; - const uint32_t t1 = GetFastMsTime(); - - const int count = DogList.GetSizeI(); - for (int i = 0; i < count; ++i) { - WatchDog* dog = DogList[i]; + Lock::Locker locker(&ListLock); - const int threshold = dog->ThreshholdMilliseconds; - const uint32_t t0 = dog->WhenLastFedMilliseconds; + const uint32_t t1 = GetFastMsTime(); - // If threshold exceeded, assume there is thread deadlock of some sort. - int delta = (int)(t1 - t0); - if (delta > threshold) + const int count = DogList.GetSizeI(); + for (int i = 0; i < count; ++i) { - // Expected behavior: - // SingleProcessDebug, SingleProcessRelease, Debug: This is only ever done for internal testing, so we don't want it to trigger the deadlock termination. - // Release: This is our release configuration where we want it to terminate itself. + WatchDog* dog = DogList[i]; - // Print a stack trace of all threads if there's no debugger present. - const bool debuggerPresent = OVRIsDebuggerPresent(); + const int threshold = dog->ThreshholdMilliseconds; + const uint32_t t0 = dog->WhenLastFedMilliseconds; - Logger.LogErrorF("Long cycle (possibly deadlock) detected: %s", dog->ThreadName.ToCStr()); + // If threshold exceeded, assume there is thread deadlock of some sort. + int delta = static_cast(t1 - t0); - if (!debuggerPresent) // We don't print threads if a debugger is present because otherwise every time the developer paused the app to debug, it would spit out a long thread trace upon resuming. + // Include an upper bound in case the computer went to sleep + if (delta > threshold && delta < threshold * 3) { - if (SymbolLookup::Initialize()) - { - // symbolLookup is static here to avoid putting 32 KB on the stack - // and potentially overflowing the stack. This function is only ever - // run by one thread so it should be safe. - static SymbolLookup symbolLookup; - String threadListOutput, moduleListOutput; - symbolLookup.ReportThreadCallstacks(threadListOutput); - symbolLookup.ReportModuleInformation(moduleListOutput); - Logger.LogErrorF("---LONG CYCLE STATE---\n\n%s\n\n%s\n---END OF LONG CYCLE STATE---", threadListOutput.ToCStr(), moduleListOutput.ToCStr()); - } + sawLongCycle = true; - if (IsReporting) - { - ExceptionHandler::ReportDeadlock(DogList[i]->ThreadName, OrganizationName , ApplicationName); - - // Disable reporting after the first deadlock report. - IsReporting = false; - } - } - - if (IsExitingOnDeadlock()) - { - OVR_ASSERT_M(false, "Watchdog detected a long cycle (possibly deadlock). Exiting the process."); // This won't have an effect unless asserts are enabled in release builds. - OVR::ExitProcess(-1); + deadlockedThreadName = dog->ThreadName; + Logger.LogWarning("Long cycle detected ", ConsecutiveLongCycles + 1, "x (max=", kMaxConsecutiveLongCycles, ") in thread '", deadlockedThreadName, "'"); } } } + + // If we did not see a long cycle: + if (!sawLongCycle) + { + if (ConsecutiveLongCycles > 0) + { + // Reset log cycle count + ConsecutiveLongCycles = 0; + + Logger.LogWarning("Recovered from long cycles"); + } + + // Reset deadlock seen flag + DeadlockSeen = false; + } + else if (++ConsecutiveLongCycles >= kMaxConsecutiveLongCycles) + { + // Since it requires consecutive long cycles, waking up from sleep/resume will not trigger a deadlock. + OnDeadlock(deadlockedThreadName); + } } - OVR_DEBUG_LOG(("[WatchDogObserver] Good night")); + Logger.LogDebug("Terminating watchdog thread"); return 0; } @@ -216,7 +257,7 @@ void WatchDogObserver::DisableReporting() // WatchDog WatchDog::WatchDog(const String& threadName) : - ThreshholdMilliseconds(DefaultThreshhold), + ThreshholdMilliseconds(DefaultThreshholdMsec), ThreadName(threadName), Listed(false) { diff --git a/LibOVRKernel/Src/Util/Util_Watchdog.h b/LibOVRKernel/Src/Util/Util_Watchdog.h index e89f82b..f684a7d 100644 --- a/LibOVRKernel/Src/Util/Util_Watchdog.h +++ b/LibOVRKernel/Src/Util/Util_Watchdog.h @@ -82,32 +82,47 @@ public: // Disables deadlock reports void DisableReporting(); + // This is the delay between deciding a deadlock occurred and terminating the process, to allow for logging + static const int TerminationDelayMsec = 10000; // 10 seconds in msec + + // Enable/disable auto-terminate on deadlock report + // IsDeadlocked() will return true, and after TerminationDelayMsec it will exit the process + void SetAutoTerminateOnDeadlock(bool enable = true) + { + AutoTerminateOnDeadlock = enable; + } + + // Is currently in a deadlock state? + bool IsDeadlocked() const + { + return DeadlockSeen; + } + protected: Lock ListLock; Array< WatchDog* > DogList; - static const int WakeupInterval = 1000; // milliseconds between checks + // This indicates that EnableReporting() was requested + bool IsReporting = false; + Event TerminationEvent; - // Used in deadlock reporting. - bool IsReporting; + // Has a deadlock been seen? + bool DeadlockSeen = false; + bool AutoTerminateOnDeadlock = true; // On Windows, deadlock logs are stored in %AppData%\OrganizationName\ApplicationName\. // See ExceptionHandler::ReportDeadlock() for how these are used. String ApplicationName; String OrganizationName; - ovrlog::Channel Logger; + void OnDeadlock(const String& deadlockedThreadName); protected: virtual int Run(); void Add(WatchDog* dog); void Remove(WatchDog* dog); - -public: - static bool IsExitingOnDeadlock(); - static void SetExitingOnDeadlock(bool enabled); }; diff --git a/Logging/include/Logging_Library.h b/Logging/include/Logging_Library.h index bc46fbd..9c0081c 100644 --- a/Logging/include/Logging_Library.h +++ b/Logging/include/Logging_Library.h @@ -36,6 +36,7 @@ limitations under the License. #include #include #include +#include #pragma warning(push) @@ -44,10 +45,11 @@ limitations under the License. namespace ovrlog { struct LogStringBuffer; -class OutputWorker; class Channel; class Configurator; +typedef uint32_t Log_Level_t; +typedef uint32_t Write_Option_t; //----------------------------------------------------------------------------- // Log Level @@ -56,7 +58,7 @@ class Configurator; // prominently it is displayed on the console window or whether or not a // message is displayed at all. -enum class Level +enum class Level : Log_Level_t { // Trace message. This is a message that can potentially happen once per @@ -174,6 +176,13 @@ LOGGING_INLINE void LogStringize(LogStringBuffer& buffer, const wchar_t(&first)[ LogStringize(buffer, str); } +template<> +LOGGING_INLINE void LogStringize(LogStringBuffer& buffer, const std::wstring& first) +{ + const wchar_t* str = first.c_str(); + LogStringize(buffer, str); +} + //----------------------------------------------------------------------------- // Log Output Worker Thread @@ -194,13 +203,50 @@ public: virtual void Write(Level level, const char* subsystem, const char* header, const char* utf8msg) = 0; }; + +//----------------------------------------------------------------------------- +// Used by channel to specify how to write +enum class WriteOption : Write_Option_t +{ + // Default log write + Default, + + // Dangerously ignore the queue limit + DangerouslyIgnoreQueueLimit +}; + + +// Iterate through the list of channels before the CRT has initialized +#pragma pack(push,1) +struct ChannelNode { const char* SubsystemName; Log_Level_t* Level; ChannelNode* Next, *Prev; }; +#pragma pack(pop) + +// Export the function to access OutputWorker::Write(). This is used by the Channel class +// to allow writing with OutputWorker possibly in a separate module +extern "C" +{ + __declspec(dllexport) extern void OutputWorkerOutputFunctionC(const char* subsystemName, Log_Level_t messageLogLevel, const char* stream, bool relogged, Write_Option_t option); + typedef void(*OutputWorkerOutputFunctionType)(const char* subsystemName, Log_Level_t messageLogLevel, const char* stream, bool relogged, Write_Option_t option); + + __declspec(dllexport) extern void ConfiguratorOnChannelLevelChangeC(const char* channelName, Log_Level_t minimumOutputLevel); + typedef void(*ConfiguratorOnChannelLevelChangeType)(const char* channelName, Log_Level_t minimumOutputLevel); + + __declspec(dllexport) extern void ConfiguratorRegisterC(ChannelNode* channelNode); + typedef void(*ConfiguratorRegisterType)(ChannelNode* channelNode); + + __declspec(dllexport) extern void ConfiguratorUnregisterC(ChannelNode* channelNode); + typedef void(*ConfiguratorUnregisterType)(ChannelNode* channelNode); +} + +// Shutdown the logging system and release memory +void ShutdownLogging(); + // Log Output Worker Thread class OutputWorker { OutputWorker(); // Use GetInstance() to get the singleton instance. public: - // Get singleton instance for logging output static OutputWorker* GetInstance(); ~OutputWorker(); @@ -214,17 +260,8 @@ public: // Blocks until all log messages before this function call are completed. void Flush(); - enum class WriteOption - { - // Default log write - Default, - - // Dangerously ignore the queue limit - DangerouslyIgnoreQueueLimit - }; - // Write a log buffer to the output - void Write(LogStringBuffer& buffer, WriteOption option = WriteOption::Default); + void Write(const char* subsystemName, Level messageLogLevel, const char* stream, bool relogged, WriteOption option); // Plugin management void AddPlugin(std::shared_ptr plugin); @@ -233,10 +270,16 @@ public: // Disable all output void DisableAllPlugins(); + // Get the lock used for the channels. + Lock* GetChannelsLock(); + private: // Is the logger running in a debugger? bool IsInDebugger; + // It's here so so we know it is valid in the scope of ~OutputWorker + Lock ChannelsLock; + // Plugins Lock PluginsLock; std::set< std::shared_ptr > Plugins; @@ -244,20 +287,14 @@ private: // Worker Log Buffer struct QueuedLogMessage { + QueuedLogMessage(const char* subsystemName, Level messageLogLevel, const char* stream, const SYSTEMTIME& time); + Level MessageLogLevel; const char* SubsystemName; std::string Buffer; + SYSTEMTIME Time; QueuedLogMessage* Next; HANDLE FlushEvent; - - QueuedLogMessage(LogStringBuffer& buffer) - { - MessageLogLevel = buffer.MessageLogLevel; - SubsystemName = buffer.SubsystemName; - Buffer = buffer.Stream.str(); - Next = nullptr; - FlushEvent = nullptr; - } }; // Maximum number of logs that we allow in the queue at a time. @@ -287,14 +324,13 @@ private: WorkQueueTail = msg; ++WorkQueueSize; } - + static DWORD WINAPI WorkerThreadEntrypoint_(void* worker); void WorkerThreadEntrypoint(); Lock StartStopLock; Terminator WorkerTerminator; AutoHandle LoggingThread; - volatile bool LoggingFromWorkerThread; // Append level and subsystem name to timestamp buffer // The buffer should point to the ending null terminator of @@ -304,11 +340,9 @@ private: void ProcessQueuedMessages(); - void FlushMessageImmediately(LogStringBuffer& buffer); - void FlushDbgViewLogImmediately(LogStringBuffer& buffer); + void FlushDbgViewLogImmediately(const char* subsystemName, Level messageLogLevel, const char* stream); }; - //----------------------------------------------------------------------------- // ErrorSilencer // @@ -356,6 +390,7 @@ public: // We recommend that the name string must be a string literal not a string // allocated on the heap at runtime. Channel(const char* nameString); + Channel(const Channel& other); ~Channel(); // Add an extra prefix to all log messages generated by the channel. @@ -372,10 +407,10 @@ public: const char* GetName() const; Level GetMinimumOutputLevel() const; - + LOGGING_INLINE bool Active(Level level) const { - return MinimumOutputLevel <= level; + return MinimumOutputLevel <= (uint32_t)level; } template @@ -529,17 +564,26 @@ public: writeLogBuffer(buffer, Prefix, args...); // Submit buffer to logging subsystem - OutputWorker::GetInstance()->Write(buffer, OutputWorker::WriteOption::DangerouslyIgnoreQueueLimit); + const std::string& tmp = buffer.Stream.str(); + OutputWorkerOutputFunction(buffer.SubsystemName, (Log_Level_t)buffer.MessageLogLevel, tmp.c_str(), buffer.Relogged, (Write_Option_t)WriteOption::DangerouslyIgnoreQueueLimit); } } // DANGER DANGER DANGER - + private: //------------------------------------------------------------------------- // Internal Implementation + Channel() {} + + friend class Configurator; + + // Used to iterate through a linked list of Channel objects + // A linked list is used to avoid CRT new / delete during startup as this is called from the constructor + ChannelNode Node; + // Level at which this channel will log. - Level MinimumOutputLevel; + Log_Level_t MinimumOutputLevel; // Channel name string const char* SubsystemName; @@ -547,6 +591,20 @@ private: // Optional prefix std::string Prefix; + // Target of doLog function + static OutputWorkerOutputFunctionType OutputWorkerOutputFunction; + + // Target of OnChannelLevelChange + static ConfiguratorOnChannelLevelChangeType ConfiguratorOnChannelLevelChange; + + // Target of Register + static ConfiguratorRegisterType ConfiguratorRegister; + + // Target of Unregister + static ConfiguratorUnregisterType ConfiguratorUnregister; + + void GetFunctionPointers(); + template LOGGING_INLINE void writeLogBuffer(LogStringBuffer& buffer, T&& arg) const { @@ -569,7 +627,8 @@ private: writeLogBuffer(buffer, Prefix, args...); // Submit buffer to logging subsystem - OutputWorker::GetInstance()->Write(buffer); + const std::string& tmp = buffer.Stream.str(); + OutputWorkerOutputFunction(buffer.SubsystemName, (Log_Level_t)buffer.MessageLogLevel, tmp.c_str(), buffer.Relogged, (Write_Option_t)WriteOption::Default); } // Returns the buffer capacity required to printf the given format+arguments. @@ -641,7 +700,8 @@ private: writeLogBuffer(buffer, Prefix, logChars); // Submit buffer to logging subsystem - OutputWorker::GetInstance()->Write(buffer); + const std::string& tmp = buffer.Stream.str(); + OutputWorkerOutputFunction(buffer.SubsystemName, (Log_Level_t)buffer.MessageLogLevel, tmp.c_str(), buffer.Relogged, (Write_Option_t)WriteOption::Default); delete[] logCharsAllocated; } @@ -687,18 +747,29 @@ public: void SetPlugin(std::shared_ptr plugin); -private: - void Register(Channel* channel); - void Unregister(Channel* channel); - void OnChannelLevelChange(Channel* channel); + // Free internal memory to avoid memory leak reports + void UnregisterAll(); - // List of registered channels - Lock ChannelsLock; - Level GlobalMinimumLogLevel; - std::set Channels; + // Get all channels - note channels do not necessarily have unique names + void GetChannels(std::vector< std::pair > &channels); + + // Set all channels with channelName to level + void SetChannel(std::string channelName, Level level); + + // Internal: Invoked through callbacks + void OnChannelLevelChange(const char* channelName, Log_Level_t level); + + // Internal: Load log level for a channel from disk + void RestoreChannelLogLevel(const char* channelName); + + // Internal: Iterate through all channels and store them + void RestoreAllChannelLogLevels(); +private: + + uint32_t GlobalMinimumLogLevel; std::shared_ptr Plugin; - void RestoreChannelLogLevel(Channel* channel); + void SetChannelNoLock(std::string channelName, Level level); }; diff --git a/Logging/include/Logging_OutputPlugins.h b/Logging/include/Logging_OutputPlugins.h index 934283b..3c631e5 100644 --- a/Logging/include/Logging_OutputPlugins.h +++ b/Logging/include/Logging_OutputPlugins.h @@ -84,6 +84,7 @@ public: private: // Event source handle initialized in constructor and used for logging HANDLE hEventSource; + Level MinReportEventLevel; virtual const char* GetUniquePluginName() override; virtual void Write(Level level, const char* subsystem, const char* header, const char* utf8msg) override; diff --git a/Logging/src/Logging_Library.cpp b/Logging/src/Logging_Library.cpp index 5b58ecb..da0b7a4 100644 --- a/Logging/src/Logging_Library.cpp +++ b/Logging/src/Logging_Library.cpp @@ -37,6 +37,106 @@ limitations under the License. namespace ovrlog { +//----------------------------------------------------------------------------- +// Channel + +OutputWorkerOutputFunctionType Channel::OutputWorkerOutputFunction; +ConfiguratorOnChannelLevelChangeType Channel::ConfiguratorOnChannelLevelChange; +ConfiguratorRegisterType Channel::ConfiguratorRegister; +ConfiguratorUnregisterType Channel::ConfiguratorUnregister; + +// Don't use locks or register channels until OutputWorker::Start has been called +// Once called the first time, register all known channels and start using locks +static volatile bool OutputWorkerInstValid = false; +static ChannelNode* ChannelNodeHead = nullptr; +void ChannelRegisterNoLock(ChannelNode* channelNode) +{ + if (ChannelNodeHead) + { + ChannelNodeHead->Prev = channelNode; + channelNode->Next = ChannelNodeHead; + channelNode->Prev = nullptr; + ChannelNodeHead = channelNode; + } + else + { + ChannelNodeHead = channelNode; + channelNode->Next = nullptr; + channelNode->Prev = nullptr; + } +} + +void ChannelRegister(ChannelNode* channelNode) +{ + Locker locker(OutputWorker::GetInstance()->GetChannelsLock()); + ChannelRegisterNoLock(channelNode); + Configurator::GetInstance()->RestoreChannelLogLevel(channelNode->SubsystemName); +} + +void ChannelUnregisterNoLock(ChannelNode* channelNode) +{ + if (channelNode == ChannelNodeHead) + { + ChannelNodeHead = channelNode->Next; + if (ChannelNodeHead) + { + ChannelNodeHead->Prev = nullptr; + } + } + else + { + channelNode->Prev->Next = channelNode->Next; + if (channelNode->Next) + { + channelNode->Next->Prev = channelNode->Prev; + } + } +} + +void ChannelUnregister(ChannelNode* channelNode) +{ + Locker locker(OutputWorker::GetInstance()->GetChannelsLock()); + + ChannelUnregisterNoLock(channelNode); +} + +// Export Write(), and three configurator functions so that Channel has access to it automatically across DLL boundaries +// These functions are looked up using GetProcAddress(GetModuleHandle(NULL), "FunctionName"); +extern "C" +{ + void OutputWorkerOutputFunctionC(const char* subsystemName, Log_Level_t messageLogLevel, const char* stream, bool relogged, Write_Option_t option) + { + OutputWorker::GetInstance()->Write(subsystemName, (Level)messageLogLevel, stream, relogged, (WriteOption)option); + } + + void ConfiguratorOnChannelLevelChangeC(const char* channelName, Log_Level_t level) + { + Configurator::GetInstance()->OnChannelLevelChange(channelName, level); + } + + void ConfiguratorRegisterC(ChannelNode* channelNode) + { + if (OutputWorkerInstValid == false) + ChannelRegisterNoLock(channelNode); + else + ChannelRegister(channelNode); + } + + void ConfiguratorUnregisterC(ChannelNode* channelNode) + { + if (OutputWorkerInstValid == false) + ChannelUnregisterNoLock(channelNode); + else + ChannelUnregister(channelNode); + } +} + +//----------------------------------------------------------------------------- +// Shutdown the logging system and release memory +void ShutdownLogging() +{ + ovrlog::OutputWorker::GetInstance()->Stop(); +} //----------------------------------------------------------------------------- // Log Output Worker Thread @@ -53,12 +153,8 @@ OutputWorker::OutputWorker() : Plugins(), WorkerWakeEvent(), WorkQueueLock(), - WorkQueueHead(nullptr), - WorkQueueTail(nullptr), - WorkQueueSize(0), WorkQueueOverrun(0), StartStopLock(), - LoggingFromWorkerThread(false), WorkerTerminator(), LoggingThread() { @@ -69,30 +165,15 @@ OutputWorker::OutputWorker() : InstallDefaultOutputPlugins(); - Start(); + OutputWorkerInstValid = true; - if (IsInDebugger) - { - LogStringBuffer buffer("Logging", Level::Warning); - buffer.Stream << "Running from a debugger. Most log output will be written from a background thread. Only DbgView (MSVC Output Window) logs will be flushed immediately."; - Write(buffer); - } + Start(); } OutputWorker::~OutputWorker() { - // If we were not already explicitly shutdown, - if (LoggingThread.IsValid()) - { - // Error in user code: - // Before ending your main() function be sure to call - // ovrlog::OutputWorker::GetInstance()->Stop(); - // This allows the logging subsystem to finish writing before closing, - // as otherwise the log will be truncated and data will be lost. - LOGGING_DEBUG_BREAK(); - } - Stop(); + OutputWorkerInstValid = false; } void OutputWorker::InstallDefaultOutputPlugins() @@ -166,6 +247,11 @@ void OutputWorker::DisableAllPlugins() Plugins.clear(); } +Lock* OutputWorker::GetChannelsLock() +{ + return &ChannelsLock; +} + void OutputWorker::Start() { // Hold start-stop lock to prevent Start() and Stop() from being called at the same time. @@ -177,6 +263,8 @@ void OutputWorker::Start() return; // Nothing to do! } + Configurator::GetInstance()->RestoreAllChannelLogLevels(); + if (!WorkerTerminator.Initialize()) { // Unable to create worker terminator event? @@ -198,15 +286,6 @@ void OutputWorker::Start() LOGGING_DEBUG_BREAK(); return; } - - // Scoped work queue lock: - { - // Set the flag to indicate the background thread should be used for log output. - // Log messages that happen before this point will flush immediately and not get - // lost so there is no race condition danger here. - Locker workQueueLock(WorkQueueLock); - LoggingFromWorkerThread = true; - } } void OutputWorker::Stop() @@ -233,33 +312,104 @@ void OutputWorker::Stop() // can use the flag to check if a flush has already occurred. Locker workQueueLock(WorkQueueLock); - // Set the flag here with the lock held as a sync point for calls into the logger. - LoggingFromWorkerThread = false; - // Finish the last set of queued messages to avoid losing any before Stop() returns. ProcessQueuedMessages(); } } +static int GetTimestamp(char* buffer, int bufferBytes, SYSTEMTIME time) +{ + // GetDateFormat and GetTimeFormat returns the number of characters written to the + // buffer if successful, including the trailing '\0'; and return 0 on failure. + char dateBuffer[16]; + int dateBufferLength; + int writtenChars = ::GetDateFormatA(LOCALE_USER_DEFAULT, 0, &time, "dd/MM ", dateBuffer, sizeof(dateBuffer)); + + if (writtenChars <= 0) + { + // Failure + buffer[0] = '\0'; + return 0; + } + dateBufferLength = (writtenChars - 1); + + char timeBuffer[32]; + int timeBufferLength; + writtenChars = ::GetTimeFormatA( // Intentionally using 'A' version. + LOCALE_USER_DEFAULT, // User locale + 0, // Default flags + &time, // Time + "HH:mm:ss", + timeBuffer, // Output buffer + sizeof(timeBuffer)); // Size of buffer in tchars + + if (writtenChars <= 0) + { + // Failure + buffer[0] = '\0'; + return 0; + } + timeBufferLength = (writtenChars - 1); + + // Append milliseconds + const char msBuffer[5] = + { + (char)('.'), + (char)(((time.wMilliseconds / 100) % 10) + '0'), + (char)(((time.wMilliseconds / 10) % 10) + '0'), + (char)((time.wMilliseconds % 10) + '0'), + (char)('\0') + }; + + const int writeSum = (dateBufferLength + timeBufferLength + sizeof(msBuffer)); + + if (bufferBytes < writeSum) + { + buffer[0] = '\0'; + return 0; + } + +#pragma warning(push) // We are guaranteed that strcpy is safe. +#pragma warning(disable: 4996) //'strcpy': This function or variable may be unsafe. + strcpy(buffer, dateBuffer); + strcpy(buffer + dateBufferLength, timeBuffer); + strcpy(buffer + dateBufferLength + timeBufferLength, msBuffer); +#pragma warning(pop) + + return (writeSum - 1); // -1 because we return the strlen of buffer, and don't include the trailing '\0'. +} + +// Returns number of bytes written to buffer +// Precondition: Buffer is large enough to hold everything, +// so don't bother complaining there isn't enough length checking. +static int GetTimestamp(char* buffer, int bufferBytes) +{ + // Get timestamp string + SYSTEMTIME time; + ::GetLocalTime(&time); + return GetTimestamp(buffer, bufferBytes, time); +} + void OutputWorker::Flush() { + if (!LoggingThread.IsValid()) + { + LOGGING_DEBUG_BREAK(); // Must be called between Start() and Stop() + return; + } + AutoHandle flushEvent; // Scoped work queue lock: { Locker workQueueLock(WorkQueueLock); - // If we are already flushing immediately, - if (!LoggingFromWorkerThread) - { - // Flush function does nothing in this case. - return; - } - // Generate a flush event flushEvent = ::CreateEventW(nullptr, FALSE, FALSE, nullptr); LogStringBuffer buffer("Logging", ovrlog::Level::Info); - QueuedLogMessage* queuedBuffer = new QueuedLogMessage(buffer); + SYSTEMTIME time; + ::GetLocalTime(&time); + QueuedLogMessage* queuedBuffer = new QueuedLogMessage("Logging", ovrlog::Level::Info, "", time); queuedBuffer->FlushEvent = flushEvent.Get(); // Add queued buffer to the end of the work queue @@ -275,38 +425,6 @@ void OutputWorker::Flush() ::WaitForSingleObject(flushEvent.Get(), INFINITE); } -// Returns number of bytes written to buffer -// Precondition: Buffer is large enough to hold everything, -// so don't bother complaining there isn't enough length checking. -static int GetTimestamp(char* buffer, int bufferBytes) -{ - // Get timestamp string - SYSTEMTIME time; - ::GetLocalTime(&time); - int writtenChars = ::GetTimeFormatA( // Intentionally using 'A' version. - LOCALE_USER_DEFAULT, // User locale - 0, // Default flags - &time, // Time - "HH:mm:ss", // No format string - buffer, // Output buffer - bufferBytes); // Size of buffer in tchars - - if (writtenChars <= 0) - { - // Failure - buffer[0] = '\0'; - return 0; - } - - // Append milliseconds - buffer[writtenChars - 1] = '.'; - buffer[writtenChars] = ((time.wMilliseconds / 100) % 10) + '0'; - buffer[writtenChars + 1] = ((time.wMilliseconds / 10) % 10) + '0'; - buffer[writtenChars + 2] = (time.wMilliseconds % 10) + '0'; - - return writtenChars + 3; -} - static void WriteAdvanceStrCpy(char*& buffer, size_t& bufferBytes, const char* str) { // Get length of string to copy into buffer @@ -385,24 +503,19 @@ void OutputWorker::ProcessQueuedMessages() return; } - // Get timestamp string - int timestampLength = GetTimestamp(HeaderBuffer, TempBufferBytes); - if (timestampLength <= 0) - { - LOGGING_DEBUG_BREAK(); return; // Maybe bug in timestamp code? - } - // Log output format: // TIMESTAMP [SubSystem] Message // If some messages were lost, if (lostCount > 0) { - LogStringBuffer buffer("Logging", Level::Error); - buffer.Stream << "Lost " << lostCount << " log messages due to queue overrun; try to reduce the amount of logging"; + char str[255]; + sprintf_s(str, sizeof(str), "Lost %i log messages due to queue overrun; try to reduce the amount of logging", lostCount); // Insert at the front of the list - QueuedLogMessage* queuedMsg = new QueuedLogMessage(buffer); + SYSTEMTIME time; + ::GetLocalTime(&time); + QueuedLogMessage* queuedMsg = new QueuedLogMessage("Logging", Level::Error, str, time); queuedMsg->Next = message; message = queuedMsg; } @@ -421,6 +534,8 @@ void OutputWorker::ProcessQueuedMessages() } else { + std::size_t timestampLength = GetTimestamp(HeaderBuffer, sizeof(HeaderBuffer), message->Time); + // Construct header on top of timestamp buffer AppendHeader(HeaderBuffer + timestampLength, sizeof(HeaderBuffer) - timestampLength, message->MessageLogLevel, message->SubsystemName); @@ -442,7 +557,7 @@ void OutputWorker::ProcessQueuedMessages() } } -void OutputWorker::FlushMessageImmediately(LogStringBuffer& buffer) +void OutputWorker::FlushDbgViewLogImmediately(const char* subsystemName, Level messageLogLevel, const char* stream) { static const int TempBufferBytes = 1024; // 1 KiB char HeaderBuffer[TempBufferBytes]; @@ -456,45 +571,12 @@ void OutputWorker::FlushMessageImmediately(LogStringBuffer& buffer) // Construct log header on top of timestamp buffer AppendHeader(HeaderBuffer + timestampLength, sizeof(HeaderBuffer) - timestampLength, - buffer.MessageLogLevel, buffer.SubsystemName); - - std::string messageString = buffer.Stream.str(); - - { - Locker locker(PluginsLock); - - // For each plugin, - for (auto& plugin : Plugins) - { - plugin->Write( - buffer.MessageLogLevel, - buffer.SubsystemName, - HeaderBuffer, - messageString.c_str()); - } - } -} - -void OutputWorker::FlushDbgViewLogImmediately(LogStringBuffer& buffer) -{ - static const int TempBufferBytes = 1024; // 1 KiB - char HeaderBuffer[TempBufferBytes]; - - // Get timestamp string - int timestampLength = GetTimestamp(HeaderBuffer, TempBufferBytes); - if (timestampLength <= 0) - { - LOGGING_DEBUG_BREAK(); return; // Maybe bug in timestamp code? - } - - // Construct log header on top of timestamp buffer - AppendHeader(HeaderBuffer + timestampLength, sizeof(HeaderBuffer) - timestampLength, - buffer.MessageLogLevel, buffer.SubsystemName); + messageLogLevel, subsystemName); // Build up a single string to send to OutputDebugStringA so it // all appears on the same line in DbgView. std::stringstream ss; - ss << HeaderBuffer << buffer.Stream.str() << "\n"; + ss << HeaderBuffer << stream << "\n"; ::OutputDebugStringA(ss.str().c_str()); } @@ -513,16 +595,8 @@ void OutputWorker::WorkerThreadEntrypoint() } } -void OutputWorker::Write(LogStringBuffer& buffer, WriteOption option) +void OutputWorker::Write(const char* subsystemName, Level messageLogLevel, const char* stream, bool relogged, WriteOption option) { - // If not logging from the worker thread, - if (!LoggingFromWorkerThread) - { - FlushMessageImmediately(buffer); - return; - } - - QueuedLogMessage* queuedBuffer = new QueuedLogMessage(buffer); bool dropped = false; // Flag indicates if the message was dropped due to queue overrun bool needToWakeWorkerThread = false; // Flag indicates if we need to wake the worker thread @@ -530,16 +604,8 @@ void OutputWorker::Write(LogStringBuffer& buffer, WriteOption option) { Locker locker(WorkQueueLock); - // If not logging from worker thread, - if (!LoggingFromWorkerThread) - { - // Immediately dequeue and log it. Yes this is slow but it only happens in transient cases. - FlushMessageImmediately(buffer); - dropped = true; - } - // If no room in the queue, - else if (option != WriteOption::DangerouslyIgnoreQueueLimit && - WorkQueueSize >= WorkQueueLimit) + if (option != WriteOption::DangerouslyIgnoreQueueLimit && + WorkQueueSize >= WorkQueueLimit) { // Record drop WorkQueueOverrun++; @@ -548,7 +614,9 @@ void OutputWorker::Write(LogStringBuffer& buffer, WriteOption option) else { // Add queued buffer to the end of the work queue - WorkQueueAdd(queuedBuffer); + SYSTEMTIME time; + ::GetLocalTime(&time); + WorkQueueAdd(new QueuedLogMessage(subsystemName, messageLogLevel, stream, time)); // Only need to wake the worker thread on the first message // The SetEvent() call takes 6 microseconds or so @@ -559,45 +627,91 @@ void OutputWorker::Write(LogStringBuffer& buffer, WriteOption option) } } - if (dropped) - { - delete queuedBuffer; - } - else if (needToWakeWorkerThread) + if (!dropped && needToWakeWorkerThread) { // Wake the worker thread ::SetEvent(WorkerWakeEvent.Get()); } // If this is the first time logging this message, - if (!buffer.Relogged) + if (!relogged) { // If we are in a debugger, if (IsInDebugger) { - FlushDbgViewLogImmediately(buffer); + FlushDbgViewLogImmediately(subsystemName, messageLogLevel, stream); } } } - //----------------------------------------------------------------------------- -// Channel +// QueuedLogMessage + +OutputWorker::QueuedLogMessage::QueuedLogMessage(const char* subsystemName, Level messageLogLevel, const char* stream, const SYSTEMTIME& time) +{ + MessageLogLevel = messageLogLevel; + SubsystemName = subsystemName; + Buffer = stream; + Time = time; + Next = nullptr; + FlushEvent = nullptr; +} + +void Channel::GetFunctionPointers() +{ + static bool gotFunctionPointers = false; + if (gotFunctionPointers == false) + { + OutputWorkerOutputFunction = (OutputWorkerOutputFunctionType)GetProcAddress(GetModuleHandle(NULL), "OutputWorkerOutputFunctionC"); + if (!OutputWorkerOutputFunction) + OutputWorkerOutputFunction = OutputWorkerOutputFunctionC; + + ConfiguratorOnChannelLevelChange = (ConfiguratorOnChannelLevelChangeType)GetProcAddress(GetModuleHandle(NULL), "ConfiguratorOnChannelLevelChangeC"); + if (!ConfiguratorOnChannelLevelChange) + ConfiguratorOnChannelLevelChange = ConfiguratorOnChannelLevelChangeC; + + ConfiguratorRegister = (ConfiguratorRegisterType)GetProcAddress(GetModuleHandle(NULL), "ConfiguratorRegisterC"); + if (!ConfiguratorRegister) + ConfiguratorRegister = ConfiguratorRegisterC; + + ConfiguratorUnregister = (ConfiguratorUnregisterType)GetProcAddress(GetModuleHandle(NULL), "ConfiguratorUnregisterC"); + if (!ConfiguratorUnregister) + ConfiguratorUnregister = ConfiguratorUnregisterC; + + gotFunctionPointers = true; + } +} Channel::Channel(const char* nameString) : SubsystemName(nameString), - MinimumOutputLevel(Level::Info) + MinimumOutputLevel((Log_Level_t)Level::Info) { SubsystemName = nameString; - Configurator::GetInstance()->Register(this); - // We can get modified from other threads here... + Node.SubsystemName = SubsystemName; + Node.Level = &MinimumOutputLevel; + + GetFunctionPointers(); + + ConfiguratorRegister(&Node); +} + +Channel::Channel(const Channel& other) +{ + SubsystemName = other.SubsystemName; + MinimumOutputLevel = other.MinimumOutputLevel; + Prefix = other.Prefix; + + Node.SubsystemName = SubsystemName; + Node.Level = &MinimumOutputLevel; + + ConfiguratorRegister(&Node); } Channel::~Channel() { // ...We can get modified from other threads here. - Configurator::GetInstance()->Unregister(this); + ConfiguratorUnregister(&Node); } std::string Channel::GetPrefix() const @@ -614,12 +728,12 @@ void Channel::SetMinimumOutputLevel(Level newLevel) { SetMinimumOutputLevelNoSave(newLevel); - Configurator::GetInstance()->OnChannelLevelChange(this); + ConfiguratorOnChannelLevelChange(SubsystemName, MinimumOutputLevel); } void Channel::SetMinimumOutputLevelNoSave(Level newLevel) { - MinimumOutputLevel = newLevel; + MinimumOutputLevel = (Log_Level_t)newLevel; } const char* Channel::GetName() const @@ -629,10 +743,9 @@ const char* Channel::GetName() const Level Channel::GetMinimumOutputLevel() const { - return MinimumOutputLevel; + return (Level) MinimumOutputLevel; } - //----------------------------------------------------------------------------- // Conversion functions @@ -710,13 +823,7 @@ ConfiguratorPlugin::~ConfiguratorPlugin() // Log Configurator Configurator::Configurator() : - ChannelsLock(), -#ifdef LOGGING_DEBUG - GlobalMinimumLogLevel(Level::Debug), -#else - GlobalMinimumLogLevel(Level::Info), -#endif - Channels(), + GlobalMinimumLogLevel((Log_Level_t) Level::Debug), Plugin(nullptr) { } @@ -733,66 +840,92 @@ Configurator::~Configurator() void Configurator::SetGlobalMinimumLogLevel(Level level) { - Locker locker(ChannelsLock); + Locker locker(OutputWorker::GetInstance()->GetChannelsLock()); - GlobalMinimumLogLevel = level; + GlobalMinimumLogLevel = (Log_Level_t)level; - for (Channel* channel : Channels) + for (ChannelNode* channelNode = ChannelNodeHead; channelNode; channelNode = channelNode->Next) { - channel->SetMinimumOutputLevelNoSave(level); + *(channelNode->Level) = (ovrlog::Log_Level_t) level; } } -void Configurator::RestoreChannelLogLevel(Channel* channel) +// Should be locked already when calling this function! +void Configurator::RestoreChannelLogLevel(const char* channelName) { - Level level = GlobalMinimumLogLevel; + Level level = (Level) GlobalMinimumLogLevel; // Look up the log level for this channel if we can if (Plugin) { - Plugin->RestoreChannelLevel(channel->GetName(), level); + Plugin->RestoreChannelLevel(channelName, level); } - channel->SetMinimumOutputLevelNoSave(level); + const std::string stdChannelName(channelName); + + SetChannelNoLock(stdChannelName, level); +} + +void Configurator::RestoreAllChannelLogLevels() +{ + Locker locker(OutputWorker::GetInstance()->GetChannelsLock()); + + for (ChannelNode* channelNode = ChannelNodeHead; channelNode; channelNode = channelNode->Next) + { + RestoreChannelLogLevel(channelNode->SubsystemName); + } } void Configurator::SetPlugin(std::shared_ptr plugin) { - Locker locker(ChannelsLock); + Locker locker(OutputWorker::GetInstance()->GetChannelsLock()); Plugin = plugin; - for (Channel* channel : Channels) + for (ChannelNode* channelNode = ChannelNodeHead; channelNode; channelNode = channelNode->Next) { - RestoreChannelLogLevel(channel); + RestoreChannelLogLevel(channelNode->SubsystemName); + } +} +void Configurator::GetChannels(std::vector< std::pair > &channels) +{ + channels.clear(); + + Locker locker(OutputWorker::GetInstance()->GetChannelsLock()); + + for (ChannelNode* channelNode = ChannelNodeHead; channelNode; channelNode = channelNode->Next) + { + channels.push_back(std::make_pair(std::string(channelNode->SubsystemName), (Level)*(channelNode->Level))); + } +} +void Configurator::SetChannel(std::string channelName, Level level) +{ + Locker locker(OutputWorker::GetInstance()->GetChannelsLock()); + SetChannelNoLock(channelName, level); +} + +// Should be locked already when calling this function! +void Configurator::SetChannelNoLock(std::string channelName, Level level) +{ + for (ChannelNode* channelNode = ChannelNodeHead; channelNode; channelNode = channelNode->Next) + { + if (std::string(channelNode->SubsystemName) == channelName) + { + *(channelNode->Level) = (Log_Level_t)level; + + // Purposely no break, channels may have duplicate names + } } } -void Configurator::Register(Channel* channel) +void Configurator::OnChannelLevelChange(const char* channelName, Log_Level_t minimumOutputLevel) { - Locker locker(ChannelsLock); - - Channels.erase(channel); - Channels.insert(channel); - - RestoreChannelLogLevel(channel); -} - -void Configurator::Unregister(Channel* channel) -{ - Locker locker(ChannelsLock); - - Channels.erase(channel); -} - -void Configurator::OnChannelLevelChange(Channel* channel) -{ - Locker locker(ChannelsLock); + Locker locker(OutputWorker::GetInstance()->GetChannelsLock()); if (Plugin) { // Save channel level - Plugin->SaveChannelLevel(channel->GetName(), channel->GetMinimumOutputLevel()); + Plugin->SaveChannelLevel(channelName, (Level) minimumOutputLevel); } } diff --git a/Logging/src/Logging_OutputPlugins.cpp b/Logging/src/Logging_OutputPlugins.cpp index 19f8c7a..44f1310 100644 --- a/Logging/src/Logging_OutputPlugins.cpp +++ b/Logging/src/Logging_OutputPlugins.cpp @@ -107,6 +107,7 @@ void OutputConsole::Write(Level level, const char* /*subsystem*/, const char* he #endif // OVR_SYSLOG_NAME OutputEventLog::OutputEventLog() + : MinReportEventLevel(Level::Error) { hEventSource = ::RegisterEventSourceW( nullptr, // No server name @@ -132,6 +133,11 @@ void OutputEventLog::Write(Level level, const char* subsystem, const char* heade { (void)subsystem; // unused + if (level < MinReportEventLevel) + { + return; + } + if (!hEventSource) { return; diff --git a/Samples/CommonSrc/Platform/Gamepad.h b/Samples/CommonSrc/Platform/Gamepad.h index 7ec8bb5..4151e3e 100644 --- a/Samples/CommonSrc/Platform/Gamepad.h +++ b/Samples/CommonSrc/Platform/Gamepad.h @@ -104,7 +104,7 @@ public: virtual uint32_t GetGamepadCount() = 0; // Get the state of the gamepad with a given index. - virtual bool GetGamepadState(uint32_t index, GamepadState* pState) = 0; + virtual bool GetGamepadState(GamepadState* pState) = 0; }; }} // OVR::OvrPlatform diff --git a/Samples/CommonSrc/Platform/Win32_Gamepad.cpp b/Samples/CommonSrc/Platform/Win32_Gamepad.cpp index d93589d..1292212 100644 --- a/Samples/CommonSrc/Platform/Win32_Gamepad.cpp +++ b/Samples/CommonSrc/Platform/Win32_Gamepad.cpp @@ -74,11 +74,8 @@ uint32_t GamepadManager::GetGamepadCount() return 1; } -bool GamepadManager::GetGamepadState(uint32_t index, GamepadState* pState) +bool GamepadManager::GetGamepadState(GamepadState* pState) { - // For now we just support one gamepad. - OVR_UNUSED(index); - if (pXInputGetState) { if((NextTryTime == 0) || (GetTickCount() >= NextTryTime)) // If the device is known to be present or if it's time to try testing for it again... diff --git a/Samples/CommonSrc/Platform/Win32_Gamepad.h b/Samples/CommonSrc/Platform/Win32_Gamepad.h index 8b332c0..f5aa906 100644 --- a/Samples/CommonSrc/Platform/Win32_Gamepad.h +++ b/Samples/CommonSrc/Platform/Win32_Gamepad.h @@ -38,7 +38,7 @@ public: ~GamepadManager(); virtual uint32_t GetGamepadCount(); - virtual bool GetGamepadState(uint32_t index, GamepadState* pState); + virtual bool GetGamepadState(GamepadState* pState); private: // Dynamically ink to XInput to simplify projects. diff --git a/Samples/OculusRoomTiny/OculusRoomTiny (DX11)/main.cpp b/Samples/OculusRoomTiny/OculusRoomTiny (DX11)/main.cpp index 2a30cda..7466594 100644 --- a/Samples/OculusRoomTiny/OculusRoomTiny (DX11)/main.cpp +++ b/Samples/OculusRoomTiny/OculusRoomTiny (DX11)/main.cpp @@ -145,7 +145,7 @@ static bool MainLoop(bool retryCreate) if (!pEyeRenderTexture[eye]->Init(session, idealSize.w, idealSize.h)) { if (retryCreate) goto Done; - VALIDATE(OVR_SUCCESS(result), "Failed to create eye texture."); + VALIDATE(false, "Failed to create eye texture."); } pEyeDepthBuffer[eye] = new DepthBuffer(DIRECTX.Device, idealSize.w, idealSize.h); eyeRenderViewport[eye].Pos.x = 0; diff --git a/Samples/OculusRoomTiny/OculusRoomTiny (DX12)/main.cpp b/Samples/OculusRoomTiny/OculusRoomTiny (DX12)/main.cpp index 4aefb86..08cad58 100644 --- a/Samples/OculusRoomTiny/OculusRoomTiny (DX12)/main.cpp +++ b/Samples/OculusRoomTiny/OculusRoomTiny (DX12)/main.cpp @@ -190,7 +190,7 @@ static bool MainLoop(bool retryCreate) if (!pEyeRenderTexture[eye]->Init(session, idealSize.w, idealSize.h, true)) { if (retryCreate) goto Done; - VALIDATE(OVR_SUCCESS(result), "Failed to create eye texture."); + VALIDATE(false, "Failed to create eye texture."); } eyeRenderViewport[eye].Pos.x = 0; diff --git a/Samples/OculusRoomTiny_Advanced/App-rendered/ORT (App-rendered)/Projects/Windows/VS2015/ORT (App-rendered).vcxproj b/Samples/OculusRoomTiny_Advanced/App-rendered/ORT (App-rendered)/Projects/Windows/VS2015/ORT (App-rendered).vcxproj index d49bc41..a6f98c2 100644 --- a/Samples/OculusRoomTiny_Advanced/App-rendered/ORT (App-rendered)/Projects/Windows/VS2015/ORT (App-rendered).vcxproj +++ b/Samples/OculusRoomTiny_Advanced/App-rendered/ORT (App-rendered)/Projects/Windows/VS2015/ORT (App-rendered).vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -32,27 +32,27 @@ Application true MultiByte - v120 + v140 Application true MultiByte - v120 + v140 Application false true Unicode - v120 + v140 Application false true Unicode - v120 + v140 @@ -255,4 +255,4 @@ - + \ No newline at end of file diff --git a/Samples/OculusRoomTiny_Advanced/App-rendered/ORT (Parallel CPU GPU)/Projects/Windows/VS2015/ORT (Parallet CPU GPU).vcxproj b/Samples/OculusRoomTiny_Advanced/App-rendered/ORT (Parallel CPU GPU)/Projects/Windows/VS2015/ORT (Parallet CPU GPU).vcxproj index e08fe67..1ab1ca1 100644 --- a/Samples/OculusRoomTiny_Advanced/App-rendered/ORT (Parallel CPU GPU)/Projects/Windows/VS2015/ORT (Parallet CPU GPU).vcxproj +++ b/Samples/OculusRoomTiny_Advanced/App-rendered/ORT (Parallel CPU GPU)/Projects/Windows/VS2015/ORT (Parallet CPU GPU).vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -32,27 +32,27 @@ Application true MultiByte - v120 + v140 Application true MultiByte - v120 + v140 Application false true Unicode - v120 + v140 Application false true Unicode - v120 + v140 @@ -255,4 +255,4 @@ - + \ No newline at end of file diff --git a/Samples/OculusRoomTiny_Advanced/App-rendered/ORT (Vary Timing, Relief)/Projects/Windows/VS2015/ORT (Vary Timing, Relief).vcxproj b/Samples/OculusRoomTiny_Advanced/App-rendered/ORT (Vary Timing, Relief)/Projects/Windows/VS2015/ORT (Vary Timing, Relief).vcxproj index 9db2bf4..72508a9 100644 --- a/Samples/OculusRoomTiny_Advanced/App-rendered/ORT (Vary Timing, Relief)/Projects/Windows/VS2015/ORT (Vary Timing, Relief).vcxproj +++ b/Samples/OculusRoomTiny_Advanced/App-rendered/ORT (Vary Timing, Relief)/Projects/Windows/VS2015/ORT (Vary Timing, Relief).vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -32,27 +32,27 @@ Application true MultiByte - v120 + v140 Application true MultiByte - v120 + v140 Application false true Unicode - v120 + v140 Application false true Unicode - v120 + v140 @@ -255,4 +255,4 @@ - + \ No newline at end of file diff --git a/Samples/OculusRoomTiny_Advanced/Common/Win32_DirectXAppUtil.h b/Samples/OculusRoomTiny_Advanced/Common/Win32_DirectXAppUtil.h index 996b72e..57e4912 100644 --- a/Samples/OculusRoomTiny_Advanced/Common/Win32_DirectXAppUtil.h +++ b/Samples/OculusRoomTiny_Advanced/Common/Win32_DirectXAppUtil.h @@ -205,12 +205,15 @@ struct DirectX11 } } - bool InitDevice(int vpW, int vpH, const LUID* pLuid, bool windowed = true) + bool InitDevice(int vpW, int vpH, const LUID* pLuid, bool windowed = true, int scale = 1) { WinSizeW = vpW; WinSizeH = vpH; - RECT size = { 0, 0, vpW, vpH }; + if (scale == 0) + scale = 1; + + RECT size = { 0, 0, vpW / scale, vpH / scale}; AdjustWindowRect(&size, WS_OVERLAPPEDWINDOW, false); const UINT flags = SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW; if (!SetWindowPos(Window, nullptr, 0, 0, size.right - size.left, size.bottom - size.top, flags)) diff --git a/Samples/OculusRoomTiny_Advanced/ORT (Handling Near Objects)/Projects/Win/VS2015/ORT (Handling Near Objects).vcxproj b/Samples/OculusRoomTiny_Advanced/ORT (Handling Near Objects)/Projects/Win/VS2015/ORT (Handling Near Objects).vcxproj new file mode 100644 index 0000000..d671109 --- /dev/null +++ b/Samples/OculusRoomTiny_Advanced/ORT (Handling Near Objects)/Projects/Win/VS2015/ORT (Handling Near Objects).vcxproj @@ -0,0 +1,258 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + {F0155D19-6156-4468-BD25-09EF912A0437} + Win32Proj + OculusRoomTiny + Handling Near Objects + + + + Application + true + MultiByte + v120 + + + Application + true + MultiByte + v120 + + + Application + false + true + Unicode + v120 + + + Application + false + true + Unicode + v120 + + + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + true + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + false + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + false + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + + NotUsing + Level3 + Disabled + OVR_BUILD_DEBUG;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + OldStyle + true + false + + + Windows + true + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + NotUsing + Level3 + Disabled + OVR_BUILD_DEBUG;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + OldStyle + true + false + + + Windows + true + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + true + OldStyle + Speed + true + true + false + /d2Zi+ %(AdditionalOptions) + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + UseLinkTimeCodeGeneration + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + PerMonitorHighDPIAware + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + true + OldStyle + Speed + true + true + false + false + /d2Zi+ %(AdditionalOptions) + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + UseLinkTimeCodeGeneration + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + PerMonitorHighDPIAware + + + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + $(IntDir)\$(MSBuildProjectName).log + + + Precise + MultiThreadedDebug + true + false + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + PerMonitorHighDPIAware + + + Default + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + + + $(IntDir)\$(MSBuildProjectName).log + + + Precise + MultiThreadedDebug + true + false + false + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + PerMonitorHighDPIAware + + + Default + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + + + + diff --git a/Samples/OculusRoomTiny_Advanced/ORT (Handling Near Objects)/Projects/Win/VS2015/ORT (Handling Near Objects).vcxproj.filters b/Samples/OculusRoomTiny_Advanced/ORT (Handling Near Objects)/Projects/Win/VS2015/ORT (Handling Near Objects).vcxproj.filters new file mode 100644 index 0000000..e3e9020 --- /dev/null +++ b/Samples/OculusRoomTiny_Advanced/ORT (Handling Near Objects)/Projects/Win/VS2015/ORT (Handling Near Objects).vcxproj.filters @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/OculusRoomTiny_Advanced/ORT (Instanced Stereo)/Projects/Windows/VS2015/ORT (Instanced Stereo).vcxproj b/Samples/OculusRoomTiny_Advanced/ORT (Instanced Stereo)/Projects/Windows/VS2015/ORT (Instanced Stereo).vcxproj new file mode 100644 index 0000000..5ee8ec2 --- /dev/null +++ b/Samples/OculusRoomTiny_Advanced/ORT (Instanced Stereo)/Projects/Windows/VS2015/ORT (Instanced Stereo).vcxproj @@ -0,0 +1,259 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + {8A01AB25-5B9B-406F-AEEA-0B84D6EBCEE4} + Win32Proj + OculusRoomTiny + v. Instanced Stereo + 8.1 + + + + Application + true + MultiByte + v140 + + + Application + true + MultiByte + v140 + + + Application + false + true + Unicode + v140 + + + Application + false + true + Unicode + v140 + + + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + true + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + false + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + false + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + + NotUsing + Level3 + Disabled + OVR_BUILD_DEBUG;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + OldStyle + true + false + + + Windows + true + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + NotUsing + Level3 + Disabled + OVR_BUILD_DEBUG;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + OldStyle + true + false + + + Windows + true + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + true + OldStyle + Speed + true + true + false + /d2Zi+ %(AdditionalOptions) + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + UseLinkTimeCodeGeneration + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + PerMonitorHighDPIAware + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + true + OldStyle + Speed + true + true + false + false + /d2Zi+ %(AdditionalOptions) + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + UseLinkTimeCodeGeneration + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + PerMonitorHighDPIAware + + + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + $(IntDir)\$(MSBuildProjectName).log + + + Precise + MultiThreadedDebug + true + false + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + PerMonitorHighDPIAware + + + Default + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + + + $(IntDir)\$(MSBuildProjectName).log + + + Precise + MultiThreadedDebug + true + false + false + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + PerMonitorHighDPIAware + + + Default + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + + + + diff --git a/Samples/OculusRoomTiny_Advanced/ORT (Instanced Stereo)/Projects/Windows/VS2015/ORT (Instanced Stereo).vcxproj.filters b/Samples/OculusRoomTiny_Advanced/ORT (Instanced Stereo)/Projects/Windows/VS2015/ORT (Instanced Stereo).vcxproj.filters new file mode 100644 index 0000000..e3e9020 --- /dev/null +++ b/Samples/OculusRoomTiny_Advanced/ORT (Instanced Stereo)/Projects/Windows/VS2015/ORT (Instanced Stereo).vcxproj.filters @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/OculusRoomTiny_Advanced/ORT (Oculus Remote)/Projects/Win/VS2015/ORT (Oculus Remote).vcxproj b/Samples/OculusRoomTiny_Advanced/ORT (Oculus Remote)/Projects/Win/VS2015/ORT (Oculus Remote).vcxproj new file mode 100644 index 0000000..d1ac460 --- /dev/null +++ b/Samples/OculusRoomTiny_Advanced/ORT (Oculus Remote)/Projects/Win/VS2015/ORT (Oculus Remote).vcxproj @@ -0,0 +1,258 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + {77F688B1-A6B4-448A-8D6A-8859D537573E} + Win32Proj + OculusRoomTiny + w. Oculus Remote + + + + Application + true + MultiByte + v120 + + + Application + true + MultiByte + v120 + + + Application + false + true + Unicode + v120 + + + Application + false + true + Unicode + v120 + + + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + true + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + false + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + false + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + + NotUsing + Level3 + Disabled + OVR_BUILD_DEBUG;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + OldStyle + true + false + + + Windows + true + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + NotUsing + Level3 + Disabled + OVR_BUILD_DEBUG;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + OldStyle + true + false + + + Windows + true + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + true + OldStyle + Speed + true + true + false + /d2Zi+ %(AdditionalOptions) + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + UseLinkTimeCodeGeneration + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + PerMonitorHighDPIAware + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + true + OldStyle + Speed + true + true + false + false + /d2Zi+ %(AdditionalOptions) + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + UseLinkTimeCodeGeneration + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + PerMonitorHighDPIAware + + + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + $(IntDir)\$(MSBuildProjectName).log + + + Precise + MultiThreadedDebug + true + false + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + PerMonitorHighDPIAware + + + Default + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + + + $(IntDir)\$(MSBuildProjectName).log + + + Precise + MultiThreadedDebug + true + false + false + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + PerMonitorHighDPIAware + + + Default + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + + + + diff --git a/Samples/OculusRoomTiny_Advanced/ORT (Oculus Remote)/Projects/Win/VS2015/ORT (Oculus Remote).vcxproj.filters b/Samples/OculusRoomTiny_Advanced/ORT (Oculus Remote)/Projects/Win/VS2015/ORT (Oculus Remote).vcxproj.filters new file mode 100644 index 0000000..e3e9020 --- /dev/null +++ b/Samples/OculusRoomTiny_Advanced/ORT (Oculus Remote)/Projects/Win/VS2015/ORT (Oculus Remote).vcxproj.filters @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/OculusRoomTiny_Advanced/ORT (Performance HUD)/main.cpp b/Samples/OculusRoomTiny_Advanced/ORT (Performance HUD)/main.cpp index 7e04032..270f8ea 100644 --- a/Samples/OculusRoomTiny_Advanced/ORT (Performance HUD)/main.cpp +++ b/Samples/OculusRoomTiny_Advanced/ORT (Performance HUD)/main.cpp @@ -36,7 +36,7 @@ limitations under the License. /// to the point when the middle scanline of the target frame is illuminated on the HMD display. /// This is the same info presented in "Application Latency Timing" section, presented here as part of the performance summary. /// -/// Unused performance +/// Performance Headroom /// The percentage of available PC performance that has not been utilized by the client application and compositor. /// This is essentially the application CPU & GPU time tracked in the "Application Render Timing" pane section divided by the /// native frame time (inverse of refresh rate) of the HMD. It is meant to be a simple guide for the user to verify that their @@ -52,7 +52,7 @@ limitations under the License. /// This is the same value provided in the "Compositor Render Timing" pane called "Compositor Missed V-Sync Count". /// /// Left-side graph: Plots frame rate of the application -/// Right-side graph: Plots the "Unused performance %" provided in the same section +/// Right-side graph: Plots the "Performance headroom %" provided in the same section /// /// Latency Timing Pane : /// diff --git a/Samples/OculusRoomTiny_Advanced/ORT (Third Person)/Projects/Win/VS2015/ORT (Third Person).vcxproj b/Samples/OculusRoomTiny_Advanced/ORT (Third Person)/Projects/Win/VS2015/ORT (Third Person).vcxproj new file mode 100644 index 0000000..d58d990 --- /dev/null +++ b/Samples/OculusRoomTiny_Advanced/ORT (Third Person)/Projects/Win/VS2015/ORT (Third Person).vcxproj @@ -0,0 +1,258 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + {EDADB6EA-D49F-4396-8B6A-7465581DCFA0} + Win32Proj + OculusRoomTiny + Third Person + + + + Application + true + MultiByte + v120 + + + Application + true + MultiByte + v120 + + + Application + false + true + Unicode + v120 + + + Application + false + true + Unicode + v120 + + + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + true + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + false + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + false + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + + NotUsing + Level3 + Disabled + OVR_BUILD_DEBUG;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + OldStyle + true + false + + + Windows + true + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + NotUsing + Level3 + Disabled + OVR_BUILD_DEBUG;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + OldStyle + true + false + + + Windows + true + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + true + OldStyle + Speed + true + true + false + /d2Zi+ %(AdditionalOptions) + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + UseLinkTimeCodeGeneration + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + PerMonitorHighDPIAware + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + true + OldStyle + Speed + true + true + false + false + /d2Zi+ %(AdditionalOptions) + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + UseLinkTimeCodeGeneration + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + PerMonitorHighDPIAware + + + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + $(IntDir)\$(MSBuildProjectName).log + + + Precise + MultiThreadedDebug + true + false + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + PerMonitorHighDPIAware + + + Default + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + + + $(IntDir)\$(MSBuildProjectName).log + + + Precise + MultiThreadedDebug + true + false + false + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + PerMonitorHighDPIAware + + + Default + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + + + + diff --git a/Samples/OculusRoomTiny_Advanced/ORT (Third Person)/Projects/Win/VS2015/ORT (Third Person).vcxproj.filters b/Samples/OculusRoomTiny_Advanced/ORT (Third Person)/Projects/Win/VS2015/ORT (Third Person).vcxproj.filters new file mode 100644 index 0000000..e3e9020 --- /dev/null +++ b/Samples/OculusRoomTiny_Advanced/ORT (Third Person)/Projects/Win/VS2015/ORT (Third Person).vcxproj.filters @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/OculusRoomTiny_Advanced/ORT (Threading)/Projects/Win/VS2015/ORT (Threading).vcxproj b/Samples/OculusRoomTiny_Advanced/ORT (Threading)/Projects/Win/VS2015/ORT (Threading).vcxproj index abcdc1a..0c13dca 100644 --- a/Samples/OculusRoomTiny_Advanced/ORT (Threading)/Projects/Win/VS2015/ORT (Threading).vcxproj +++ b/Samples/OculusRoomTiny_Advanced/ORT (Threading)/Projects/Win/VS2015/ORT (Threading).vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -32,27 +32,27 @@ Application true MultiByte - v120 + v140 Application true MultiByte - v120 + v140 Application false true Unicode - v120 + v140 Application false true Unicode - v120 + v140 @@ -255,4 +255,4 @@ - + \ No newline at end of file diff --git a/Samples/OculusRoomTiny_Advanced/ORT (Tunnelling)/Projects/Windows/VS2015/ORT (Tunnelling).vcxproj b/Samples/OculusRoomTiny_Advanced/ORT (Tunnelling)/Projects/Windows/VS2015/ORT (Tunnelling).vcxproj new file mode 100644 index 0000000..9f22e28 --- /dev/null +++ b/Samples/OculusRoomTiny_Advanced/ORT (Tunnelling)/Projects/Windows/VS2015/ORT (Tunnelling).vcxproj @@ -0,0 +1,258 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + {059F3E59-D4C2-4D08-8593-AB8FC45CBA43} + Win32Proj + OculusRoomTiny + Tunnelling + + + + Application + true + MultiByte + v120 + + + Application + true + MultiByte + v120 + + + Application + false + true + Unicode + v120 + + + Application + false + true + Unicode + v120 + + + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + true + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + false + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + false + $(ProjectDir)..\..\..\Obj\Windows\$(Platform)\$(Configuration)\VS2015\ + $(ProjectDir)..\..\..\Bin\Windows\$(Platform)\$(Configuration)\VS2015\ + + + + NotUsing + Level3 + Disabled + OVR_BUILD_DEBUG;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + OldStyle + true + false + + + Windows + true + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + NotUsing + Level3 + Disabled + OVR_BUILD_DEBUG;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + OldStyle + true + false + + + Windows + true + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + true + OldStyle + Speed + true + true + false + /d2Zi+ %(AdditionalOptions) + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + UseLinkTimeCodeGeneration + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + PerMonitorHighDPIAware + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + true + OldStyle + Speed + true + true + false + false + /d2Zi+ %(AdditionalOptions) + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + UseLinkTimeCodeGeneration + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + PerMonitorHighDPIAware + + + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + $(ProjectName)\$(IntDir)\$(MSBuildProjectName).log + + + PerMonitorHighDPIAware + + + + + $(IntDir)\$(MSBuildProjectName).log + + + Precise + MultiThreadedDebug + true + false + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + PerMonitorHighDPIAware + + + Default + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + + + $(IntDir)\$(MSBuildProjectName).log + + + Precise + MultiThreadedDebug + true + false + false + $(OVRSDKROOT)LibOVR/Include/;%(AdditionalIncludeDirectories) + + + PerMonitorHighDPIAware + + + Default + $(OVRSDKROOT)LibOVR/Lib/Windows/$(Platform)/$(Configuration)/VS2015/LibOVR.lib;%(AdditionalDependencies) + + + + + + diff --git a/Samples/OculusRoomTiny_Advanced/ORT (Tunnelling)/Projects/Windows/VS2015/ORT (Tunnelling).vcxproj.filters b/Samples/OculusRoomTiny_Advanced/ORT (Tunnelling)/Projects/Windows/VS2015/ORT (Tunnelling).vcxproj.filters new file mode 100644 index 0000000..e3e9020 --- /dev/null +++ b/Samples/OculusRoomTiny_Advanced/ORT (Tunnelling)/Projects/Windows/VS2015/ORT (Tunnelling).vcxproj.filters @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/OculusWorldDemo/OculusWorldDemo.cpp b/Samples/OculusWorldDemo/OculusWorldDemo.cpp index cb8aae4..c50a3fe 100644 --- a/Samples/OculusWorldDemo/OculusWorldDemo.cpp +++ b/Samples/OculusWorldDemo/OculusWorldDemo.cpp @@ -1192,6 +1192,7 @@ ovrResult OculusWorldDemoApp::CalculateHmdValues() MultisampleEnabled = false; } + // Initialize eye rendering information. // The viewport sizes are re-computed in case RenderTargetSize changed due to HW limitations. g_EyeFov[0] = HmdDesc.DefaultEyeFov[0]; @@ -3728,10 +3729,10 @@ void OculusWorldDemoApp::DisplayLastErrorMessageBox(const char* pMessage) if(InteractiveMode) { - OVR::Util::DisplayMessageBoxF("OculusWorldDemo", "%s %x -- %s", pMessage, errorInfo.Result, errorInfo.ErrorString); + OVR::Util::DisplayMessageBoxF("OculusWorldDemo", "%s %d -- %s", pMessage, errorInfo.Result, errorInfo.ErrorString); } - OVR_DEBUG_LOG(("OculusWorldDemo: %s %x -- %s", pMessage, errorInfo.Result, errorInfo.ErrorString)); + OVR_DEBUG_LOG(("OculusWorldDemo: %s %d -- %s", pMessage, errorInfo.Result, errorInfo.ErrorString)); }