Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
FramePresenterD3D11.h237 linesDownload Raw Back to AppDecD3D
1/*
2* Copyright 2017-2024 NVIDIA Corporation.  All rights reserved.
3*
4* Please refer to the NVIDIA end user license agreement (EULA) associated
5* with this source code for terms and conditions that govern your use of
6* this software. Any use, reproduction, disclosure, or distribution of
7* this software and related documentation outside the terms of the EULA
8* is strictly prohibited.
9*
10*/
11#pragma once
12
13#include <iostream>
14#include <mutex>
15#include <thread>
16#include <d3d11.h>
17#include <cuda.h>
18#include <cudaD3D11.h>
19#include "FramePresenterD3D.h"
20#include "../Utils/NvCodecUtils.h"
21
22/**
23* @brief D3D11 presenter class derived from FramePresenterD3D
24*/
25class FramePresenterD3D11 : public FramePresenterD3D
26{
27public:
28    /**
29    *   @brief  FramePresenterD3D11 constructor. This will launch a rendering thread which will be fed with decoded frames
30    *   @param  cuContext - CUDA context handle
31    *   @param  nWidth - Width of D3D surface
32    *   @param  nHeight - Height of D3D surface
33    */
34    FramePresenterD3D11(CUcontext cuContext, int nWidth, int nHeight) : 
35        FramePresenterD3D(cuContext, nWidth, nHeight) 
36    {
37        pthMsgLoop = new std::thread(ThreadProc, this);
38        while (!bReady) {
39            std::this_thread::sleep_for(std::chrono::milliseconds(1));
40        }
41        hTimerQueue = CreateTimerQueue();
42        hPresentEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
43    }
44
45    /**
46    *   @brief  FramePresenterD3D11 destructor.
47    */
48    ~FramePresenterD3D11() {
49        if (hTimerQueue)
50        {
51            DeleteTimerQueue(hTimerQueue);
52        }
53        if (hPresentEvent)
54        {
55            CloseHandle(hPresentEvent);
56        }
57        bQuit = true;
58        pthMsgLoop->join();
59        delete pthMsgLoop;
60    }
61
62    /**
63    *   @brief  Presents a frame present in host memory. More specifically, it copies the host surface
64    *           data to a d3d staging texture and then copies it to the swap chain backbuffer for presentation
65    *   @param  pData - pointer to host surface data
66    *   @param  nBytes - number of bytes to copy
67    *   @return true on success
68    *   @return false when the windowing thread is not ready to be served
69    */
70    bool PresentHostFrame(BYTE *pData, int nBytes) {
71        mtx.lock();
72        if (!bReady) {
73            mtx.unlock();
74            return false;
75        }
76
77        D3D11_MAPPED_SUBRESOURCE mappedTexture;
78        ck(pContext->Map(pStagingTexture, 0, D3D11_MAP_WRITE, 0, &mappedTexture));
79        memcpy(mappedTexture.pData, pData, min(nWidth * nHeight * 4, nBytes));
80        pContext->Unmap(pStagingTexture, 0);
81        pContext->CopyResource(pBackBuffer, pStagingTexture);
82        ck(pSwapChain->Present(0, 0));
83        mtx.unlock();
84        return true;
85    }
86
87    bool PresentDeviceFrame(unsigned char *dpBgra, int nPitch, int64_t delay) {
88        mtx.lock();
89        if (!bReady) {
90            mtx.unlock();
91            return false;
92        }
93        CopyDeviceFrame(dpBgra, nPitch);
94        if (!CreateTimerQueueTimer(&hTimer, hTimerQueue,
95            (WAITORTIMERCALLBACK)PresentRoutine, this, (DWORD)delay, 0, 0))
96        {
97            std::cout << "Problem in createtimer" << std::endl;
98        }
99        while (WaitForSingleObject(hPresentEvent, 0) != WAIT_OBJECT_0)
100        {
101        }
102        if (hTimer)
103        {
104            DeleteTimerQueueTimer(hTimerQueue, hTimer, nullptr);
105        }
106        mtx.unlock();
107        return true;
108    }
109
110private:
111    /**
112    *   @brief  Launches the windowing functionality
113    *   @param  This - pointer to FramePresenterD3D11 object
114    */
115    static void ThreadProc(FramePresenterD3D11 *This) {
116        This->Run();
117    }
118    /**
119    *   @brief  Callback called by D3D runtime. This callback is registered during call to
120    *           CreateTimerQueueTimer in PresentDeviceFrame. In CreateTimerQueueTimer we also
121    *           set a timer. When this timer expires this callback is called. This functionality
122    *           is present to facilitate timestamp based presentation.
123    *   @param  lpParam - void pointer to client data
124    *   @param  TimerOrWaitFired - TRUE for this callback as this is a Timer based callback (Refer:https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms687066(v=vs.85))
125    */
126    static VOID CALLBACK PresentRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired)
127    {
128        if (!lpParam) return;
129        FramePresenterD3D11* presenter = (FramePresenterD3D11 *)lpParam;
130        presenter->pSwapChain->Present(1, 0);
131        SetEvent(presenter->hPresentEvent);
132    }
133
134    /**
135    *   @brief This function is on a thread spawned during FramePresenterD3D11 construction.
136    *          It creates the D3D window and monitors window messages in a loop. This function
137    *          also creates swap chain for presentation and also registers the swap chain backbuffer
138    *          with cuda.
139    */
140    void Run() {
141        HWND hwndMain = CreateAndShowWindow(nWidth, nHeight);
142
143        DXGI_SWAP_CHAIN_DESC sc = { 0 };
144        sc.BufferCount = 1;
145        sc.BufferDesc.Width = nWidth;
146        sc.BufferDesc.Height = nHeight;
147        sc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
148        sc.BufferDesc.RefreshRate.Numerator = 0;
149        sc.BufferDesc.RefreshRate.Denominator = 1;
150        sc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
151        sc.OutputWindow = hwndMain;
152        sc.SampleDesc.Count = 1;
153        sc.SampleDesc.Quality = 0;
154        sc.Windowed = TRUE;
155
156        ID3D11Device *pDevice = NULL;
157        ck(D3D11CreateDeviceAndSwapChain(GetAdapterByContext(cuContext), D3D_DRIVER_TYPE_UNKNOWN,
158            NULL, 0, NULL, 0, D3D11_SDK_VERSION, &sc, &pSwapChain, &pDevice, NULL, &pContext));
159        ck(pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer));
160
161        D3D11_TEXTURE2D_DESC td;
162        pBackBuffer->GetDesc(&td);
163        td.BindFlags = 0;
164        td.Usage = D3D11_USAGE_STAGING;
165        td.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
166        ck(pDevice->CreateTexture2D(&td, NULL, &pStagingTexture));
167
168        ck(cuCtxPushCurrent(cuContext));
169        ck(cuGraphicsD3D11RegisterResource(&cuResource, pBackBuffer, CU_GRAPHICS_REGISTER_FLAGS_NONE));
170        ck(cuGraphicsResourceSetMapFlags(cuResource, CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD));
171        ck(cuCtxPopCurrent(NULL));
172
173        bReady = true;
174        MSG msg = { 0 };
175        while (!bQuit && msg.message != WM_QUIT) {
176            if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
177                TranslateMessage(&msg);
178                DispatchMessage(&msg);
179            }
180        }
181
182        mtx.lock();
183        bReady = false;
184        ck(cuCtxPushCurrent(cuContext));
185        ck(cuGraphicsUnregisterResource(cuResource));
186        ck(cuCtxPopCurrent(NULL));
187        pStagingTexture->Release();
188        pBackBuffer->Release();
189        pContext->Release();
190        pDevice->Release();
191        pSwapChain->Release();
192        DestroyWindow(hwndMain);
193        mtx.unlock();
194    }
195
196    /**
197    *   @brief  Gets the DXGI adapter on which the given cuda context is current
198    *   @param   CUcontext - handle to cuda context
199    *   @return  pAdapter - pointer to DXGI adapter
200    *   @return  NULL - In case there is no adapter corresponding to the supplied cuda context
201    */
202    static IDXGIAdapter *GetAdapterByContext(CUcontext cuContext) {
203        CUdevice cuDeviceTarget;
204        ck(cuCtxPushCurrent(cuContext));
205        ck(cuCtxGetDevice(&cuDeviceTarget));
206        ck(cuCtxPopCurrent(NULL));
207
208        IDXGIFactory1 *pFactory = NULL;
209        ck(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void **)&pFactory));
210        IDXGIAdapter *pAdapter = NULL;
211        for (unsigned i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; i++) {
212            CUdevice cuDevice;
213            ck(cuD3D11GetDevice(&cuDevice, pAdapter));
214            if (cuDevice == cuDeviceTarget) {
215                pFactory->Release();
216                return pAdapter;
217            }
218            pAdapter->Release();
219        }
220        pFactory->Release();
221        return NULL;
222    }
223
224private:
225    bool bReady = false;
226    bool bQuit = false;
227    std::mutex mtx;
228    std::thread *pthMsgLoop = NULL;
229
230    IDXGISwapChain *pSwapChain = NULL;
231    ID3D11DeviceContext *pContext = NULL;
232    ID3D11Texture2D *pBackBuffer = NULL, *pStagingTexture = NULL;
233    HANDLE hTimer;
234    HANDLE hTimerQueue;
235    HANDLE hPresentEvent;
236};
237 
codekingpro/portable-devtools · Team Ai