<commit_before>/** @file
@brief Header file describing the OSVR direct-to-device rendering interface

@date 2016

@author
Sensics, Inc.
<http://sensics.com/osvr>
*/

// Copyright 2016 Sensics, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once
#include <osvr/ClientKit/Context.h>
#include <osvr/ClientKit/Interface.h>
#include "RenderManagerD3DBase.h"
#include "RenderManagerOpenGL.h"
#include "GraphicsLibraryD3D11.h"

#include <vector>
#include <string>
#include <thread>
#include <mutex>
#include <functional>
#include <map>

namespace osvr {
    namespace renderkit {

        class RenderManagerD3D11ATW : public RenderManagerD3D11Base {
        private:
            // Indices into the keys for the Render Thread
            const UINT rtAcqKey = 0;
            const UINT rtRelKey = 1;
            // Indices into the keys for the ATW thread
            const UINT acqKey = 1;
            const UINT relKey = 0;

            /// Holds the information needed to handle locking and unlocking of
            /// buffers and also the copying of buffers in the case where we have
            /// our own internal copy.
            typedef struct {
                osvr::renderkit::RenderBuffer atwBuffer;
                IDXGIKeyedMutex* rtMutex;
                IDXGIKeyedMutex* atwMutex;
                HANDLE sharedResourceHandle;
                ID3D11Texture2D *textureCopy;   //< nullptr if no copy needed.
            } RenderBufferATWInfo;
            std::map<osvr::renderkit::RenderBufferD3D11*, RenderBufferATWInfo> mBufferMap;

            std::mutex mLock;
            std::shared_ptr<std::thread> 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
            /// simultaneous use in both threads.
            struct {
                std::vector<osvr::renderkit::RenderBuffer> renderBuffers;
                std::vector<osvr::renderkit::RenderInfo> renderInfo;
                std::vector<OSVR_ViewportDescription> normalizedCroppingViewports;
                RenderParams renderParams;
                bool flipInY;
            } mNextFrameInfo;

            bool mQuit = false;
            bool mStarted = false;
            bool mFirstFramePresented = false;

        public:
            /**
            * Construct an D3D ATW wrapper around an existing D3D render
            * manager. Takes ownership of the passed in render manager
            * and deletes it when the wrapper is deleted.
            */
            RenderManagerD3D11ATW(
                OSVR_ClientContext context,
                ConstructorParameters p, RenderManagerD3D11Base* D3DToHarness)
                : RenderManagerD3D11Base(context, p) {
                mRenderManager.reset(D3DToHarness);
            }

            virtual ~RenderManagerD3D11ATW() {
                if (mThread) {
                    stop();
                    mThread->join();
                }
                // Delete textures and views that we allocated or otherwise opened
                std::map<osvr::renderkit::RenderBufferD3D11*, RenderBufferATWInfo>::iterator i;
                for (i = mBufferMap.begin(); i != mBufferMap.end(); i++) {
                  i->second.atwBuffer.D3D11->colorBuffer->Release();
                  i->second.atwBuffer.D3D11->colorBufferView->Release();
                  if (i->second.textureCopy != nullptr) {
                    i->second.textureCopy->Release();
                  }
                }
            }

            OpenResults OpenDisplay() override {
                std::lock_guard<std::mutex> lock(mLock);

                OpenResults ret;

                // Set the device and context we're going to use
                // but don't open an additional display -- we're
                // going to pass all display-related things down to
                // our render thread.
                // @todo Consider whether we want to just return
                // the device and context of our render-thread's
                // RenderManager
                if (!SetDeviceAndContext()) {
                  std::cerr << "RenderManagerD3D11ATW::OpenDisplay: Could not "
                    "create device and context"
                    << std::endl;
                  ret.status = OpenStatus::FAILURE;
                  return ret;
                }

                // Try to open the display in the harnessed
                // RenderManager.  Return false if it fails.
                ret = mRenderManager->OpenDisplay();
                if (ret.status == OpenStatus::FAILURE) {
                  std::cerr << "RenderManagerD3D11ATW::OpenDisplay: Could not "
                    "open display in harnessed RenderManager"
                    << std::endl;
                  return ret;
                }

                //======================================================
                // Start our ATW sub-thread.
                start();

                //======================================================
                // Fill in our library with the things the application may need to
                // use to do its graphics state set-up.
                m_library.D3D11->device = m_D3D11device;
                m_library.D3D11->context = m_D3D11Context;

                // Fill in our library, rather than that of
                // the harnessed RenderManager, since this is the one
                // that the client will deal with.
                ret.library = m_library;
                return ret;
            }

        protected:

          bool OSVR_RENDERMANAGER_EXPORT
            PresentRenderBuffersInternal(const std::vector<RenderBuffer>& renderBuffers,
                const std::vector<RenderInfo>& renderInfoUsed,
                const RenderParams& renderParams = RenderParams(),
                const std::vector<OSVR_ViewportDescription>& normalizedCroppingViewports =
                  std::vector<OSVR_ViewportDescription>(),
                bool flipInY = false) override {

                  // Lock our mutex so we don't adjust the buffers while rendering is happening.
                  std::lock_guard<std::mutex> lock(mLock);
                  HRESULT hr;

                  // For all the buffers that have been given to the ATW thread,
                  // release them there and acquire them back for the render thread.
                  // This starts us with the render thread owning all of the buffers.
                  // Then clear the buffer list that is owned by the ATW thread.
                  for (size_t i = 0; i < mNextFrameInfo.renderBuffers.size(); i++) {
                    auto key = mNextFrameInfo.renderBuffers[i].D3D11;
                    auto bufferInfoItr = mBufferMap.find(key);
                    if (bufferInfoItr == mBufferMap.end()) {
                      std::cerr << "No Buffer info for key " << (size_t)key << std::endl;
                      m_doingOkay = false;
                      mQuit = true;
                    }
                    auto bufferInfo = bufferInfoItr->second;
                    //std::cerr << "releasing atwMutex " << (size_t)key << std::endl;
                    hr = bufferInfoItr->second.atwMutex->ReleaseSync(relKey);
                    if (FAILED(hr)) {
                      std::cerr << "Could not ReleaseSync in the render manager thread." << std::endl;
                      m_doingOkay = false;
                      mQuit = true;
                    }
                    //std::cerr << "acquiring rtMutex " << (size_t)key << std::endl;
                    hr = bufferInfoItr->second.rtMutex->AcquireSync(rtAcqKey, INFINITE);
                    if (FAILED(hr)) {
                      std::cerr << "Could not lock the render thread's mutex" << std::endl;
                      m_doingOkay = false;
                      mQuit = true;
                    }
                  }
                  mNextFrameInfo.renderBuffers.clear();

                  // If we have non-NULL texture-copy pointers in any of the buffers
                  // associated with the presented buffers, copy the texture into
                  // the associated buffer.  This is to handle the case where the client
                  // did not promise not to overwrite the texture before it is presented.
                  for (size_t i = 0; i < renderBuffers.size(); i++) {
                    auto key = renderBuffers[i].D3D11;
                    auto bufferInfoItr = mBufferMap.find(key);
                    if (bufferInfoItr == mBufferMap.end()) {
                      std::cerr << "Could not find buffer info for RenderBuffer " << (size_t)key << std::endl;
                      m_doingOkay = false;
                      return false;
                    }

                    if (bufferInfoItr->second.textureCopy != nullptr) {
                      m_D3D11Context->CopyResource(bufferInfoItr->second.textureCopy,
                        renderBuffers[i].D3D11->colorBuffer);
                    }
                  }

                  // For all of the buffers we're getting ready to hand to the ATW thread,
                  // we release our lock and lock them for that thread and then push them
                  // onto the vector for use by that thread.
                  for (size_t i = 0; i < renderBuffers.size(); i++) {
                      // We need to unlock the render thread's mutex (remember they're locked initially)
                      auto key = renderBuffers[i].D3D11;
                      //std::cerr << "releasing rtMutex " << (size_t)key << std::endl;
                      auto bufferInfoItr = mBufferMap.find(key);
                      if (bufferInfoItr == mBufferMap.end()) {
                          std::cerr << "Could not find buffer info for RenderBuffer " << (size_t)key << std::endl;
                          m_doingOkay = false;
                          return false;
                      }
                      hr = bufferInfoItr->second.rtMutex->ReleaseSync(rtRelKey);
                      if (FAILED(hr)) {
                          std::cerr << "Could not ReleaseSync on a client render target's IDXGIKeyedMutex during present." << std::endl;
                          m_doingOkay = false;
                          return false;
                      }
                      // and lock the ATW thread's mutex
                      //std::cerr << "locking atwMutex " << (size_t)key << std::endl;
                      hr = bufferInfoItr->second.atwMutex->AcquireSync(rtRelKey, INFINITE);
                      if (FAILED(hr)) {
                          std::cerr << "Could not AcquireSync on the atw IDXGIKeyedMutex during present.";
                          m_doingOkay = false;
                          return false;
                      }
                      mNextFrameInfo.renderBuffers.push_back(renderBuffers[i]);
                  }
                  mFirstFramePresented = true;
                  mNextFrameInfo.renderInfo = renderInfoUsed;
                  mNextFrameInfo.flipInY = flipInY;
                  mNextFrameInfo.renderParams = renderParams;
                  mNextFrameInfo.normalizedCroppingViewports = normalizedCroppingViewports;
                  return true;
            }

            void start() {
                if (mStarted) {
                    std::cerr << "RenderManagerThread::start() - thread loop already started." << std::endl;
                } else {
                    mThread.reset(new std::thread(std::bind(&RenderManagerD3D11ATW::threadFunc, this)));
                }
                mStarted = true;
            }

            void stop() {
                std::lock_guard<std::mutex> lock(mLock);<commit_msg>Whitespace and comment changes.  Removal of DLL linkage flag that is not needed for a protected function.<commit_after>/** @file
@brief Header file describing the OSVR direct-to-device rendering interface

@date 2016

@author
Sensics, Inc.
<http://sensics.com/osvr>
*/

// Copyright 2016 Sensics, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once
#include <osvr/ClientKit/Context.h>
#include <osvr/ClientKit/Interface.h>
#include "RenderManagerD3DBase.h"
#include "RenderManagerOpenGL.h"
#include "GraphicsLibraryD3D11.h"

#include <vector>
#include <string>
#include <thread>
#include <mutex>
#include <functional>
#include <map>

namespace osvr {
    namespace renderkit {

        class RenderManagerD3D11ATW : public RenderManagerD3D11Base {
        private:
            // Indices into the keys for the Render Thread
            const UINT rtAcqKey = 0;
            const UINT rtRelKey = 1;
            // Indices into the keys for the ATW thread
            const UINT acqKey = 1;
            const UINT relKey = 0;

            /// Holds the information needed to handle locking and unlocking of
            /// buffers and also the copying of buffers in the case where we have
            /// our own internal copy.
            typedef struct {
                osvr::renderkit::RenderBuffer atwBuffer;
                IDXGIKeyedMutex* rtMutex;
                IDXGIKeyedMutex* atwMutex;
                HANDLE sharedResourceHandle;
                ID3D11Texture2D *textureCopy;   //< nullptr if no copy needed.
            } RenderBufferATWInfo;
            std::map<osvr::renderkit::RenderBufferD3D11*, RenderBufferATWInfo> mBufferMap;

            std::mutex mLock;
            std::shared_ptr<std::thread> 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
            /// simultaneous use in both threads.
            struct {
                std::vector<osvr::renderkit::RenderBuffer> renderBuffers;
                std::vector<osvr::renderkit::RenderInfo> renderInfo;
                std::vector<OSVR_ViewportDescription> normalizedCroppingViewports;
                RenderParams renderParams;
                bool flipInY;
            } mNextFrameInfo;

            bool mQuit = false;
            bool mStarted = false;
            bool mFirstFramePresented = false;

        public:
            /**
            * Construct an D3D ATW wrapper around an existing D3D render
            * manager. Takes ownership of the passed in render manager
            * and deletes it when the wrapper is deleted.
            */
            RenderManagerD3D11ATW(
                OSVR_ClientContext context,
                ConstructorParameters p, RenderManagerD3D11Base* D3DToHarness)
                : RenderManagerD3D11Base(context, p) {
                mRenderManager.reset(D3DToHarness);
            }

            virtual ~RenderManagerD3D11ATW() {
                if (mThread) {
                    stop();
                    mThread->join();
                }
                // Delete textures and views that we allocated or otherwise opened
                std::map<osvr::renderkit::RenderBufferD3D11*, RenderBufferATWInfo>::iterator i;
                for (i = mBufferMap.begin(); i != mBufferMap.end(); i++) {
                  i->second.atwBuffer.D3D11->colorBuffer->Release();
                  i->second.atwBuffer.D3D11->colorBufferView->Release();
                  if (i->second.textureCopy != nullptr) {
                    i->second.textureCopy->Release();
                  }
                }
            }

            OpenResults OpenDisplay() override {
                std::lock_guard<std::mutex> lock(mLock);

                OpenResults ret;

                // Set the device and context we're going to use
                // but don't open an additional display -- we're
                // going to pass all display-related things down to
                // our render thread.
                if (!SetDeviceAndContext()) {
                  std::cerr << "RenderManagerD3D11ATW::OpenDisplay: Could not "
                    "create device and context"
                    << std::endl;
                  ret.status = OpenStatus::FAILURE;
                  return ret;
                }

                // Try to open the display in the harnessed
                // RenderManager.  Return false if it fails.
                ret = mRenderManager->OpenDisplay();
                if (ret.status == OpenStatus::FAILURE) {
                  std::cerr << "RenderManagerD3D11ATW::OpenDisplay: Could not "
                    "open display in harnessed RenderManager"
                    << std::endl;
                  return ret;
                }

                //======================================================
                // Start our ATW sub-thread.
                start();

                //======================================================
                // Fill in our library with the things the application may need to
                // use to do its graphics state set-up.
                m_library.D3D11->device = m_D3D11device;
                m_library.D3D11->context = m_D3D11Context;

                // Fill in our library, rather than that of
                // the harnessed RenderManager, since this is the one
                // that the client will deal with.
                ret.library = m_library;
                return ret;
            }

        protected:

          bool
            PresentRenderBuffersInternal(const std::vector<RenderBuffer>& renderBuffers,
                const std::vector<RenderInfo>& renderInfoUsed,
                const RenderParams& renderParams = RenderParams(),
                const std::vector<OSVR_ViewportDescription>& normalizedCroppingViewports =
                  std::vector<OSVR_ViewportDescription>(),
                bool flipInY = false) override {

                  // Lock our mutex so we don't adjust the buffers while rendering is happening.
                  std::lock_guard<std::mutex> lock(mLock);
                  HRESULT hr;

                  // For all the buffers that have been given to the ATW thread,
                  // release them there and acquire them back for the render thread.
                  // This starts us with the render thread owning all of the buffers.
                  // Then clear the buffer list that is owned by the ATW thread.
                  for (size_t i = 0; i < mNextFrameInfo.renderBuffers.size(); i++) {
                    auto key = mNextFrameInfo.renderBuffers[i].D3D11;
                    auto bufferInfoItr = mBufferMap.find(key);
                    if (bufferInfoItr == mBufferMap.end()) {
                      std::cerr << "RenderManagerD3D11ATW::PresentRenderBuffersInternal "
                        << "No Buffer info for key " << (size_t)key << std::endl;
                      m_doingOkay = false;
                      mQuit = true;
                    }
                    auto bufferInfo = bufferInfoItr->second;
                    //std::cerr << "releasing atwMutex " << (size_t)key << std::endl;
                    hr = bufferInfoItr->second.atwMutex->ReleaseSync(relKey);
                    if (FAILED(hr)) {
                      std::cerr << "RenderManagerD3D11ATW::PresentRenderBuffersInternal "
                        << "Could not ReleaseSync in the render manager thread." << std::endl;
                      m_doingOkay = false;
                      mQuit = true;
                    }
                    //std::cerr << "acquiring rtMutex " << (size_t)key << std::endl;
                    hr = bufferInfoItr->second.rtMutex->AcquireSync(rtAcqKey, INFINITE);
                    if (FAILED(hr)) {
                      std::cerr << "RenderManagerD3D11ATW::PresentRenderBuffersInternal "
                        << "Could not lock the render thread's mutex" << std::endl;
                      m_doingOkay = false;
                      mQuit = true;
                    }
                  }
                  mNextFrameInfo.renderBuffers.clear();

                  // If we have non-NULL texture-copy pointers in any of the buffers
                  // associated with the presented buffers, copy the texture into
                  // the associated buffer.  This is to handle the case where the client
                  // did not promise not to overwrite the texture before it is presented.
                  for (size_t i = 0; i < renderBuffers.size(); i++) {
                    auto key = renderBuffers[i].D3D11;
                    auto bufferInfoItr = mBufferMap.find(key);
                    if (bufferInfoItr == mBufferMap.end()) {
                      std::cerr << "RenderManagerD3D11ATW::PresentRenderBuffersInternal "
                        << "Could not find buffer info for RenderBuffer " << (size_t)key << std::endl;
                      std::cerr << "  (Be sure to register buffers before presenting them)" << std::endl;
                      m_doingOkay = false;
                      return false;
                    }

                    if (bufferInfoItr->second.textureCopy != nullptr) {
                      m_D3D11Context->CopyResource(bufferInfoItr->second.textureCopy,
                        renderBuffers[i].D3D11->colorBuffer);
                    }
                  }

                  // For all of the buffers we're getting ready to hand to the ATW thread,
                  // we release our lock and lock them for that thread and then push them
                  // onto the vector for use by that thread.
                  for (size_t i = 0; i < renderBuffers.size(); i++) {
                      // We need to unlock the render thread's mutex (remember they're locked initially)
                      auto key = renderBuffers[i].D3D11;
                      //std::cerr << "releasing rtMutex " << (size_t)key << std::endl;
                      auto bufferInfoItr = mBufferMap.find(key);
                      if (bufferInfoItr == mBufferMap.end()) {
                          std::cerr << "RenderManagerD3D11ATW::PresentRenderBuffersInternal "
                            << "Could not find buffer info for RenderBuffer " << (size_t)key << std::endl;
                          std::cerr << "  (Be sure to register buffers before presenting them)" << std::endl;
                          m_doingOkay = false;
                          return false;
                      }
                      hr = bufferInfoItr->second.rtMutex->ReleaseSync(rtRelKey);
                      if (FAILED(hr)) {
                          std::cerr << "RenderManagerD3D11ATW::PresentRenderBuffersInternal "
                            << "Could not ReleaseSync on a client render target's IDXGIKeyedMutex during present." << std::endl;
                          m_doingOkay = false;
                          return false;
                      }
                      // and lock the ATW thread's mutex
                      //std::cerr << "locking atwMutex " << (size_t)key << std::endl;
                      hr = bufferInfoItr->second.atwMutex->AcquireSync(rtRelKey, INFINITE);
                      if (FAILED(hr)) {
                          std::cerr << "RenderManagerD3D11ATW::PresentRenderBuffersInternal "
                            << "Could not AcquireSync on the atw IDXGIKeyedMutex during present.";
                          m_doingOkay = false;
                          return false;
                      }
                      mNextFrameInfo.renderBuffers.push_back(renderBuffers[i]);
                  }
                  mFirstFramePresented = true;
                  mNextFrameInfo.renderInfo = renderInfoUsed;
                  mNextFrameInfo.flipInY = flipInY;
                  mNextFrameInfo.renderParams = renderParams;
                  mNextFrameInfo.normalizedCroppingViewports = normalizedCroppingViewports;
                  return true;
            }

            void start() {
                if (mStarted) {
                    std::cerr << "RenderManagerThread::start() - thread loop already started." << std::endl;
                } else {
                    mThread.reset(new std::thread(std::bind(&RenderManagerD3D11ATW::threadFunc, this)));
                }
                mStarted = true;
            }

            void stop() {
                std::lock_guard<std::mutex> lock(mLock);
{'fraction_non_alphanumeric': 0.09247581371665818, 'fraction_numerical': 0.008421135090674083, 'mean_word_length': 1.5144770533779792, 'pattern_counts': {'":': 0, '<': 213, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '657244', 'n_tokens_mistral': 6585, 'n_tokens_neox': 6111, 'n_words': 1837}