diff --git a/examples/RenderManagerD3DATWDoubleBufferExample.cpp b/examples/RenderManagerD3DATWDoubleBufferExample.cpp index ecf7fe9..713b9e5 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; @@ -117,7 +118,7 @@ void RenderView( // draw room simpleShader.use(device, context, xm_projectionD3D, xm_viewD3D, identity); - roomCube.draw(device, context); + roomCube.draw(device, context); } void Usage(std::string name) { @@ -135,8 +136,10 @@ struct FrameInfo { }; int main(int argc, char* argv[]) { + 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 d33dff3..686ece6 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,7 @@ void Usage(std::string name) { } int main(int argc, char* argv[]) { + 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 +150,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 +260,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,13 +272,11 @@ 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 = {}; - 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; @@ -317,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; @@ -370,8 +385,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 +413,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 +422,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 +430,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/NDA/OSVR-RenderManager-NVIDIA b/osvr/RenderKit/NDA/OSVR-RenderManager-NVIDIA index faa429a..ae7bf1c 160000 --- a/osvr/RenderKit/NDA/OSVR-RenderManager-NVIDIA +++ b/osvr/RenderKit/NDA/OSVR-RenderManager-NVIDIA @@ -1 +1 @@ -Subproject commit faa429a9556415aba872d2d833fb32b8b5627dd1 +Subproject commit ae7bf1ce10848ae20facd805cbe593e9f5f9a092 diff --git a/osvr/RenderKit/RenderManagerBase.cpp b/osvr/RenderKit/RenderManagerBase.cpp index ee420d4..889986c 100644 --- a/osvr/RenderKit/RenderManagerBase.cpp +++ b/osvr/RenderKit/RenderManagerBase.cpp @@ -2338,8 +2338,15 @@ namespace renderkit { // DirectMode interface as well. if (p.m_asynchronousTimeWarp) { RenderManager::ConstructorParameters pTemp = p; + pTemp.m_verticalSync = true; + 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 608bf6f..b03cc74 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,17 @@ 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..."; } + + if(m_params.m_verticalSyncBlocksRendering) + { + 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 +285,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,12 +293,13 @@ namespace osvr { } bool getQuit() { - std::lock_guard lock(mLock); + std::lock_guard lock(mMutex); return mQuit; } 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; @@ -334,79 +348,87 @@ namespace osvr { } if (timeToPresent) { - // Lock our mutex so that we're not rendering while new buffers are - // being presented. - std::lock_guard lock(mLock); - 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); - } - - // 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; - } - - 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++; - } + { + // 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; } } @@ -425,7 +447,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 +599,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; } } 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