codekingpro/portable-devtools
114k
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#include <cuda.h>
13#include "../Utils/NvCodecUtils.h"
14
15/**
16* @brief Base class for D3D presentation of decoded frames
17*/
18class FramePresenterD3D {
19public:
20 /**
21 * @brief FramePresenterD3D constructor.
22 * @param cuContext - CUDA context handle
23 * @param nWidth - Width of D3D Surface
24 * @param nHeight - Height of D3D Surface
25 */
26 FramePresenterD3D(CUcontext cuContext, int nWidth, int nHeight) : cuContext(cuContext), nWidth(nWidth), nHeight(nHeight) {}
27 /**
28 * @brief FramePresenterD3D destructor.
29 */
30 virtual ~FramePresenterD3D() {};
31 /**
32 * @brief Pure virtual to be implemented by derived classes. Should present decoded frames available in device memory
33 * @param dpBgra - CUDA device pointer to BGRA surface
34 * @param nPitch - pitch of the BGRA surface. Typically width in pixels * number of bytes per pixel
35 * @param delay - presentation delay. Cue to D3D presenter to inform about the time at which this frame needs to be presented
36 * @return true on success
37 * @return false on failure
38 */
39 virtual bool PresentDeviceFrame(unsigned char *dpBgra, int nPitch, int64_t delay) = 0;
40
41protected:
42 /**
43 * @brief Create and show D3D window.
44 * @param nWidth - Width of the window
45 * @param nHeight - Height of the window
46 * @return hwndMain - handle to the created window
47 */
48 static HWND CreateAndShowWindow(int nWidth, int nHeight) {
49 double r = max(nWidth / 1280.0, nHeight / 720.0);
50 if (r > 1.0) {
51 nWidth = (int)(nWidth / r);
52 nHeight = (int)(nHeight / r);
53 }
54
55 static char szAppName[] = "D3DPresenter";
56 WNDCLASS wndclass;
57 wndclass.style = CS_HREDRAW | CS_VREDRAW;
58 wndclass.lpfnWndProc = WndProc;
59 wndclass.cbClsExtra = 0;
60 wndclass.cbWndExtra = 0;
61 wndclass.hInstance = (HINSTANCE)GetModuleHandle(NULL);
62 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
63 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
64 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
65 wndclass.lpszMenuName = NULL;
66 wndclass.lpszClassName = szAppName;
67 RegisterClass(&wndclass);
68
69 RECT rc{
70 (GetSystemMetrics(SM_CXSCREEN) - nWidth) / 2,
71 (GetSystemMetrics(SM_CYSCREEN) - nHeight) / 2,
72 (GetSystemMetrics(SM_CXSCREEN) + nWidth) / 2,
73 (GetSystemMetrics(SM_CYSCREEN) + nHeight) / 2
74 };
75 AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
76
77 HWND hwndMain = CreateWindow(szAppName, szAppName, WS_OVERLAPPEDWINDOW,
78 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
79 NULL, NULL, wndclass.hInstance, NULL);
80 ShowWindow(hwndMain, SW_SHOW);
81 UpdateWindow(hwndMain);
82
83 return hwndMain;
84 }
85
86 /**
87 * @brief Copy device frame to cuda registered D3D surface. More specifically, this function maps the
88 * D3D swap chain backbuffer into a cuda array and copies the contents of dpBgra into it.
89 * This ensures that the swap chain back buffer will contain the next surface to be presented.
90 * @param dpBgra - CUDA device pointer to BGRA surface
91 * @param nPitch - pitch of the BGRA surface. Typically width in pixels * number of bytes per pixel
92 */
93 void CopyDeviceFrame(unsigned char *dpBgra, int nPitch) {
94 ck(cuCtxPushCurrent(cuContext));
95 ck(cuGraphicsMapResources(1, &cuResource, 0));
96 CUarray dstArray;
97 ck(cuGraphicsSubResourceGetMappedArray(&dstArray, cuResource, 0, 0));
98
99 CUDA_MEMCPY2D m = { 0 };
100 m.srcMemoryType = CU_MEMORYTYPE_DEVICE;
101 m.srcDevice = (CUdeviceptr)dpBgra;
102 m.srcPitch = nPitch ? nPitch : nWidth * 4;
103 m.dstMemoryType = CU_MEMORYTYPE_ARRAY;
104 m.dstArray = dstArray;
105 m.WidthInBytes = nWidth * 4;
106 m.Height = nHeight;
107 ck(cuMemcpy2D(&m));
108
109 ck(cuGraphicsUnmapResources(1, &cuResource, 0));
110 ck(cuCtxPopCurrent(NULL));
111 }
112
113private:
114 /**
115 * @brief Callback called by D3D runtime. This callback is registered during window creation.
116 * On Window close this function posts a quit message. The thread runs to completion once
117 * it retrieves this quit message in its message queue. Refer to Run() function in each of the
118 * derived classes.
119 * @param hwnd - handle to the window
120 * @param msg - The message sent to this window
121 * @param wParam - Message specific additional information (No Op in this case)
122 * @param lParam - Message specific additional information (No Op on this case)
123 * @return 0 on posting quit message
124 * @return result of default window procedure in cases other than the above
125 */
126 static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
127 switch (msg) {
128 case WM_CLOSE:
129 PostQuitMessage(0);
130 return 0;
131 }
132 return DefWindowProc(hwnd, msg, wParam, lParam);
133 }
134
135protected:
136 int nWidth = 0, nHeight = 0;
137 CUcontext cuContext = NULL;
138 CUgraphicsResource cuResource = NULL;
139};
140 