Created
December 17, 2015 17:58
-
-
Save JeroMiya/385abd497a6e282466af to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @file | |
@brief Example program that uses the OSVR direct-to-display interface | |
and D3D to render a scene with low latency. | |
@date 2015 | |
@author | |
Russ Taylor working through ReliaSolve.com for Sensics, Inc. | |
<http://sensics.com/osvr> | |
*/ | |
// Copyright 2015 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. | |
// Internal Includes | |
#include <osvr/ClientKit/Context.h> | |
#include <osvr/ClientKit/Interface.h> | |
#include "osvr/RenderKit/RenderManager.h" | |
// Library/third-party includes | |
#include <windows.h> | |
#include <initguid.h> | |
#include <d3d11.h> | |
#include <wrl.h> | |
#include <DirectXMath.h> | |
// Standard includes | |
#include <iostream> | |
#include <string> | |
#include <stdlib.h> // For exit() | |
#include <thread> | |
#include <mutex> | |
#include <functional> | |
//This must come after we include <d3d11.h> so its pointer types are defined. | |
#include "osvr/RenderKit/GraphicsLibraryD3D11.h" | |
// Includes from our own directory | |
#include "pixelshader3d.h" | |
#include "vertexshader3d.h" | |
using namespace DirectX; | |
#include "D3DCube.h" | |
#include "D3DSimpleShader.h" | |
// Set to true when it is time for the application to quit. | |
// Handlers below that set it to true when the user causes | |
// any of a variety of events so that we shut down the system | |
// cleanly. This only works on Windows, but so does D3D... | |
static bool quit = false; | |
static Cube roomCube(5.0f, true); | |
static SimpleShader simpleShader; | |
#ifdef _WIN32 | |
// Note: On Windows, this runs in a different thread from | |
// the main application. | |
static BOOL CtrlHandler(DWORD fdwCtrlType) | |
{ | |
switch (fdwCtrlType) | |
{ | |
// Handle the CTRL-C signal. | |
case CTRL_C_EVENT: | |
// CTRL-CLOSE: confirm that the user wants to exit. | |
case CTRL_CLOSE_EVENT: | |
case CTRL_BREAK_EVENT: | |
case CTRL_LOGOFF_EVENT: | |
case CTRL_SHUTDOWN_EVENT: | |
quit = true; | |
return TRUE; | |
default: | |
return FALSE; | |
} | |
} | |
#endif | |
// This callback sets a boolean value whose pointer is passed in to | |
// the state of the button that was pressed. This lets the callback | |
// be used to handle any button press that just needs to update state. | |
void myButtonCallback(void *userdata, const OSVR_TimeValue * /*timestamp*/, | |
const OSVR_ButtonReport *report) | |
{ | |
bool *result = static_cast<bool*>(userdata); | |
*result = (report->state != 0); | |
} | |
// Callbacks to draw things in world space, left-hand space, and right-hand | |
// space. | |
void RenderView( | |
const osvr::renderkit::RenderInfo &renderInfo //< Info needed to render | |
, ID3D11RenderTargetView *renderTargetView | |
, ID3D11DepthStencilView *depthStencilView | |
, ID3D11Device *device | |
, ID3D11DeviceContext *context | |
) | |
{ | |
// Make sure our pointers are filled in correctly. The config file selects | |
// the graphics library to use, and may not match our needs. | |
if (renderInfo.library.D3D11 == nullptr) { | |
std::cerr << "SetupDisplay: No D3D11 GraphicsLibrary, this should not happen" << std::endl; | |
return; | |
} | |
//auto context = renderInfo.library.D3D11->context; | |
//auto device = renderInfo.library.D3D11->device; | |
float projectionD3D[16]; | |
float viewD3D[16]; | |
XMMATRIX identity = XMMatrixIdentity(); | |
// Set up to render to the textures for this eye | |
context->OMSetRenderTargets(1, &renderTargetView, depthStencilView); | |
// Set up the viewport we're going to draw into. | |
CD3D11_VIEWPORT viewport( | |
static_cast<float>(renderInfo.viewport.left), | |
static_cast<float>(renderInfo.viewport.lower), | |
static_cast<float>(renderInfo.viewport.width), | |
static_cast<float>(renderInfo.viewport.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); | |
osvr::renderkit::OSVR_PoseState_to_D3D(viewD3D, renderInfo.pose); | |
osvr::renderkit::OSVR_Projection_to_D3D(projectionD3D, renderInfo.projection); | |
XMMATRIX _projectionD3D(projectionD3D), _viewD3D(viewD3D); | |
// draw room | |
simpleShader.use(device, context, _projectionD3D, _viewD3D, identity); | |
roomCube.draw(device, context); | |
} | |
void Usage(std::string name) | |
{ | |
std::cerr << "Usage: " << name << std::endl; | |
exit(-1); | |
} | |
class RenderManagerThread | |
{ | |
private: | |
std::shared_ptr<osvr::renderkit::RenderManager> mRenderManager = nullptr; | |
std::mutex mLock; | |
std::shared_ptr<std::thread> mThread = nullptr; | |
osvr::clientkit::ClientContext *mContext; | |
bool mQuit = false; | |
bool mHaveBuffer = false; | |
bool mStarted = false; | |
std::vector<osvr::renderkit::RenderBuffer> mRenderBuffers; | |
std::vector<IDXGIKeyedMutex *> mKeyedMutexes; | |
std::vector<osvr::renderkit::RenderInfo> *mRenderInfo; | |
public: | |
RenderManagerThread(osvr::clientkit::ClientContext *context) { | |
mContext = context; | |
// Open Direct3D and set up the context for rendering to | |
// an HMD. Do this using the OSVR RenderManager interface, | |
// which maps to the nVidia or other vendor direct mode | |
// to reduce the latency. | |
mRenderManager.reset( | |
osvr::renderkit::createRenderManager(context->get(), "Direct3D11")); | |
if (mRenderManager == nullptr || !mRenderManager->doingOkay()) { | |
std::cerr << "Could not create RenderManager" << std::endl; | |
throw std::exception("Could not create RenderManager"); | |
} | |
// Open the display and make sure this worked. | |
osvr::renderkit::RenderManager::OpenResults ret = mRenderManager->OpenDisplay(); | |
if (ret.status == osvr::renderkit::RenderManager::OpenStatus::FAILURE) { | |
std::cerr << "Could not open display" << std::endl; | |
throw std::exception("Could not open display"); | |
} | |
std::cerr << "Successfully opened direct mode display." << std::endl; | |
if (ret.library.D3D11 == nullptr) { | |
std::cerr << "Attempted to run a Direct3D11 program with a config file " | |
<< "that specified a different rendering library." << std::endl; | |
throw std::exception("Attempted to run a Direct3D11 program with a config file " | |
"that specified a different rendering library."); | |
} | |
} | |
~RenderManagerThread() { | |
if (mThread) { | |
stop(); | |
mThread->join(); | |
} | |
} | |
std::vector<osvr::renderkit::RenderInfo> GetRenderInfo() { | |
std::lock_guard<std::mutex> lock(mLock); | |
return mRenderManager->GetRenderInfo(); | |
} | |
bool RegisterRenderBuffers( | |
std::vector<HANDLE> &sharedHandles, | |
bool appWillNotOverwriteBeforeNewPresent = false) { | |
if (mRenderBuffers.size() > 0) { | |
std::cerr << "Only call RenderManagerThread::RegisterRenderBuffers once." << std::endl; | |
return false; | |
} | |
std::vector<osvr::renderkit::RenderInfo> renderInfo = GetRenderInfo(); | |
for (size_t i = 0; i < sharedHandles.size(); i++) { | |
auto device = renderInfo[i].library.D3D11->device; | |
ID3D11Texture2D *texture2D = nullptr; | |
auto hr = device->OpenSharedResource(sharedHandles[i], __uuidof(ID3D11Texture2D), | |
(LPVOID*)&texture2D); | |
if (FAILED(hr)) { | |
std::cerr << "RenderManagerThread::RegisterRenderBuffers() - failed to open shared resource." << std::endl; | |
return false; | |
} | |
IDXGIKeyedMutex *dxgiKeyedMutex = nullptr; | |
hr = texture2D->QueryInterface(__uuidof(IDXGIKeyedMutex), (LPVOID*)&dxgiKeyedMutex); | |
if (FAILED(hr) || dxgiKeyedMutex == nullptr) { | |
std::cerr << "RenderManagerThread::RegisterRenderBuffers() - failed to create keyed mutex." << std::endl; | |
return false; | |
} | |
mKeyedMutexes.push_back(dxgiKeyedMutex); | |
// Fill in the resource view for your render texture buffer here | |
D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc; | |
memset(&renderTargetViewDesc, 0, sizeof(renderTargetViewDesc)); | |
// This must match what was created in the texture to be rendered | |
// @todo Figure this out by introspection on the texture? | |
//renderTargetViewDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; | |
renderTargetViewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; | |
renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; | |
renderTargetViewDesc.Texture2D.MipSlice = 0; | |
// Create the render target view. | |
ID3D11RenderTargetView *renderTargetView; //< Pointer to our render target view | |
hr = renderInfo[i].library.D3D11->device->CreateRenderTargetView( | |
texture2D, &renderTargetViewDesc, &renderTargetView); | |
if (FAILED(hr)) { | |
std::cerr << "Could not create render target for eye " << i | |
<< std::endl; | |
return false; | |
} | |
osvr::renderkit::RenderBuffer buffer; | |
buffer.D3D11 = new osvr::renderkit::RenderBufferD3D11(); | |
buffer.D3D11->colorBuffer = texture2D; | |
buffer.D3D11->colorBufferView = renderTargetView; | |
mRenderBuffers.push_back(buffer); | |
} | |
return mRenderManager->RegisterRenderBuffers(mRenderBuffers, appWillNotOverwriteBeforeNewPresent); | |
} | |
void PresentRenderBuffers(std::vector<osvr::renderkit::RenderInfo> *renderInfo) { | |
std::lock_guard<std::mutex> lock(mLock); | |
if (mHaveBuffer) { | |
std::cerr << "ReaderManagerThread::PresentRenderBuffers called multiple times before frame processed." | |
<< " A frame may be missed." << std::endl; | |
} | |
mHaveBuffer = true; | |
mRenderInfo = renderInfo; | |
} | |
void start() { | |
if (mStarted) { | |
std::cerr << "RenderManagerThread::start() - thread loop already started." << std::endl; | |
} else { | |
mThread.reset(new std::thread(std::bind(&RenderManagerThread::threadFunc, this))); | |
} | |
} | |
void stop() { | |
std::lock_guard<std::mutex> lock(mLock); | |
if (!mStarted) { | |
std::cerr << "RenderManagerThread::stop() - thread loop not already started." << std::endl; | |
} | |
mQuit = true; | |
} | |
private: | |
bool getQuit() { | |
std::lock_guard<std::mutex> lock(mLock); | |
return mQuit; | |
} | |
void threadFunc() { | |
bool quit = getQuit(); | |
while (!quit) { | |
std::lock_guard<std::mutex> lock(mLock); | |
if (mHaveBuffer) { | |
// Update the context so we get our callbacks called and | |
// update tracker state. | |
mContext->update(); | |
UINT acqKey = 1; | |
UINT relKey = 0; | |
DWORD hr; | |
for (size_t i = 0; i < mRenderBuffers.size(); i++) { | |
auto keyedMutex = mKeyedMutexes[i]; | |
hr = keyedMutex->AcquireSync(acqKey, INFINITE); | |
if (FAILED(hr)) { | |
std::cerr << "Could not AcquireSync in render manager thread." << std::endl; | |
throw std::runtime_error("Could not AcquireSync in render manager thread."); | |
} | |
} | |
// Send the rendered results to the screen | |
if (!mRenderManager->PresentRenderBuffers(mRenderBuffers, *mRenderInfo)) { | |
std::cerr << "PresentRenderBuffers() returned false, maybe because it was asked to quit" << std::endl; | |
mQuit = true; | |
} | |
for (size_t i = 0; i < mRenderBuffers.size(); i++) { | |
auto keyedMutex = mKeyedMutexes[i]; | |
hr = keyedMutex->ReleaseSync(relKey); | |
if (FAILED(hr)) { | |
std::cerr << "Could not ReleaseSync in the render manager thread." << std::endl; | |
throw std::runtime_error("Could not ReleaseSync in the render manager thread."); | |
} | |
} | |
mHaveBuffer = false; | |
} | |
quit = mQuit; | |
} | |
} | |
}; | |
int main(int argc, char *argv[]) | |
{ | |
// Parse the command line | |
int realParams = 0; | |
for (int i = 1; i < argc; i++) { | |
if (argv[i][0] == '-') { | |
Usage(argv[0]); | |
} | |
else switch (++realParams) { | |
case 1: | |
default: | |
Usage(argv[0]); | |
} | |
} | |
if (realParams != 0) { Usage(argv[0]); } | |
// Get an OSVR client context to use to access the devices | |
// that we need. | |
osvr::clientkit::ClientContext context( | |
"org.opengoggles.exampleclients.TrackerCallback"); | |
//// 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 | |
//// right-hand controller. | |
//osvr::clientkit::Interface leftButton1 = | |
// context.getInterface("/controller/left/1"); | |
//leftButton1.registerCallback(&myButtonCallback, &quit); | |
//osvr::clientkit::Interface rightButton1 = | |
// context.getInterface("/controller/right/1"); | |
//rightButton1.registerCallback(&myButtonCallback, &quit); | |
// Create a D3D11 device and context to be used, rather than | |
// having RenderManager make one for us. This is an example | |
// of using an external one, which would be needed for clients | |
// that already have a rendering pipeline, like Unity. | |
ID3D11Device *myDevice = nullptr; // Fill this in | |
ID3D11DeviceContext *myContext = nullptr; // Fill this in. | |
// Here, we open the device and context ourselves, but if you | |
// are working with a render library that provides them for you, | |
// just stick them into the values rather than constructing | |
// them. (This is a bit of a toy example, because we could | |
// just let RenderManager do this work for us and use the library | |
// it sends back. However, it does let us set parameters on the | |
// device and context construction the way that we want, so it | |
// might be useful. Be sure to get D3D11 and have set | |
// D3D11_CREATE_DEVICE_BGRA_SUPPORT in the device/context | |
// creation, however it is done). | |
D3D_FEATURE_LEVEL acceptibleAPI = D3D_FEATURE_LEVEL_11_0; | |
D3D_FEATURE_LEVEL foundAPI; | |
auto hr = D3D11CreateDevice( | |
nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT, | |
&acceptibleAPI, 1, D3D11_SDK_VERSION, &myDevice, | |
&foundAPI, &myContext); | |
if (FAILED(hr)) { | |
std::cerr << "Could not create D3D11 device and context" << std::endl; | |
return -1; | |
} | |
// Set up a handler to cause us to exit cleanly. | |
#ifdef _WIN32 | |
SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE); | |
#endif | |
RenderManagerThread renderThread(&context); | |
// Do a call to get the information we need to construct our | |
// color and depth render-to-texture buffers. | |
std::vector<osvr::renderkit::RenderInfo> renderInfo; | |
context.update(); | |
renderInfo = renderThread.GetRenderInfo(); | |
// Set up the vector of textures to render to and any framebuffer | |
// we need to group them. | |
std::vector<osvr::renderkit::RenderBuffer> renderBuffers; | |
std::vector<ID3D11Texture2D *> depthStencilTextures; | |
std::vector<ID3D11DepthStencilView *> depthStencilViews; | |
std::vector<IDXGIKeyedMutex *> dxgiKeyedMutexes; | |
std::vector<HANDLE> sharedHandles; | |
for (size_t i = 0; i < renderInfo.size(); i++) { | |
// The color buffer for this eye. We need to put this into | |
// a generic structure for the Present function, but we only need | |
// to fill in the Direct3D portion. | |
// 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<int>(renderInfo[i].viewport.width); | |
unsigned height = static_cast<int>(renderInfo[i].viewport.height); | |
// Initialize a new render target texture description. | |
D3D11_TEXTURE2D_DESC textureDesc; | |
memset(&textureDesc, 0, sizeof(textureDesc)); | |
textureDesc.Width = width; | |
textureDesc.Height = height; | |
textureDesc.MipLevels = 1; | |
textureDesc.ArraySize = 1; | |
//textureDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; | |
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; | |
textureDesc.SampleDesc.Count = 1; | |
textureDesc.SampleDesc.Quality = 0; | |
textureDesc.Usage = D3D11_USAGE_DEFAULT; | |
// We need it to be both a render target and a shader resource | |
textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; | |
textureDesc.CPUAccessFlags = 0; | |
textureDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX; | |
// Create a new render target texture to use. | |
hr = renderInfo[i].library.D3D11->device->CreateTexture2D( | |
&textureDesc, NULL, &D3DTexture); | |
if (FAILED(hr)) { | |
std::cerr << "Can't create texture for eye " << i << std::endl; | |
return -1; | |
} | |
IDXGIResource* dxgiResource = NULL; | |
hr = D3DTexture->QueryInterface(__uuidof(IDXGIResource), (LPVOID*)&dxgiResource); | |
if (FAILED(hr)) { | |
std::cerr << "Can't get the IDXGIResource for the texture resource." << std::endl; | |
return -1; | |
} | |
HANDLE sharedHandle; | |
hr = dxgiResource->GetSharedHandle(&sharedHandle); | |
if (FAILED(hr)) { | |
std::cerr << "Can't get the shared handle from the dxgiResource." << std::endl; | |
return -1; | |
} | |
dxgiResource->Release(); | |
sharedHandles.push_back(sharedHandle); | |
IDXGIKeyedMutex* dxgiKeyedMutex = nullptr; | |
hr = D3DTexture->QueryInterface(__uuidof(IDXGIKeyedMutex), (LPVOID*)&dxgiKeyedMutex); | |
if (FAILED(hr) || dxgiKeyedMutex == nullptr) { | |
std::cerr << "Can't get the IDXGIKeyedMutex from the texture resource." << std::endl; | |
return -1; | |
} | |
dxgiKeyedMutexes.push_back(dxgiKeyedMutex); | |
// Fill in the resource view for your render texture buffer here | |
D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc; | |
memset(&renderTargetViewDesc, 0, sizeof(renderTargetViewDesc)); | |
// This must match what was created in the texture to be rendered | |
// @todo Figure this out by introspection on the texture? | |
//renderTargetViewDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; | |
renderTargetViewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; | |
renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; | |
renderTargetViewDesc.Texture2D.MipSlice = 0; | |
// Create the render target view. | |
ID3D11RenderTargetView *renderTargetView; //< Pointer to our render target view | |
hr = renderInfo[i].library.D3D11->device->CreateRenderTargetView( | |
D3DTexture, &renderTargetViewDesc, &renderTargetView); | |
if (FAILED(hr)) { | |
std::cerr << "Could not create render target for eye " << i | |
<< std::endl; | |
return -2; | |
} | |
// Push the filled-in RenderBuffer onto the stack. | |
osvr::renderkit::RenderBufferD3D11 *rbD3D = new osvr::renderkit::RenderBufferD3D11; | |
rbD3D->colorBuffer = D3DTexture; | |
rbD3D->colorBufferView = renderTargetView; | |
osvr::renderkit::RenderBuffer rb; | |
rb.D3D11 = rbD3D; | |
renderBuffers.push_back(rb); | |
//================================================================== | |
// Create a depth buffer | |
// Make the depth/stencil texture. | |
D3D11_TEXTURE2D_DESC textureDescription = { 0 }; | |
textureDescription.SampleDesc.Count = 1; | |
textureDescription.SampleDesc.Quality = 0; | |
textureDescription.Usage = D3D11_USAGE_DEFAULT; | |
textureDescription.BindFlags = D3D11_BIND_DEPTH_STENCIL; | |
textureDescription.Width = width; | |
textureDescription.Height = height; | |
textureDescription.MipLevels = 1; | |
textureDescription.ArraySize = 1; | |
textureDescription.CPUAccessFlags = 0; | |
textureDescription.MiscFlags = 0; | |
/// @todo Make this a parameter | |
textureDescription.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; | |
ID3D11Texture2D *depthStencilBuffer; | |
hr = renderInfo[i].library.D3D11->device->CreateTexture2D( | |
&textureDescription, NULL, &depthStencilBuffer); | |
if (FAILED(hr)) { | |
std::cerr << "Could not create depth/stencil texture for eye " | |
<< i << std::endl; | |
return -4; | |
} | |
depthStencilTextures.push_back(depthStencilBuffer); | |
// Create the depth/stencil view description | |
D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDescription; | |
memset(&depthStencilViewDescription, 0, sizeof(depthStencilViewDescription)); | |
depthStencilViewDescription.Format = textureDescription.Format; | |
depthStencilViewDescription.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; | |
depthStencilViewDescription.Texture2D.MipSlice = 0; | |
ID3D11DepthStencilView *depthStencilView; | |
hr = renderInfo[i].library.D3D11->device->CreateDepthStencilView( | |
depthStencilBuffer, | |
&depthStencilViewDescription, | |
&depthStencilView); | |
if (FAILED(hr)) { | |
std::cerr << "Could not create depth/stencil view for eye " | |
<< i << std::endl; | |
return -5; | |
} | |
depthStencilViews.push_back(depthStencilView); | |
} | |
// Create depth stencil state. | |
// Describe how depth and stencil tests should be performed. | |
D3D11_DEPTH_STENCIL_DESC depthStencilDescription = { 0 }; | |
depthStencilDescription.DepthEnable = true; | |
depthStencilDescription.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; | |
depthStencilDescription.DepthFunc = D3D11_COMPARISON_LESS; | |
depthStencilDescription.StencilEnable = true; | |
depthStencilDescription.StencilReadMask = 0xFF; | |
depthStencilDescription.StencilWriteMask = 0xFF; | |
// Front-facing stencil operations | |
depthStencilDescription.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; | |
depthStencilDescription.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR; | |
depthStencilDescription.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; | |
depthStencilDescription.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; | |
// Back-facing stencil operations | |
depthStencilDescription.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; | |
depthStencilDescription.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR; | |
depthStencilDescription.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; | |
depthStencilDescription.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; | |
ID3D11DepthStencilState *depthStencilState; | |
hr = renderInfo[0].library.D3D11->device->CreateDepthStencilState( | |
&depthStencilDescription, | |
&depthStencilState); | |
if (FAILED(hr)) { | |
std::cerr << "Could not create depth/stencil state" | |
<< std::endl; | |
return -3; | |
} | |
// Register our constructed buffers so that we can use them for | |
// presentation. | |
if (!renderThread.RegisterRenderBuffers(sharedHandles)) { | |
std::cerr << "RegisterRenderBuffers() returned false, cannot continue" << std::endl; | |
quit = true; | |
} | |
renderThread.start(); | |
// 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(); | |
renderInfo = renderThread.GetRenderInfo(); | |
// Render into each buffer using the specified information. | |
for (size_t i = 0; i < renderInfo.size(); i++) { | |
auto keyedMutex = dxgiKeyedMutexes[i]; | |
renderInfo[i].library.D3D11->context->OMSetDepthStencilState(depthStencilState, 1); | |
UINT acqKey = 0; | |
UINT relKey = 1; | |
hr = keyedMutex->AcquireSync(acqKey, INFINITE); | |
if (FAILED(hr)) { | |
std::cerr << "Could not AcquireSync in game render thread." << std::endl; | |
return -4; | |
} | |
RenderView(renderInfo[i], renderBuffers[i].D3D11->colorBufferView, | |
depthStencilViews[i], myDevice, myContext); | |
hr = keyedMutex->ReleaseSync(relKey); | |
if (FAILED(hr)) { | |
std::cerr << "Could not ReleaseSync in the game render thread." << std::endl; | |
return -5; | |
} | |
} | |
// Send the rendered results to the screen | |
renderThread.PresentRenderBuffers(&renderInfo); | |
} | |
renderThread.stop(); | |
// Clean up after ourselves. | |
myContext->Release(); | |
myDevice->Release(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment