From 7230ca73e6755295f3285a908de07efc9ccd70bf Mon Sep 17 00:00:00 2001 From: Jeremy Bell Date: Fri, 17 Nov 2017 12:32:30 -0500 Subject: [PATCH 1/5] Added present blocking code to D3D11ATW wrapper backend. --- ...RenderManagerD3DATWDoubleBufferExample.cpp | 3 + examples/RenderManagerD3DCAPIExample.cpp | 253 ++++++++++-------- osvr/RenderKit/RenderManagerD3D11ATW.h | 33 ++- 3 files changed, 172 insertions(+), 117 deletions(-) diff --git a/examples/RenderManagerD3DATWDoubleBufferExample.cpp b/examples/RenderManagerD3DATWDoubleBufferExample.cpp index ecf7fe9..4c477cf 100644 --- a/examples/RenderManagerD3DATWDoubleBufferExample.cpp +++ b/examples/RenderManagerD3DATWDoubleBufferExample.cpp @@ -40,6 +40,7 @@ Russ Taylor #include #include #include +#include #include // For exit() using namespace DirectX; @@ -135,6 +136,8 @@ struct FrameInfo { }; int main(int argc, char* argv[]) { + std::cout << "Render thread id: " << std::this_thread::get_id(); + // Parse the command line int delayMilliSeconds = 500; int realParams = 0; diff --git a/examples/RenderManagerD3DCAPIExample.cpp b/examples/RenderManagerD3DCAPIExample.cpp index d33dff3..11dde22 100644 --- a/examples/RenderManagerD3DCAPIExample.cpp +++ b/examples/RenderManagerD3DCAPIExample.cpp @@ -42,6 +42,7 @@ #include #include // For exit() #include +#include using namespace DirectX; @@ -88,8 +89,8 @@ void myButtonCallback(void* userdata, const OSVR_TimeValue* /*timestamp*/, // Callbacks to draw things in world space, left-hand space, and right-hand // space. void RenderView( - const OSVR_RenderInfoD3D11& renderInfo //< Info needed to render - , + size_t eye, + const OSVR_RenderInfoD3D11& renderInfo, //< Info needed to render ID3D11RenderTargetView* renderTargetView, ID3D11DepthStencilView* depthStencilView) { @@ -103,17 +104,12 @@ void RenderView( context->OMSetRenderTargets(1, &renderTargetView, depthStencilView); // Set up the viewport we're going to draw into. - CD3D11_VIEWPORT viewport(static_cast(renderInfo.viewport.left), - static_cast(renderInfo.viewport.lower), - static_cast(renderInfo.viewport.width), - static_cast(renderInfo.viewport.height)); - context->RSSetViewports(1, &viewport); + CD3D11_VIEWPORT viewport(static_cast(eye == 0 ? 0 : renderInfo.viewport.width), + static_cast(renderInfo.viewport.lower), + static_cast(renderInfo.viewport.width), + static_cast(renderInfo.viewport.height)); - // Make a grey background - FLOAT colorRgba[4] = {0.3f, 0.3f, 0.3f, 1.0f}; - context->ClearRenderTargetView(renderTargetView, colorRgba); - context->ClearDepthStencilView( - depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); + context->RSSetViewports(1, &viewport); OSVR_PoseState_to_D3D(viewD3D, renderInfo.pose); OSVR_Projection_to_D3D(projectionD3D, @@ -132,6 +128,8 @@ void Usage(std::string name) { } int main(int argc, char* argv[]) { + SetThreadName((DWORD)-1, "RenderThread"); + std::cout << "Render thread id: " << std::this_thread::get_id(); // Parse the command line int realParams = 0; for (int i = 1; i < argc; i++) { @@ -153,6 +151,23 @@ int main(int argc, char* argv[]) { osvr::clientkit::ClientContext context( "osvr.RenderManager.D3DPresentExample3D"); + // Wait for good status on context + { + auto ctxInitStart = std::chrono::system_clock::now(); + bool timeout = false; + do { + context.update(); + auto ctxInitEnd = std::chrono::system_clock::now(); + std::chrono::duration elapsedSec = ctxInitEnd - ctxInitStart; + int secs = static_cast(elapsedSec.count()); + timeout = secs >= 2; + } while (!context.checkStatus() && !timeout); + if (timeout) { + std::cerr << "Timed out waiting for the ClientContext to connect to the OSVR server."; + return 1; + } + } + // Construct button devices and connect them to a callback // that will set the "quit" variable to true when it is // pressed. Use button "1" on the left-hand or @@ -246,8 +261,11 @@ int main(int argc, char* argv[]) { std::vector depthStencilTextures; std::vector depthStencilViews; + double width = renderInfo[0].viewport.width + renderInfo[1].viewport.width; + double height = renderInfo[0].viewport.height; + HRESULT hr; - for (size_t i = 0; i < numRenderInfo; i++) { + for (size_t i = 0; i < 2; i++) { // The color buffer for this eye. We need to put this into // a generic structure for the Present function, but we only need @@ -255,8 +273,6 @@ int main(int argc, char* argv[]) { // Note that this texture format must be RGBA and unsigned byte, // so that we can present it to Direct3D for DirectMode. ID3D11Texture2D* D3DTexture = nullptr; - unsigned width = static_cast(renderInfo[i].viewport.width); - unsigned height = static_cast(renderInfo[i].viewport.height); // Initialize a new render target texture description. D3D11_TEXTURE2D_DESC textureDesc = {}; @@ -370,8 +386,7 @@ int main(int argc, char* argv[]) { // Front-facing stencil operations depthStencilDescription.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - depthStencilDescription.FrontFace.StencilDepthFailOp = - D3D11_STENCIL_OP_INCR; + depthStencilDescription.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR; depthStencilDescription.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; depthStencilDescription.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; @@ -399,7 +414,7 @@ int main(int argc, char* argv[]) { osvrDestroyRenderManager(render); return -4; } - for (size_t i = 0; i < numRenderInfo; i++) { + for (size_t i = 0; i < renderBuffers.size(); i++) { if ((OSVR_RETURN_SUCCESS != osvrRenderManagerRegisterRenderBufferD3D11( registerBufferState, renderBuffers[i]))) { std::cerr << "Could not register render buffer " << i << std::endl; @@ -408,7 +423,7 @@ int main(int argc, char* argv[]) { } } if ((OSVR_RETURN_SUCCESS != osvrRenderManagerFinishRegisterRenderBuffers( - render, registerBufferState, false))) { + render, registerBufferState, true))) { std::cerr << "Could not start finish registering render buffers" << std::endl; osvrDestroyRenderManager(render); return -6; @@ -416,99 +431,121 @@ int main(int argc, char* argv[]) { // Timing of frame rates size_t count = 0; + size_t frameIndex = 0; std::chrono::time_point start, end; start = std::chrono::system_clock::now(); // Continue rendering until it is time to quit. - while (!quit) { - // Update the context so we get our callbacks called and - // update tracker state. - context.update(); - - if ((OSVR_RETURN_SUCCESS != osvrRenderManagerGetRenderInfoCollection( - render, renderParams, &renderInfoCollection))) { - std::cerr << "Could not get render info" << std::endl; - osvrDestroyRenderManager(render); - return 105; - } - osvrRenderManagerGetNumRenderInfoInCollection(renderInfoCollection, &numRenderInfo); - - - renderInfo.clear(); - for (OSVR_RenderInfoCount i = 0; i < numRenderInfo; i++) { - OSVR_RenderInfoD3D11 info; - if ((OSVR_RETURN_SUCCESS != osvrRenderManagerGetRenderInfoFromCollectionD3D11( - renderInfoCollection, i, &info))) { - std::cerr << "Could not get render info " << i - << std::endl; - osvrDestroyRenderManager(render); - return 106; - } - renderInfo.push_back(info); - } - osvrRenderManagerReleaseRenderInfoCollection(renderInfoCollection); - - // Render into each buffer using the specified information. - for (size_t i = 0; i < renderInfo.size(); i++) { - renderInfo[i].library.context->OMSetDepthStencilState( - depthStencilState, 1); - RenderView(renderInfo[i], renderBuffers[i].colorBufferView, - depthStencilViews[i]); - } - - // Every other second, we show a black screen to test how - // a game engine might blank it between scenes. Every even - // second, we display the video. - end = std::chrono::system_clock::now(); - std::chrono::duration elapsed_sec = end - start; - int secs = static_cast(elapsed_sec.count()); - - if (secs % 2 == 0) { - // Send the rendered results to the screen - OSVR_RenderManagerPresentState presentState; - if ((OSVR_RETURN_SUCCESS != osvrRenderManagerStartPresentRenderBuffers( - &presentState))) { - std::cerr << "Could not start presenting render buffers" << std::endl; - osvrDestroyRenderManager(render); - return 201; - } - OSVR_ViewportDescription fullView; - fullView.left = fullView.lower = 0; - fullView.width = fullView.height = 1; - for (size_t i = 0; i < numRenderInfo; i++) { - if ((OSVR_RETURN_SUCCESS != osvrRenderManagerPresentRenderBufferD3D11( - presentState, renderBuffers[i], renderInfo[i], fullView))) { - std::cerr << "Could not present render buffer " << i << std::endl; - osvrDestroyRenderManager(render); - return 202; - } - } - if ((OSVR_RETURN_SUCCESS != osvrRenderManagerFinishPresentRenderBuffers( - render, presentState, renderParams, false))) { - std::cerr << "Could not finish presenting render buffers" << std::endl; - osvrDestroyRenderManager(render); - return 203; - } - } else { - // send a black screen. - OSVR_RGB_FLOAT black; - black.r = black.g = black.b = 0; - osvrRenderManagerPresentSolidColorf(render, black); - } - - // Timing information - if (elapsed_sec.count() >= 2) { - std::chrono::duration elapsed_usec = - end - start; - double usec = elapsed_usec.count(); - std::cout << "Rendering at " << count / (usec * 1e-6) << " fps" - << std::endl; - start = end; - count = 0; - } - count++; - } - + while (!quit) { + size_t renderBufferIndex = frameIndex % 2; + frameIndex++; + + // Update the context so we get our callbacks called and + // update tracker state. + context.update(); + + if ((OSVR_RETURN_SUCCESS != osvrRenderManagerGetRenderInfoCollection( + render, renderParams, &renderInfoCollection))) { + std::cerr << "Could not get render info" << std::endl; + osvrDestroyRenderManager(render); + return 105; + } + osvrRenderManagerGetNumRenderInfoInCollection(renderInfoCollection, &numRenderInfo); + + + renderInfo.clear(); + for (OSVR_RenderInfoCount i = 0; i < numRenderInfo; i++) { + OSVR_RenderInfoD3D11 info; + if ((OSVR_RETURN_SUCCESS != osvrRenderManagerGetRenderInfoFromCollectionD3D11( + renderInfoCollection, i, &info))) { + std::cerr << "Could not get render info " << i + << std::endl; + osvrDestroyRenderManager(render); + return 106; + } + renderInfo.push_back(info); + } + osvrRenderManagerReleaseRenderInfoCollection(renderInfoCollection); + + // Set up to render to the textures for this eye + auto renderTargetView = renderBuffers[renderBufferIndex].colorBufferView; + auto depthStencilView = depthStencilViews[renderBufferIndex]; + auto context = renderInfo[0].library.context; + context->OMSetRenderTargets(1, &renderTargetView, depthStencilView); + + // Set up the viewport we're going to draw into. + //CD3D11_VIEWPORT viewport(static_cast(renderInfo.viewport.left), + // static_cast(renderInfo.viewport.lower), + // static_cast(renderInfo.viewport.width), + // static_cast(renderInfo.viewport.height)); + CD3D11_VIEWPORT viewport( + 0.0f, + 0.0f, + static_cast(width), + static_cast(height)); + + context->RSSetViewports(1, &viewport); + + // Make a grey background + FLOAT colorRgba[4] = { 0.3f, 0.3f, 0.3f, 1.0f }; + context->ClearRenderTargetView(renderTargetView, colorRgba); + context->ClearDepthStencilView( + depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); + + // Render into each buffer using the specified information. + for (size_t i = 0; i < renderInfo.size(); i++) { + renderInfo[i].library.context->OMSetDepthStencilState( + depthStencilState, 1); + RenderView(i, renderInfo[i], renderTargetView, depthStencilView); + } + + // Every other second, we show a black screen to test how + // a game engine might blank it between scenes. Every even + // second, we display the video. + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_sec = end - start; + int secs = static_cast(elapsed_sec.count()); + + // Send the rendered results to the screen + OSVR_RenderManagerPresentState presentState; + if ((OSVR_RETURN_SUCCESS != osvrRenderManagerStartPresentRenderBuffers(&presentState))) { + std::cerr << "Could not start presenting render buffers" << std::endl; + osvrDestroyRenderManager(render); + return 201; + } + + for (size_t i = 0; i < numRenderInfo; i++) { + OSVR_ViewportDescription normalizedViewport; + normalizedViewport.left = i == 0 ? 0 : 0.5; + normalizedViewport.lower = 0; + normalizedViewport.width = 0.5; + normalizedViewport.height = 1.0; + + if ((OSVR_RETURN_SUCCESS != osvrRenderManagerPresentRenderBufferD3D11( + presentState, renderBuffers[renderBufferIndex], renderInfo[i], normalizedViewport))) { + std::cerr << "Could not present render buffer " << i << std::endl; + osvrDestroyRenderManager(render); + return 202; + } + } + if ((OSVR_RETURN_SUCCESS != osvrRenderManagerFinishPresentRenderBuffers( + render, presentState, renderParams, false))) { + std::cerr << "Could not finish presenting render buffers" << std::endl; + osvrDestroyRenderManager(render); + return 203; + } + + // Timing information + if (elapsed_sec.count() >= 2) { + std::chrono::duration elapsed_usec = end - start; + double usec = elapsed_usec.count(); + std::cout << "Rendering at " << count / (usec * 1e-6) << " fps" + << std::endl; + start = end; + count = 0; + } + count++; + } // Clean up after ourselves. // @todo diff --git a/osvr/RenderKit/RenderManagerD3D11ATW.h b/osvr/RenderKit/RenderManagerD3D11ATW.h index 608bf6f..eb14ca5 100644 --- a/osvr/RenderKit/RenderManagerD3D11ATW.h +++ b/osvr/RenderKit/RenderManagerD3D11ATW.h @@ -36,6 +36,7 @@ Sensics, Inc. #include #include #include +#include #include #include #include @@ -58,12 +59,13 @@ namespace osvr { } RenderBufferATWInfo; std::map mBufferMap; - std::mutex mLock; + std::mutex mMutex; + std::condition_variable mPresentFinishedCV; std::shared_ptr mThread = nullptr; /// Holds information about the buffers to be used by the next rendering /// pass. This is filled in by PresentRenderBuffersInternal() and used - /// by the ATW thread. Access should be guarded using the mLock to prevent + /// by the ATW thread. Access should be guarded using the mMutex to prevent /// simultaneous use in both threads. struct { std::vector colorBuffers; @@ -72,6 +74,7 @@ namespace osvr { RenderParams renderParams; bool flipInY; } mNextFrameInfo; + bool mNextFrameAvailable = false; bool mQuit = false; bool mStarted = false; @@ -106,7 +109,7 @@ namespace osvr { } OpenResults OpenDisplay() override { - std::lock_guard lock(mLock); + std::lock_guard lock(mMutex); OpenResults ret; @@ -192,7 +195,7 @@ namespace osvr { { // Adding block to scope the lock_guard. // Lock our mutex so we don't adjust the buffers while rendering is happening. // This lock is automatically released when we're done with this function. - std::lock_guard lock(mLock); + std::lock_guard lock(mMutex); HRESULT hr; mNextFrameInfo.colorBuffers.clear(); @@ -250,7 +253,16 @@ namespace osvr { mNextFrameInfo.renderParams = renderParams; mNextFrameInfo.normalizedCroppingViewports = normalizedCroppingViewports; mFirstFramePresented = true; + mNextFrameAvailable = true; } + + //m_log->info() << "RenderManagerD3D11ATW::PresentFrameInternal: Queued next frame info, waiting for it to be presented..."; + { + std::unique_lock lock(mMutex); + mPresentFinishedCV.wait(lock, [this] { return !mNextFrameAvailable; }); + } + //m_log->info() << "RenderManagerD3D11ATW::PresentFrameInternal: Finished waiting for the frame to be presented."; + return true; } @@ -272,7 +284,7 @@ namespace osvr { } void stop() { - std::lock_guard lock(mLock); + std::lock_guard lock(mMutex); if (!mStarted) { m_log->error() << "RenderManagerThread::stop() - thread loop not already started."; } @@ -280,7 +292,7 @@ namespace osvr { } bool getQuit() { - std::lock_guard lock(mLock); + std::lock_guard lock(mMutex); return mQuit; } @@ -336,7 +348,7 @@ namespace osvr { if (timeToPresent) { // Lock our mutex so that we're not rendering while new buffers are // being presented. - std::lock_guard lock(mLock); + std::lock_guard lock(mMutex); if (mFirstFramePresented) { // Update the context so we get our callbacks called and // update tracker state, which will be read during the @@ -404,7 +416,10 @@ namespace osvr { lastFrameTime = now; iteration++; + + mNextFrameAvailable = false; } + mPresentFinishedCV.notify_all(); } quit = mQuit; @@ -425,7 +440,7 @@ namespace osvr { bool PresentFrameFinalize() override { return true; } bool SolidColorEye(size_t eye, const RGBColorf &color) override { - std::lock_guard lock(mLock); + std::lock_guard lock(mMutex); // Stop the rendering thread from overwriting with warped // versions of the most recently presented buffers. mFirstFramePresented = false; @@ -577,7 +592,7 @@ namespace osvr { { // Adding block to scope the lock_guard. // Lock our mutex so that we're not rendering while new buffers are // being added or old ones modified. - std::lock_guard lock(mLock); + std::lock_guard lock(mMutex); mBufferMap[buffers[i].D3D11->colorBuffer] = newInfo; } } From 753d0dd01e9a819df355304f6d3e4230324c7574 Mon Sep 17 00:00:00 2001 From: Jeremy Bell Date: Fri, 17 Nov 2017 13:45:49 -0500 Subject: [PATCH 2/5] Modification to turn off vsync/blocking on the wrapped render manager backend --- examples/RenderManagerD3DATWDoubleBufferExample.cpp | 8 +++++--- examples/RenderManagerD3DCAPIExample.cpp | 9 ++++----- osvr/RenderKit/NDA/OSVR-RenderManager-NVIDIA | 2 +- osvr/RenderKit/RenderManagerBase.cpp | 7 +++++++ osvr/RenderKit/RenderManagerD3D11ATW.h | 5 +++++ osvr/RenderKit/RenderManagerD3DBase.h | 12 ++++++++++++ 6 files changed, 34 insertions(+), 9 deletions(-) diff --git a/examples/RenderManagerD3DATWDoubleBufferExample.cpp b/examples/RenderManagerD3DATWDoubleBufferExample.cpp index 4c477cf..fd69f3f 100644 --- a/examples/RenderManagerD3DATWDoubleBufferExample.cpp +++ b/examples/RenderManagerD3DATWDoubleBufferExample.cpp @@ -118,7 +118,9 @@ void RenderView( // draw room simpleShader.use(device, context, xm_projectionD3D, xm_viewD3D, identity); - roomCube.draw(device, context); + //for (size_t i = 0; i < 10000; i++) { + roomCube.draw(device, context); + //} } void Usage(std::string name) { @@ -136,10 +138,10 @@ struct FrameInfo { }; int main(int argc, char* argv[]) { - std::cout << "Render thread id: " << std::this_thread::get_id(); + std::cout << "Render thread id: " << std::this_thread::get_id() << std::endl; // Parse the command line - int delayMilliSeconds = 500; + int delayMilliSeconds = 0; int realParams = 0; for (int i = 1; i < argc; i++) { if (argv[i][0] == '-') { diff --git a/examples/RenderManagerD3DCAPIExample.cpp b/examples/RenderManagerD3DCAPIExample.cpp index 11dde22..686ece6 100644 --- a/examples/RenderManagerD3DCAPIExample.cpp +++ b/examples/RenderManagerD3DCAPIExample.cpp @@ -128,7 +128,6 @@ void Usage(std::string name) { } int main(int argc, char* argv[]) { - SetThreadName((DWORD)-1, "RenderThread"); std::cout << "Render thread id: " << std::this_thread::get_id(); // Parse the command line int realParams = 0; @@ -276,8 +275,8 @@ int main(int argc, char* argv[]) { // Initialize a new render target texture description. D3D11_TEXTURE2D_DESC textureDesc = {}; - textureDesc.Width = width; - textureDesc.Height = height; + textureDesc.Width = static_cast(width); + textureDesc.Height = static_cast(height); textureDesc.MipLevels = 1; textureDesc.ArraySize = 1; textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; @@ -333,8 +332,8 @@ int main(int argc, char* argv[]) { textureDescription.SampleDesc.Quality = 0; textureDescription.Usage = D3D11_USAGE_DEFAULT; textureDescription.BindFlags = D3D11_BIND_DEPTH_STENCIL; - textureDescription.Width = width; - textureDescription.Height = height; + textureDescription.Width = static_cast(width); + textureDescription.Height = static_cast(height); textureDescription.MipLevels = 1; textureDescription.ArraySize = 1; textureDescription.CPUAccessFlags = 0; diff --git a/osvr/RenderKit/NDA/OSVR-RenderManager-NVIDIA b/osvr/RenderKit/NDA/OSVR-RenderManager-NVIDIA index 883686b..ee7dc6c 160000 --- a/osvr/RenderKit/NDA/OSVR-RenderManager-NVIDIA +++ b/osvr/RenderKit/NDA/OSVR-RenderManager-NVIDIA @@ -1 +1 @@ -Subproject commit 883686bcb1259c482402f35c531f36c1c25efece +Subproject commit ee7dc6c57502b138b3079b9e70c92fb0e7a0d03b diff --git a/osvr/RenderKit/RenderManagerBase.cpp b/osvr/RenderKit/RenderManagerBase.cpp index 34b6fc6..e988f60 100644 --- a/osvr/RenderKit/RenderManagerBase.cpp +++ b/osvr/RenderKit/RenderManagerBase.cpp @@ -2335,8 +2335,15 @@ namespace renderkit { // DirectMode interface as well. if (p.m_asynchronousTimeWarp) { RenderManager::ConstructorParameters pTemp = p; + pTemp.m_verticalSync = false; + pTemp.m_verticalSyncBlocksRendering = false; + pTemp.m_maxMSBeforeVsyncTimeWarp = 0; + pTemp.m_enableTimeWarp = true; + pTemp.m_asynchronousTimeWarp = false; pTemp.m_graphicsLibrary.D3D11 = nullptr; + auto wrappedRm = openRenderManagerDirectMode(contextParameter, pTemp); + wrappedRm->m_vsyncBlockAfterFrameBufferPresent = true; ret.reset(new RenderManagerD3D11ATW(contextParameter, p, wrappedRm)); } else { diff --git a/osvr/RenderKit/RenderManagerD3D11ATW.h b/osvr/RenderKit/RenderManagerD3D11ATW.h index eb14ca5..6e67ced 100644 --- a/osvr/RenderKit/RenderManagerD3D11ATW.h +++ b/osvr/RenderKit/RenderManagerD3D11ATW.h @@ -298,6 +298,7 @@ namespace osvr { void threadFunc() { // Used to make sure we don't take too long to render + m_log->info() << "RenderManagerD3D11ATW::threadFunc thread id: " << std::this_thread::get_id() << std::endl; struct timeval lastFrameTime = {}; bool quit = getQuit(); size_t iteration = 0; @@ -370,6 +371,8 @@ namespace osvr { atwRenderBuffers.push_back(bufferInfoItr->second.atwBuffer); } + //m_log->info() << "RenderManagerD3D11ATW::threadFunc: presenting frame to internal backend."; + // Send the rendered results to the screen, using the // RenderInfo that was handed to us by the client the last // time they gave us some images. @@ -386,6 +389,8 @@ namespace osvr { mQuit = true; } + //m_log->info() << "RenderManagerD3D11ATW::threadFunc: finished presenting frame to internal backend."; + struct timeval now; vrpn_gettimeofday(&now, nullptr); if (expectedFrameInterval >= 0 && lastFrameTime.tv_sec != 0) { diff --git a/osvr/RenderKit/RenderManagerD3DBase.h b/osvr/RenderKit/RenderManagerD3DBase.h index 59df65f..c2b4dc9 100644 --- a/osvr/RenderKit/RenderManagerD3DBase.h +++ b/osvr/RenderKit/RenderManagerD3DBase.h @@ -93,6 +93,12 @@ namespace renderkit { bool m_displayOpen; ///< Has our display been opened? + /// Block until vsync after a framebuffer or direct mode present, even if + /// parameters say not to. This is used by the ATW wrapper to do a more + /// fine-grained blocking (no blocking before present, but yes blocking after) + /// TODO: Could this be added as a new parameter? Might be a breaking change if so. + bool m_vsyncBlockAfterFrameBufferPresent = false; + /// The adapter, if and only if explicitly set. Microsoft::WRL::ComPtr m_adapter; @@ -208,6 +214,12 @@ namespace renderkit { friend class RenderManagerD3D11OpenGL; friend class RenderManagerD3D11ATW; friend class ::sensics::compositor::DisplayServerInterfaceD3D11Singleton; + + // needed to access m_vsyncBlockAfterFrameBufferPresent from createRenderManager + // TODO: if this is added as a parameter (breaking change), then this isn't needed anymore and should be removed. + friend RenderManager* createRenderManager(OSVR_ClientContext contextParameter, + const std::string& renderLibraryName, + GraphicsLibrary graphicsLibrary); }; } // namespace renderkit From 290553b48bc4325e67277db7a1508e354bf1a3ff Mon Sep 17 00:00:00 2001 From: Jeremy Bell Date: Fri, 17 Nov 2017 18:03:52 -0500 Subject: [PATCH 3/5] Fixed condition variable bug. --- osvr/RenderKit/RenderManagerBase.cpp | 2 +- osvr/RenderKit/RenderManagerD3D11ATW.h | 163 +++++++++++++------------ 2 files changed, 83 insertions(+), 82 deletions(-) diff --git a/osvr/RenderKit/RenderManagerBase.cpp b/osvr/RenderKit/RenderManagerBase.cpp index e988f60..674c106 100644 --- a/osvr/RenderKit/RenderManagerBase.cpp +++ b/osvr/RenderKit/RenderManagerBase.cpp @@ -2335,7 +2335,7 @@ namespace renderkit { // DirectMode interface as well. if (p.m_asynchronousTimeWarp) { RenderManager::ConstructorParameters pTemp = p; - pTemp.m_verticalSync = false; + pTemp.m_verticalSync = true; pTemp.m_verticalSyncBlocksRendering = false; pTemp.m_maxMSBeforeVsyncTimeWarp = 0; pTemp.m_enableTimeWarp = true; diff --git a/osvr/RenderKit/RenderManagerD3D11ATW.h b/osvr/RenderKit/RenderManagerD3D11ATW.h index 6e67ced..cf07639 100644 --- a/osvr/RenderKit/RenderManagerD3D11ATW.h +++ b/osvr/RenderKit/RenderManagerD3D11ATW.h @@ -190,7 +190,7 @@ namespace osvr { // rendering will get moving right away. // @todo Enable overlapped rendering on one frame while presentation // of the previous by doing this waiting on another thread. - WaitForRenderCompletion(); + //WaitForRenderCompletion(); { // Adding block to scope the lock_guard. // Lock our mutex so we don't adjust the buffers while rendering is happening. @@ -254,14 +254,14 @@ namespace osvr { mNextFrameInfo.normalizedCroppingViewports = normalizedCroppingViewports; mFirstFramePresented = true; mNextFrameAvailable = true; + //m_log->info() << "RenderManagerD3D11ATW::PresentFrameInternal: Queued next frame info, waiting for it to be presented..."; } - //m_log->info() << "RenderManagerD3D11ATW::PresentFrameInternal: Queued next frame info, waiting for it to be presented..."; { std::unique_lock lock(mMutex); mPresentFinishedCV.wait(lock, [this] { return !mNextFrameAvailable; }); + //m_log->info() << "RenderManagerD3D11ATW::PresentFrameInternal: Finished waiting for the frame to be presented."; } - //m_log->info() << "RenderManagerD3D11ATW::PresentFrameInternal: Finished waiting for the frame to be presented."; return true; } @@ -347,86 +347,87 @@ namespace osvr { } if (timeToPresent) { - // Lock our mutex so that we're not rendering while new buffers are - // being presented. - std::lock_guard lock(mMutex); - if (mFirstFramePresented) { - // Update the context so we get our callbacks called and - // update tracker state, which will be read during the - // time-warp calculation in our harnessed RenderManager. - osvrClientUpdate(mRenderManager->m_context); - - // make a new RenderBuffers array with the atw thread's buffers - std::vector atwRenderBuffers; - for (size_t i = 0; i < mNextFrameInfo.colorBuffers.size(); i++) { - auto key = mNextFrameInfo.colorBuffers[i]; - auto bufferInfoItr = mBufferMap.find(key); - if (bufferInfoItr == mBufferMap.end()) { - m_log->error() << "No buffer info for key " << (size_t)key; - setDoingOkay(false); - mQuit = true; - break; - } - - atwRenderBuffers.push_back(bufferInfoItr->second.atwBuffer); - } - - //m_log->info() << "RenderManagerD3D11ATW::threadFunc: presenting frame to internal backend."; - - // Send the rendered results to the screen, using the - // RenderInfo that was handed to us by the client the last - // time they gave us some images. - if (!mRenderManager->PresentRenderBuffers( - atwRenderBuffers, - mNextFrameInfo.renderInfo, - mNextFrameInfo.renderParams, - mNextFrameInfo.normalizedCroppingViewports, - mNextFrameInfo.flipInY)) { - /// @todo if this might be intentional (expected) - shouldn't be an error... - m_log->error() - << "PresentRenderBuffers() returned false, maybe because it was asked to quit"; - setDoingOkay(false); - mQuit = true; - } - - //m_log->info() << "RenderManagerD3D11ATW::threadFunc: finished presenting frame to internal backend."; - - struct timeval now; - vrpn_gettimeofday(&now, nullptr); - if (expectedFrameInterval >= 0 && lastFrameTime.tv_sec != 0) { - double frameInterval = vrpn_TimevalDurationSeconds(now, lastFrameTime); - if (frameInterval > expectedFrameInterval * 1.9) { - m_log->info() << "RenderManagerThread::threadFunc(): Missed" - " 1+ frame at " << iteration << - ", expected interval " << expectedFrameInterval * 1e3 - << "ms but got " << frameInterval * 1e3; - m_log->info() << " (PresentRenderBuffers took " - << mRenderManager->timePresentRenderBuffers * 1e3 - << "ms)"; - m_log->info() << " (FrameInit " - << mRenderManager->timePresentFrameInitialize * 1e3 - << ", WaitForSync " - << mRenderManager->timeWaitForSync * 1e3 - << ", DisplayInit " - << mRenderManager->timePresentDisplayInitialize * 1e3 - << ", PresentEye " - << mRenderManager->timePresentEye * 1e3 - << ", DisplayFinal " - << mRenderManager->timePresentDisplayFinalize * 1e3 - << ", FrameFinal " - << mRenderManager->timePresentFrameFinalize * 1e3 - << ")"; - } - } - lastFrameTime = now; - - iteration++; - - mNextFrameAvailable = false; - } + { + // Lock our mutex so that we're not rendering while new buffers are + // being presented. + std::lock_guard lock(mMutex); + if (mFirstFramePresented) { + // Update the context so we get our callbacks called and + // update tracker state, which will be read during the + // time-warp calculation in our harnessed RenderManager. + osvrClientUpdate(mRenderManager->m_context); + + // make a new RenderBuffers array with the atw thread's buffers + std::vector atwRenderBuffers; + for (size_t i = 0; i < mNextFrameInfo.colorBuffers.size(); i++) { + auto key = mNextFrameInfo.colorBuffers[i]; + auto bufferInfoItr = mBufferMap.find(key); + if (bufferInfoItr == mBufferMap.end()) { + m_log->error() << "No buffer info for key " << (size_t)key; + setDoingOkay(false); + mQuit = true; + break; + } + + atwRenderBuffers.push_back(bufferInfoItr->second.atwBuffer); + } + + //m_log->info() << "RenderManagerD3D11ATW::threadFunc: presenting frame to internal backend."; + + // Send the rendered results to the screen, using the + // RenderInfo that was handed to us by the client the last + // time they gave us some images. + if (!mRenderManager->PresentRenderBuffers( + atwRenderBuffers, + mNextFrameInfo.renderInfo, + mNextFrameInfo.renderParams, + mNextFrameInfo.normalizedCroppingViewports, + mNextFrameInfo.flipInY)) { + /// @todo if this might be intentional (expected) - shouldn't be an error... + m_log->error() + << "PresentRenderBuffers() returned false, maybe because it was asked to quit"; + setDoingOkay(false); + mQuit = true; + } + + //m_log->info() << "RenderManagerD3D11ATW::threadFunc: finished presenting frame to internal backend."; + + struct timeval now; + vrpn_gettimeofday(&now, nullptr); + if (expectedFrameInterval >= 0 && lastFrameTime.tv_sec != 0) { + double frameInterval = vrpn_TimevalDurationSeconds(now, lastFrameTime); + if (frameInterval > expectedFrameInterval * 1.9) { + m_log->info() << "RenderManagerThread::threadFunc(): Missed" + " 1+ frame at " << iteration << + ", expected interval " << expectedFrameInterval * 1e3 + << "ms but got " << frameInterval * 1e3; + m_log->info() << " (PresentRenderBuffers took " + << mRenderManager->timePresentRenderBuffers * 1e3 + << "ms)"; + m_log->info() << " (FrameInit " + << mRenderManager->timePresentFrameInitialize * 1e3 + << ", WaitForSync " + << mRenderManager->timeWaitForSync * 1e3 + << ", DisplayInit " + << mRenderManager->timePresentDisplayInitialize * 1e3 + << ", PresentEye " + << mRenderManager->timePresentEye * 1e3 + << ", DisplayFinal " + << mRenderManager->timePresentDisplayFinalize * 1e3 + << ", FrameFinal " + << mRenderManager->timePresentFrameFinalize * 1e3 + << ")"; + } + } + lastFrameTime = now; + + iteration++; + + mNextFrameAvailable = false; + } + } mPresentFinishedCV.notify_all(); } - quit = mQuit; } } From 7b66b0cba219b5db33be0231371b76b220f88ebb Mon Sep 17 00:00:00 2001 From: Jeremy Bell Date: Mon, 20 Nov 2017 12:09:08 -0500 Subject: [PATCH 4/5] Reverted change to comment out WaitForRenderCompletion in the D3D11ATW backend and some commented out code in the D3D11 ATW double buffer example --- examples/RenderManagerD3DATWDoubleBufferExample.cpp | 4 +--- osvr/RenderKit/RenderManagerD3D11ATW.h | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/RenderManagerD3DATWDoubleBufferExample.cpp b/examples/RenderManagerD3DATWDoubleBufferExample.cpp index fd69f3f..713b9e5 100644 --- a/examples/RenderManagerD3DATWDoubleBufferExample.cpp +++ b/examples/RenderManagerD3DATWDoubleBufferExample.cpp @@ -118,9 +118,7 @@ void RenderView( // draw room simpleShader.use(device, context, xm_projectionD3D, xm_viewD3D, identity); - //for (size_t i = 0; i < 10000; i++) { - roomCube.draw(device, context); - //} + roomCube.draw(device, context); } void Usage(std::string name) { diff --git a/osvr/RenderKit/RenderManagerD3D11ATW.h b/osvr/RenderKit/RenderManagerD3D11ATW.h index cf07639..ab74484 100644 --- a/osvr/RenderKit/RenderManagerD3D11ATW.h +++ b/osvr/RenderKit/RenderManagerD3D11ATW.h @@ -190,7 +190,7 @@ namespace osvr { // rendering will get moving right away. // @todo Enable overlapped rendering on one frame while presentation // of the previous by doing this waiting on another thread. - //WaitForRenderCompletion(); + WaitForRenderCompletion(); { // Adding block to scope the lock_guard. // Lock our mutex so we don't adjust the buffers while rendering is happening. From 9675115a6c41755f30e4f231dd25a9ecd5e7cdde Mon Sep 17 00:00:00 2001 From: Jeremy Bell Date: Thu, 30 Nov 2017 17:36:58 -0500 Subject: [PATCH 5/5] NVidia ATW backend now respects the server config for blocking on present. --- osvr/RenderKit/RenderManagerD3D11ATW.h | 1 + 1 file changed, 1 insertion(+) diff --git a/osvr/RenderKit/RenderManagerD3D11ATW.h b/osvr/RenderKit/RenderManagerD3D11ATW.h index ab74484..b03cc74 100644 --- a/osvr/RenderKit/RenderManagerD3D11ATW.h +++ b/osvr/RenderKit/RenderManagerD3D11ATW.h @@ -257,6 +257,7 @@ namespace osvr { //m_log->info() << "RenderManagerD3D11ATW::PresentFrameInternal: Queued next frame info, waiting for it to be presented..."; } + if(m_params.m_verticalSyncBlocksRendering) { std::unique_lock lock(mMutex); mPresentFinishedCV.wait(lock, [this] { return !mNextFrameAvailable; });