1 /*
2  * Copyright 2011-2019 Branimir Karadzic. All rights reserved.
3  * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
4  */
5 
6 #ifndef BGFX_RENDERER_D3D9_H_HEADER_GUARD
7 #define BGFX_RENDERER_D3D9_H_HEADER_GUARD
8 
9 #define BGFX_CONFIG_RENDERER_DIRECT3D9EX BX_PLATFORM_WINDOWS
10 
11 #if BX_PLATFORM_WINDOWS
12 #	include <sal.h>
13 #	include <d3d9.h>
14 #endif // BX_PLATFORM_
15 
16 #ifndef D3DSTREAMSOURCE_INDEXEDDATA
17 #	define D3DSTREAMSOURCE_INDEXEDDATA  (1<<30)
18 #endif// D3DSTREAMSOURCE_INDEXEDDATA
19 
20 #ifndef D3DSTREAMSOURCE_INSTANCEDATA
21 #	define D3DSTREAMSOURCE_INSTANCEDATA (2<<30)
22 #endif // D3DSTREAMSOURCE_INSTANCEDATA
23 
24 #include "renderer.h"
25 #include "renderer_d3d.h"
26 #include "nvapi.h"
27 
28 #define BGFX_D3D9_PROFILER_BEGIN(_view, _abgr)          \
29 	BX_MACRO_BLOCK_BEGIN                                \
30 		PIX_BEGINEVENT(_abgr, s_viewNameW[_view]);      \
31 		BGFX_PROFILER_BEGIN(s_viewName[view], _abgr);   \
32 	BX_MACRO_BLOCK_END
33 
34 #define BGFX_D3D9_PROFILER_BEGIN_LITERAL(_name, _abgr)  \
35 	BX_MACRO_BLOCK_BEGIN                                \
36 		PIX_BEGINEVENT(_abgr, L"" # _name);             \
37 		BGFX_PROFILER_BEGIN_LITERAL("" # _name, _abgr); \
38 	BX_MACRO_BLOCK_END
39 
40 #define BGFX_D3D9_PROFILER_END()                        \
41 	BX_MACRO_BLOCK_BEGIN                                \
42 		BGFX_PROFILER_END();                            \
43 		PIX_ENDEVENT();                                 \
44 	BX_MACRO_BLOCK_END
45 
46 namespace bgfx { namespace d3d9
47 {
48 #	if defined(D3D_DISABLE_9EX)
49 #		define D3DFMT_S8_LOCKABLE D3DFORMAT( 85)
50 #		define D3DFMT_A1          D3DFORMAT(118)
51 #	endif // defined(D3D_DISABLE_9EX)
52 
53 #	ifndef D3DFMT_ATI1
54 #		define D3DFMT_ATI1 ( (D3DFORMAT)BX_MAKEFOURCC('A', 'T', 'I', '1') )
55 #	endif // D3DFMT_ATI1
56 
57 #	ifndef D3DFMT_ATI2
58 #		define D3DFMT_ATI2 ( (D3DFORMAT)BX_MAKEFOURCC('A', 'T', 'I', '2') )
59 #	endif // D3DFMT_ATI2
60 
61 #	ifndef D3DFMT_ATOC
62 #		define D3DFMT_ATOC ( (D3DFORMAT)BX_MAKEFOURCC('A', 'T', 'O', 'C') )
63 #	endif // D3DFMT_ATOC
64 
65 #	ifndef D3DFMT_DF16
66 #		define D3DFMT_DF16 ( (D3DFORMAT)BX_MAKEFOURCC('D', 'F', '1', '6') )
67 #	endif // D3DFMT_DF16
68 
69 #	ifndef D3DFMT_DF24
70 #		define D3DFMT_DF24 ( (D3DFORMAT)BX_MAKEFOURCC('D', 'F', '2', '4') )
71 #	endif // D3DFMT_DF24
72 
73 #	ifndef D3DFMT_INST
74 #		define D3DFMT_INST ( (D3DFORMAT)BX_MAKEFOURCC('I', 'N', 'S', 'T') )
75 #	endif // D3DFMT_INST
76 
77 #	ifndef D3DFMT_INTZ
78 #		define D3DFMT_INTZ ( (D3DFORMAT)BX_MAKEFOURCC('I', 'N', 'T', 'Z') )
79 #	endif // D3DFMT_INTZ
80 
81 #	ifndef D3DFMT_NULL
82 #		define D3DFMT_NULL ( (D3DFORMAT)BX_MAKEFOURCC('N', 'U', 'L', 'L') )
83 #	endif // D3DFMT_NULL
84 
85 #	ifndef D3DFMT_RESZ
86 #		define D3DFMT_RESZ ( (D3DFORMAT)BX_MAKEFOURCC('R', 'E', 'S', 'Z') )
87 #	endif // D3DFMT_RESZ
88 
89 #	ifndef D3DFMT_RAWZ
90 #		define D3DFMT_RAWZ ( (D3DFORMAT)BX_MAKEFOURCC('R', 'A', 'W', 'Z') )
91 #	endif // D3DFMT_RAWZ
92 
93 #	ifndef D3DFMT_S8_LOCKABLE
94 #		define D3DFMT_S8_LOCKABLE ( (D3DFORMAT)85)
95 #	endif // D3DFMT_S8_LOCKABLE
96 
97 #	ifndef D3DFMT_A1
98 #		define D3DFMT_A1 ( (D3DFORMAT)118)
99 #	endif // D3DFMT_A1
100 
101 	struct ExtendedFormat
102 	{
103 		enum Enum
104 		{
105 			Ati1,
106 			Ati2,
107 			Df16,
108 			Df24,
109 			Inst,
110 			Intz,
111 			Null,
112 			Resz,
113 			Rawz,
114 			Atoc,
115 
116 			Count,
117 		};
118 
119 		D3DFORMAT m_fmt;
120 		DWORD m_usage;
121 		D3DRESOURCETYPE m_type;
122 		bool m_supported;
123 	};
124 
125 	struct Msaa
126 	{
127 		D3DMULTISAMPLE_TYPE m_type;
128 		DWORD m_quality;
129 	};
130 
131 	struct IndexBufferD3D9
132 	{
IndexBufferD3D9IndexBufferD3D9133 		IndexBufferD3D9()
134 			: m_ptr(NULL)
135 			, m_dynamic(NULL)
136 			, m_size(0)
137 			, m_flags(BGFX_BUFFER_NONE)
138 		{
139 		}
140 
141 		void create(uint32_t _size, void* _data, uint16_t _flags);
142 		void update(uint32_t _offset, uint32_t _size, void* _data, bool _discard = false)
143 		{
144 			if (NULL  != m_dynamic
145 			&&  _data != m_dynamic)
146 			{
147 				bx::memCopy(&m_dynamic[_offset], _data, _size);
148 			}
149 
150 			void* buffer;
151 			DX_CHECK(m_ptr->Lock(_offset
152 				, _size
153 				, &buffer
154 				, _discard || (m_dynamic && 0 == _offset && m_size == _size) ? D3DLOCK_DISCARD : 0
155 				) );
156 
157 			bx::memCopy(buffer, _data, _size);
158 
159 			DX_CHECK(m_ptr->Unlock() );
160 		}
161 
destroyIndexBufferD3D9162 		void destroy()
163 		{
164 			if (NULL != m_ptr)
165 			{
166 				DX_RELEASE(m_ptr, 0);
167 
168 				if (NULL != m_dynamic)
169 				{
170 					BX_FREE(g_allocator, m_dynamic);
171 					m_dynamic = NULL;
172 				}
173 			}
174 		}
175 
176 		void preReset();
177 		void postReset();
178 
179 		IDirect3DIndexBuffer9* m_ptr;
180 		uint8_t* m_dynamic;
181 		uint32_t m_size;
182 		uint16_t m_flags;
183 	};
184 
185 	struct VertexBufferD3D9
186 	{
VertexBufferD3D9VertexBufferD3D9187 		VertexBufferD3D9()
188 			: m_ptr(NULL)
189 			, m_dynamic(NULL)
190 			, m_size(0)
191 		{
192 		}
193 
194 		void create(uint32_t _size, void* _data, VertexLayoutHandle _layoutHandle);
195 		void update(uint32_t _offset, uint32_t _size, void* _data, bool _discard = false)
196 		{
197 			if (NULL  != m_dynamic
198 			&&  _data != m_dynamic)
199 			{
200 				bx::memCopy(&m_dynamic[_offset], _data, _size);
201 			}
202 
203 			void* buffer;
204 			DX_CHECK(m_ptr->Lock(_offset
205 				, _size
206 				, &buffer
207 				, _discard || (m_dynamic && 0 == _offset && m_size == _size) ? D3DLOCK_DISCARD : 0
208 				) );
209 
210 			bx::memCopy(buffer, _data, _size);
211 
212 			DX_CHECK(m_ptr->Unlock() );
213 		}
214 
destroyVertexBufferD3D9215 		void destroy()
216 		{
217 			if (NULL != m_ptr)
218 			{
219 				DX_RELEASE(m_ptr, 0);
220 
221 				if (NULL != m_dynamic)
222 				{
223 					BX_FREE(g_allocator, m_dynamic);
224 					m_dynamic = NULL;
225 				}
226 			}
227 		}
228 
229 		void preReset();
230 		void postReset();
231 
232 		IDirect3DVertexBuffer9* m_ptr;
233 		uint8_t* m_dynamic;
234 		uint32_t m_size;
235 		VertexLayoutHandle m_layoutHandle;
236 	};
237 
238 	struct ShaderD3D9
239 	{
ShaderD3D9ShaderD3D9240 		ShaderD3D9()
241 			: m_vertexShader(NULL)
242 			, m_constantBuffer(NULL)
243 			, m_numPredefined(0)
244 			, m_type(0)
245 		{
246 		}
247 
248 		void create(const Memory* _mem);
249 
destroyShaderD3D9250 		void destroy()
251 		{
252 			if (NULL != m_constantBuffer)
253 			{
254 				UniformBuffer::destroy(m_constantBuffer);
255 				m_constantBuffer = NULL;
256 			}
257 			m_numPredefined = 0;
258 
259 			switch (m_type)
260 			{
261 			case 0:  DX_RELEASE(m_vertexShader, 0); BX_FALLTHROUGH;
262 			default: DX_RELEASE(m_pixelShader,  0);
263 			}
264 		}
265 
266 		union
267 		{
268 			// X360 doesn't have interface inheritance (can't use IUnknown*).
269 			IDirect3DVertexShader9* m_vertexShader;
270 			IDirect3DPixelShader9*  m_pixelShader;
271 		};
272 		UniformBuffer* m_constantBuffer;
273 		PredefinedUniform m_predefined[PredefinedUniform::Count];
274 		uint8_t m_numPredefined;
275 		uint8_t m_type;
276 	};
277 
278 	struct ProgramD3D9
279 	{
createProgramD3D9280 		void create(const ShaderD3D9* _vsh, const ShaderD3D9* _fsh)
281 		{
282 			m_vsh = _vsh;
283 			m_fsh = _fsh;
284 
285 			bx::memCopy(&m_predefined[0], _vsh->m_predefined, _vsh->m_numPredefined*sizeof(PredefinedUniform) );
286 			m_numPredefined = _vsh->m_numPredefined;
287 
288 			if (NULL != _fsh)
289 			{
290 				bx::memCopy(&m_predefined[_vsh->m_numPredefined], _fsh->m_predefined, _fsh->m_numPredefined*sizeof(PredefinedUniform) );
291 				m_numPredefined += _fsh->m_numPredefined;
292 			}
293 		}
294 
destroyProgramD3D9295 		void destroy()
296 		{
297 			m_numPredefined = 0;
298 			m_vsh = NULL;
299 			m_fsh = NULL;
300 		}
301 
302 		const ShaderD3D9* m_vsh;
303 		const ShaderD3D9* m_fsh;
304 
305 		PredefinedUniform m_predefined[PredefinedUniform::Count*2];
306 		uint8_t m_numPredefined;
307 	};
308 
309 	struct TextureD3D9
310 	{
311 		enum Enum
312 		{
313 			Texture2D,
314 			Texture3D,
315 			TextureCube,
316 		};
317 
TextureD3D9TextureD3D9318 		TextureD3D9()
319 			: m_ptr(NULL)
320 			, m_surface(NULL)
321 			, m_staging(NULL)
322 			, m_textureFormat(TextureFormat::Unknown)
323 		{
324 		}
325 
326 		void createTexture(uint32_t _width, uint32_t _height, uint8_t _numMips);
327 		void createVolumeTexture(uint32_t _width, uint32_t _height, uint32_t _depth, uint8_t _numMips);
328 		void createCubeTexture(uint32_t _width, uint8_t _numMips);
329 
330 		uint8_t* lock(uint8_t _side, uint8_t _lod, uint32_t& _pitch, uint32_t& _slicePitch, const Rect* _rect = NULL);
331 		void unlock(uint8_t _side, uint8_t _lod);
332 		void dirty(uint8_t _side, const Rect& _rect, uint16_t _z, uint16_t _depth);
333 		IDirect3DSurface9* getSurface(uint8_t _side = 0, uint8_t _mip = 0) const;
334 
335 		void create(const Memory* _mem, uint64_t _flags, uint8_t _skip);
336 
337 		void destroy(bool _resize = false)
338 		{
339 			if (0 == (m_flags & BGFX_SAMPLER_INTERNAL_SHARED) )
340 			{
341 				if (_resize)
342 				{
343 					// BK - at the time of resize there might be one reference held by frame buffer
344 					//      surface. This frame buffer will be recreated later, and release reference
345 					//      to existing surface. That's why here we don't care about ref count.
346 					m_ptr->Release();
347 				}
348 				else
349 				{
350 					DX_RELEASE(m_ptr, 0);
351 				}
352 			}
353 			DX_RELEASE(m_surface, 0);
354 			DX_RELEASE(m_staging, 0);
355 			m_textureFormat = TextureFormat::Unknown;
356 		}
357 
overrideInternalTextureD3D9358 		void overrideInternal(uintptr_t _ptr)
359 		{
360 			destroy();
361 			m_flags |= BGFX_SAMPLER_INTERNAL_SHARED;
362 			m_ptr = (IDirect3DBaseTexture9*)_ptr;
363 		}
364 
365 		void updateBegin(uint8_t _side, uint8_t _mip);
366 		void update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem);
367 		void updateEnd();
368 		void commit(uint8_t _stage, uint32_t _flags, const float _palette[][4]);
369 		void resolve(uint8_t _resolve) const;
370 
371 		void preReset();
372 		void postReset();
373 
374 		union
375 		{
376 			IDirect3DBaseTexture9*   m_ptr;
377 			IDirect3DTexture9*       m_texture2d;
378 			IDirect3DVolumeTexture9* m_texture3d;
379 			IDirect3DCubeTexture9*   m_textureCube;
380 		};
381 
382 		IDirect3DSurface9* m_surface;
383 
384 		union
385 		{
386 			IDirect3DBaseTexture9*   m_staging;
387 			IDirect3DTexture9*       m_staging2d;
388 			IDirect3DVolumeTexture9* m_staging3d;
389 			IDirect3DCubeTexture9*   m_stagingCube;
390 		};
391 
392 		uint64_t m_flags;
393 		uint32_t m_width;
394 		uint32_t m_height;
395 		uint32_t m_depth;
396 		uint8_t m_numMips;
397 		uint8_t m_type;
398 		uint8_t m_requestedFormat;
399 		uint8_t m_textureFormat;
400 	};
401 
402 	struct FrameBufferD3D9
403 	{
FrameBufferD3D9FrameBufferD3D9404 		FrameBufferD3D9()
405 			: m_hwnd(NULL)
406 			, m_denseIdx(UINT16_MAX)
407 			, m_num(0)
408 			, m_numTh(0)
409 			, m_dsIdx(UINT8_MAX)
410 			, m_needResolve(false)
411 			, m_needPresent(false)
412 		{
413 		}
414 
415 		void create(uint8_t _num, const Attachment* _attachment);
416 		void create(uint16_t _denseIdx, void* _nwh, uint32_t _width, uint32_t _height, TextureFormat::Enum _format, TextureFormat::Enum _depthFormat);
417 		uint16_t destroy();
418 		HRESULT present();
419 		void resolve() const;
420 		void preReset();
421 		void postReset();
422 		void createNullColorRT();
423 		void set();
424 
425 		IDirect3DSurface9* m_surface[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1];
426 		IDirect3DSwapChain9* m_swapChain;
427 		HWND m_hwnd;
428 		uint32_t m_width;
429 		uint32_t m_height;
430 
431 		Attachment m_attachment[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS];
432 		uint16_t m_denseIdx;
433 		uint8_t m_num;
434 		uint8_t m_numTh;
435 		uint8_t m_dsIdx;
436 		bool m_needResolve;
437 		bool m_needPresent;
438 	};
439 
440 	struct TimerQueryD3D9
441 	{
TimerQueryD3D9TimerQueryD3D9442 		TimerQueryD3D9()
443 			: m_control(BX_COUNTOF(m_query) )
444 		{
445 		}
446 
447 		void postReset();
448 		void preReset();
449 		uint32_t begin(uint32_t _resultIdx);
450 		void end(uint32_t _idx);
451 		bool update();
452 
453 		struct Query
454 		{
455 			IDirect3DQuery9* m_disjoint;
456 			IDirect3DQuery9* m_begin;
457 			IDirect3DQuery9* m_end;
458 			IDirect3DQuery9* m_freq;
459 			uint32_t         m_resultIdx;
460 			bool             m_ready;
461 		};
462 
463 		struct Result
464 		{
resetTimerQueryD3D9::Result465 			void reset()
466 			{
467 				m_begin     = 0;
468 				m_end       = 0;
469 				m_frequency = 1;
470 				m_pending   = 0;
471 			}
472 
473 			uint64_t m_begin;
474 			uint64_t m_end;
475 			uint64_t m_frequency;
476 			uint32_t m_pending;
477 		};
478 
479 		Result m_result[BGFX_CONFIG_MAX_VIEWS+1];
480 
481 		Query m_query[BGFX_CONFIG_MAX_VIEWS*4];
482 		bx::RingBufferControl m_control;
483 	};
484 
485 	struct OcclusionQueryD3D9
486 	{
OcclusionQueryD3D9OcclusionQueryD3D9487 		OcclusionQueryD3D9()
488 			: m_control(BX_COUNTOF(m_query) )
489 		{
490 		}
491 
492 		void postReset();
493 		void preReset();
494 		void begin(Frame* _render, OcclusionQueryHandle _handle);
495 		void end();
496 		void resolve(Frame* _render, bool _wait = false);
497 		void invalidate(OcclusionQueryHandle _handle);
498 
499 		struct Query
500 		{
501 			IDirect3DQuery9* m_ptr;
502 			OcclusionQueryHandle m_handle;
503 		};
504 
505 		Query m_query[BGFX_CONFIG_MAX_OCCLUSION_QUERIES];
506 		bx::RingBufferControl m_control;
507 	};
508 
509 } /* namespace d3d9 */ } // namespace bgfx
510 
511 #endif // BGFX_RENDERER_D3D9_H_HEADER_GUARD
512