Exemplo n.º 1
0
bool spoutDirectX::LockD3D11Texture(ID3D11Texture2D* pD3D11Texture)
{
	DWORD dwWaitResult;
	IDXGIKeyedMutex* pDXGIKeyedMutex;

	if(pD3D11Texture == NULL) return false;

	pD3D11Texture->QueryInterface(_uuidof(IDXGIKeyedMutex), (void**)&pDXGIKeyedMutex);
	if (pDXGIKeyedMutex) {
		dwWaitResult = (DWORD)pDXGIKeyedMutex->AcquireSync(0, 67); // TODO - link with SPOUT_WAIT_TIMEOUT
		if (dwWaitResult == WAIT_OBJECT_0 ) {
			// The state of the object is signaled.
			return true;
		}
		else {
			switch(dwWaitResult) {
				case WAIT_ABANDONED : // Could return here
					printf("LockD3D11Texture : WAIT_ABANDONED\n");
					break;
				case WAIT_TIMEOUT : // The time-out interval elapsed, and the object's state is nonsignaled.
					printf("LockD3D11Texture : SPOUT_WAIT_TIMEOUT\n");
					break;
				default :
					break;
			}
		}
	}
	return false;
}
Exemplo n.º 2
0
void spoutDirectX::UnlockD3D11Texture(ID3D11Texture2D* pD3D11Texture)
{
  if(pD3D11Texture == NULL) return;

  IDXGIKeyedMutex* pDXGIKeyedMutex;

  pD3D11Texture->QueryInterface(_uuidof(IDXGIKeyedMutex), (void**)&pDXGIKeyedMutex);
  if (pDXGIKeyedMutex) {
    HRESULT hr = pDXGIKeyedMutex->ReleaseSync(0);
    if (FAILED(hr)) {
      // printf("Failed to unlock the shared texture");
    }
  }
}
int main(int argc, char* argv[]) {
    // Parse the command line
    int delayMilliSeconds = 500;
    int realParams = 0;
    for (int i = 1; i < argc; i++) {
        if (argv[i][0] == '-') {
            Usage(argv[0]);
        } else {
            switch (++realParams) {
            case 1:
              delayMilliSeconds = atoi(argv[i]);
              break;
            default:
                Usage(argv[0]);
            }
        }
    }
    if (realParams > 1) {
        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;
    }

    // Put the device and context into a structure to let RenderManager
    // know to use this one rather than creating its own.
    osvr::renderkit::GraphicsLibrary library;
    library.D3D11 = new osvr::renderkit::GraphicsLibraryD3D11;
    library.D3D11->device = myDevice;
    library.D3D11->context = myContext;

    // 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.
    osvr::renderkit::RenderManager* render =
        osvr::renderkit::createRenderManager(context.get(), "Direct3D11",
        library);

    if ((render == nullptr) || (!render->doingOkay())) {
        std::cerr << "Could not create RenderManager" << std::endl;
        return 1;
    }

    // Set up a handler to cause us to exit cleanly.
#ifdef _WIN32
    SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);
#endif

    // Open the display and make sure this worked.
    osvr::renderkit::RenderManager::OpenResults ret = render->OpenDisplay();
    if (ret.status == osvr::renderkit::RenderManager::OpenStatus::FAILURE) {
        std::cerr << "Could not open display" << std::endl;
        return 2;
    }
    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;
        return 3;
    }

    // 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 = render->GetRenderInfo();

    std::vector<FrameInfo> frameInfo(2);
    for (size_t frame = 0; frame < frameInfo.size(); frame++) {
        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 = {};
            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;
            }

            // Grab and lock the mutex, so that we will be able to render
            // to it whether or not RenderManager locks it on our behalf.
            // it will not be auto-locked when we're in the non-ATW case.
            IDXGIKeyedMutex* myMutex = nullptr;
            hr = D3DTexture->QueryInterface(
              __uuidof(IDXGIKeyedMutex), (LPVOID*)&myMutex);
            if (FAILED(hr) || myMutex == nullptr) {
              std::cerr << "Could not get mutex pointer" << std::endl;
              return -2;
            }
            hr = myMutex->AcquireSync(0, INFINITE);
            if (FAILED(hr)) {
              std::cerr << "Could not acquire mutex" << std::endl;
              return -3;
            }

            // 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
            renderTargetViewDesc.Format = textureDesc.Format;
            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;
            frameInfo[frame].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;
            }
            frameInfo[frame].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;
            }
            frameInfo[frame].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;

    // We only have one depth/stencil state for all displays.
    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 all of our constructed buffers so that we can use them for
    // presentation, and promise not to re-use a buffer for rendering until
    // we're not presenting it.
    std::vector<osvr::renderkit::RenderBuffer> allBuffers;
    // Register our constructed buffers so that we can use them for
    // presentation.
    for (size_t frame = 0; frame < frameInfo.size(); frame++) {
      for (size_t buf = 0; buf < frameInfo[frame].renderBuffers.size(); buf++) {
        allBuffers.push_back(frameInfo[frame].renderBuffers[buf]);
      }
    }
    if (!render->RegisterRenderBuffers(allBuffers, true)) {
      std::cerr << "RegisterRenderBuffers() returned false, cannot continue" << std::endl;
      quit = true;
    }
    allBuffers.clear();

    size_t iteration = 0;
    // Continue rendering until it is time to quit.
    while (!quit) {
        size_t frame = iteration % frameInfo.size();
        // Update the context so we get our callbacks called and
        // update tracker state.
        context.update();

        renderInfo = render->GetRenderInfo();

        // Render into each buffer using the specified information.
        for (size_t i = 0; i < renderInfo.size(); i++) {
          renderInfo[i].library.D3D11->context->OMSetDepthStencilState(depthStencilState, 1);
            RenderView(renderInfo[i], frameInfo[frame].renderBuffers[i].D3D11->colorBufferView,
                frameInfo[frame].depthStencilViews[i], myDevice,
                renderInfo[i].library.D3D11->context);
        }

        // Send the rendered results to the screen
        render->PresentRenderBuffers(frameInfo[frame].renderBuffers, renderInfo);

        // Delay the requested length of time to simulate a long render time.
        // Busy-wait so we don't get swapped out longer than we wanted.
        auto end =
          std::chrono::high_resolution_clock::now() +
          std::chrono::milliseconds(delayMilliSeconds);
        do {
        } while (std::chrono::high_resolution_clock::now() < end);
        iteration++;
    }

    // Close the Renderer interface cleanly.
    delete render;

    // Clean up after ourselves.
    myContext->Release();
    myDevice->Release();

    return 0;
}