1+ // See https://aka.ms/new-console-template for more information
2+
3+ using System ;
4+ using System . Collections . Generic ;
5+ using System . Diagnostics ;
6+ using System . Drawing ;
7+ using System . Linq ;
8+ using System . Runtime . CompilerServices ;
9+ using System . Runtime . InteropServices ;
10+ using System . Runtime . Versioning ;
11+ using System . Text ;
12+ using System . Threading ;
13+
14+ using Vortice . DCommon ;
15+ using Vortice . Direct2D1 ;
16+ using Vortice . Direct3D ;
17+ using Vortice . Direct3D11 ;
18+ using Vortice . DirectComposition ;
19+ using Vortice . DXGI ;
20+ using Vortice . Mathematics ;
21+ using Vortice . Win32 ;
22+
23+ using Windows . Win32 ;
24+ using Windows . Win32 . Foundation ;
25+ using Windows . Win32 . Graphics . Gdi ;
26+ using Windows . Win32 . UI . Input . Pointer ;
27+ using Windows . Win32 . UI . WindowsAndMessaging ;
28+
29+ using static Windows . Win32 . PInvoke ;
30+
31+ using AlphaMode = Vortice . DXGI . AlphaMode ;
32+ using Color = Vortice . Mathematics . Color ;
33+ using D2D = Vortice . Direct2D1 ;
34+
35+ namespace JecekelbereLaiwharhowhelli ;
36+
37+ class Program
38+ {
39+ [ STAThread ]
40+ static unsafe void Main ( string [ ] args )
41+ {
42+ HWND window ;
43+
44+ #region 创建窗口
45+
46+ WINDOW_EX_STYLE exStyle = WINDOW_EX_STYLE . WS_EX_APPWINDOW ;
47+
48+ var style = WNDCLASS_STYLES . CS_OWNDC | WNDCLASS_STYLES . CS_HREDRAW | WNDCLASS_STYLES . CS_VREDRAW ;
49+
50+ var defaultCursor = LoadCursor (
51+ new HINSTANCE ( IntPtr . Zero ) , new PCWSTR ( IDC_ARROW . Value ) ) ;
52+ var wndProcDelegate = new WNDPROC ( WndProc ) ;
53+
54+ var className = $ "lindexi-{ Guid . NewGuid ( ) . ToString ( ) } ";
55+ var title = "The Title" ;
56+ fixed ( char * pClassName = className )
57+ fixed ( char * pTitle = title )
58+ {
59+ var wndClassEx = new WNDCLASSEXW
60+ {
61+ cbSize = ( uint ) Marshal . SizeOf < WNDCLASSEXW > ( ) ,
62+ style = style ,
63+ lpfnWndProc = wndProcDelegate ,
64+ hInstance = new HINSTANCE ( GetModuleHandle ( null ) . DangerousGetHandle ( ) ) ,
65+ hCursor = defaultCursor ,
66+ hbrBackground = new HBRUSH ( IntPtr . Zero ) ,
67+ lpszClassName = new PCWSTR ( pClassName )
68+ } ;
69+ ushort atom = RegisterClassEx ( in wndClassEx ) ;
70+
71+ WINDOW_STYLE dwStyle = WINDOW_STYLE . WS_OVERLAPPEDWINDOW | WINDOW_STYLE . WS_VISIBLE | WINDOW_STYLE . WS_CAPTION | WINDOW_STYLE . WS_SYSMENU | WINDOW_STYLE . WS_MINIMIZEBOX | WINDOW_STYLE . WS_CLIPCHILDREN | WINDOW_STYLE . WS_BORDER | WINDOW_STYLE . WS_DLGFRAME | WINDOW_STYLE . WS_THICKFRAME | WINDOW_STYLE . WS_TABSTOP | WINDOW_STYLE . WS_SIZEBOX ;
72+
73+ HWND windowHwnd = CreateWindowEx (
74+ exStyle ,
75+ new PCWSTR ( ( char * ) atom ) ,
76+ new PCWSTR ( pTitle ) ,
77+ dwStyle ,
78+ 0 , 0 , 1900 , 1000 ,
79+ HWND . Null , HMENU . Null , HINSTANCE . Null , null ) ;
80+ window = windowHwnd ;
81+ }
82+
83+ // 防止委托对象被回收,导致注册进去的方法指针失效
84+ GC . KeepAlive ( wndProcDelegate ) ; // 保稳来说,这句话应该放在方法末尾
85+
86+ #endregion
87+
88+ // 显示窗口
89+ ShowWindow ( window , SHOW_WINDOW_CMD . SW_NORMAL ) ;
90+
91+ RECT windowRect ;
92+ GetClientRect ( window , & windowRect ) ;
93+ GetClientRect ( window , & windowRect ) ;
94+ var clientSize = new SizeI ( windowRect . right - windowRect . left , windowRect . bottom - windowRect . top ) ;
95+
96+ #region 初始化 DX 相关
97+
98+ DeviceCreationFlags creationFlags = DeviceCreationFlags . BgraSupport ;
99+ var result = D3D11 . D3D11CreateDevice
100+ (
101+ null ,
102+ DriverType . Hardware ,
103+ creationFlags ,
104+ null ,
105+ out ID3D11Device ? d3D11Device
106+ ) ;
107+
108+ result . CheckError ( ) ;
109+ Debug . Assert ( d3D11Device != null ) ;
110+
111+ // 缓存的数量,包括前缓存。大部分应用来说,至少需要两个缓存,这个玩过游戏的伙伴都知道
112+ const int FrameCount = 2 ;
113+ Format colorFormat = Format . B8G8R8A8_UNorm ;
114+ SwapChainDescription1 swapChainDescription = new ( )
115+ {
116+ Width = ( uint ) clientSize . Width ,
117+ Height = ( uint ) clientSize . Height ,
118+ Format = colorFormat ,
119+ BufferCount = FrameCount ,
120+ BufferUsage = Usage . RenderTargetOutput ,
121+ SampleDescription = SampleDescription . Default ,
122+ Scaling = Scaling . Stretch ,
123+ SwapEffect = SwapEffect . FlipSequential ,
124+ AlphaMode = AlphaMode . Ignore ,
125+ Flags = SwapChainFlags . None ,
126+ } ;
127+
128+ var fullscreenDescription = new SwapChainFullscreenDescription ( )
129+ {
130+ Windowed = true ,
131+ } ;
132+
133+ using var dxgiFactory2 = DXGI . CreateDXGIFactory1 < IDXGIFactory2 > ( ) ;
134+ using IDXGISwapChain1 swapChain =
135+ dxgiFactory2 . CreateSwapChainForHwnd ( d3D11Device , window , swapChainDescription , fullscreenDescription ) ;
136+
137+ // 不要被按下 alt+enter 进入全屏
138+ dxgiFactory2 . MakeWindowAssociation ( window ,
139+ WindowAssociationFlags . IgnoreAltEnter | WindowAssociationFlags . IgnorePrintScreen ) ;
140+ #endregion
141+
142+ #region 对接 D2D 渲染
143+
144+ using var d3D11Texture2D = swapChain . GetBuffer < ID3D11Texture2D > ( 0 ) ;
145+ using var dxgiSurface = d3D11Texture2D . QueryInterface < IDXGISurface > ( ) ;
146+
147+ var renderTargetProperties = new D2D . RenderTargetProperties ( )
148+ {
149+ PixelFormat = new PixelFormat ( colorFormat , Vortice . DCommon . AlphaMode . Premultiplied ) ,
150+ Type = D2D . RenderTargetType . Hardware ,
151+ } ;
152+
153+ using D2D . ID2D1Factory1 d2DFactory = D2D . D2D1 . D2D1CreateFactory < D2D . ID2D1Factory1 > ( ) ;
154+ D2D . ID2D1RenderTarget d2D1RenderTarget =
155+ d2DFactory . CreateDxgiSurfaceRenderTarget ( dxgiSurface , renderTargetProperties ) ;
156+ D2D . ID2D1RenderTarget renderTarget = d2D1RenderTarget ;
157+ #endregion
158+
159+ var maxCount = 100 ;
160+ var stepTimeList = new List < TimeSpan > ( ) ;
161+ var stopwatch = new Stopwatch ( ) ;
162+
163+ while ( true )
164+ {
165+ renderTarget . BeginDraw ( ) ;
166+
167+ renderTarget . Clear ( new Color4 ( ( uint ) Random . Shared . Next ( ) ) ) ;
168+
169+ renderTarget . EndDraw ( ) ;
170+
171+ stopwatch . Restart ( ) ;
172+ swapChain . Present ( 1 , 0 ) ;
173+ stopwatch . Stop ( ) ;
174+
175+ if ( stepTimeList . Count < maxCount )
176+ {
177+ stepTimeList . Add ( stopwatch . Elapsed ) ;
178+ }
179+ else
180+ {
181+ var stringBuilder = new StringBuilder ( ) ;
182+
183+ for ( var i = 0 ; i < stepTimeList . Count ; i ++ )
184+ {
185+ var timeSpan = stepTimeList [ i ] ;
186+ stringBuilder . AppendLine ( $ "[{ i : D3} ] { timeSpan . TotalMilliseconds : 0.000} ms") ;
187+ }
188+
189+ var costText = stringBuilder . ToString ( ) ;
190+ Console . WriteLine ( costText ) ;
191+
192+ /*
193+ [000] 0.173 ms
194+ [001] 0.171 ms
195+ [002] 0.591 ms
196+ [003] 7.008 ms
197+ [004] 16.074 ms
198+ [005] 17.490 ms
199+ [006] 10.339 ms
200+ [007] 18.348 ms
201+ [008] 12.287 ms
202+ [009] 15.211 ms
203+ [010] 16.125 ms
204+ [011] 16.110 ms
205+ [012] 16.100 ms
206+ [013] 2.887 ms
207+ [014] 2.171 ms
208+ [015] 2.223 ms
209+ [016] 2.365 ms
210+ [017] 15.942 ms
211+ [018] 15.915 ms
212+ [019] 15.896 ms
213+ [020] 15.930 ms
214+ [021] 15.950 ms
215+ [022] 15.903 ms
216+ [023] 15.602 ms
217+ [024] 16.525 ms
218+ [025] 15.597 ms
219+ [026] 15.878 ms
220+ [027] 15.908 ms
221+ [028] 15.912 ms
222+ [029] 16.046 ms
223+ [030] 15.938 ms
224+ */
225+
226+ Console . ReadLine ( ) ;
227+ }
228+
229+ // 以下只是为了防止窗口无响应而已
230+ var success = PeekMessage ( out var msg , HWND . Null , 0 , 0 , PEEK_MESSAGE_REMOVE_TYPE . PM_REMOVE ) ;
231+ if ( success )
232+ {
233+ // 处理窗口消息
234+ TranslateMessage ( & msg ) ;
235+ DispatchMessage ( & msg ) ;
236+ }
237+ }
238+
239+ Console . ReadLine ( ) ;
240+
241+ LRESULT WndProc ( HWND hwnd , uint message , WPARAM wParam , LPARAM lParam )
242+ {
243+ return DefWindowProc ( hwnd , message , wParam , lParam ) ;
244+ }
245+ }
246+ }
0 commit comments