Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/src/util/d3d11_device.h
7489 views
1
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <[email protected]>
2
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
3
4
#pragma once
5
6
#include "d3d11_stream_buffer.h"
7
#include "gpu_device.h"
8
9
#include "common/windows_headers.h"
10
11
#include <d3d11_1.h>
12
#include <dxgi1_5.h>
13
#include <memory>
14
#include <string>
15
#include <string_view>
16
#include <unordered_map>
17
#include <vector>
18
#include <wrl/client.h>
19
20
class D3D11Pipeline;
21
class D3D11Shader;
22
class D3D11Texture;
23
class D3D11TextureBuffer;
24
25
class D3D11Device final : public GPUDevice
26
{
27
public:
28
template<typename T>
29
using ComPtr = Microsoft::WRL::ComPtr<T>;
30
31
D3D11Device();
32
~D3D11Device();
33
34
ALWAYS_INLINE static D3D11Device& GetInstance() { return *static_cast<D3D11Device*>(g_gpu_device.get()); }
35
ALWAYS_INLINE static ID3D11Device1* GetD3DDevice() { return GetInstance().m_device.Get(); }
36
ALWAYS_INLINE static ID3D11DeviceContext1* GetD3DContext() { return GetInstance().m_context.Get(); }
37
ALWAYS_INLINE static IDXGIFactory5* GetDXGIFactory() { return GetInstance().m_dxgi_factory.Get(); }
38
ALWAYS_INLINE static D3D_FEATURE_LEVEL GetMaxFeatureLevel() { return GetInstance().m_max_feature_level; }
39
40
std::string GetDriverInfo() const override;
41
42
void FlushCommands() override;
43
void WaitForGPUIdle() override;
44
45
std::unique_ptr<GPUSwapChain> CreateSwapChain(const WindowInfo& wi, GPUVSyncMode vsync_mode,
46
const ExclusiveFullscreenMode* exclusive_fullscreen_mode,
47
std::optional<bool> exclusive_fullscreen_control,
48
Error* error) override;
49
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
50
GPUTexture::Type type, GPUTextureFormat format, GPUTexture::Flags flags,
51
const void* data = nullptr, u32 data_stride = 0,
52
Error* error = nullptr) override;
53
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config, Error* error = nullptr) override;
54
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements,
55
Error* error = nullptr) override;
56
57
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTextureFormat format,
58
Error* error = nullptr) override;
59
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTextureFormat format,
60
void* memory, size_t memory_size, u32 memory_stride,
61
Error* error = nullptr) override;
62
63
bool SupportsTextureFormat(GPUTextureFormat format) const override;
64
void CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src,
65
u32 src_x, u32 src_y, u32 src_layer, u32 src_level, u32 width, u32 height) override;
66
void ResolveTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src,
67
u32 src_x, u32 src_y, u32 width, u32 height) override;
68
void ClearRenderTarget(GPUTexture* t, u32 c) override;
69
void ClearDepth(GPUTexture* t, float d) override;
70
void InvalidateRenderTarget(GPUTexture* t) override;
71
72
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
73
Error* error) override;
74
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
75
std::string_view source, const char* entry_point,
76
DynamicHeapArray<u8>* out_binary, Error* error) override;
77
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) override;
78
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::ComputeConfig& config, Error* error) override;
79
80
#ifdef ENABLE_GPU_OBJECT_NAMES
81
void PushDebugGroup(const char* name) override;
82
void PopDebugGroup() override;
83
void InsertDebugMessage(const char* msg) override;
84
#endif
85
86
void MapVertexBuffer(u32 vertex_size, u32 vertex_count, void** map_ptr, u32* map_space,
87
u32* map_base_vertex) override;
88
void UnmapVertexBuffer(u32 vertex_size, u32 vertex_count) override;
89
void MapIndexBuffer(u32 index_count, DrawIndex** map_ptr, u32* map_space, u32* map_base_index) override;
90
void UnmapIndexBuffer(u32 used_index_count) override;
91
void* MapUniformBuffer(u32 size) override;
92
void UnmapUniformBuffer(u32 size) override;
93
void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
94
GPUPipeline::RenderPassFlag flags = GPUPipeline::NoRenderPassFlags) override;
95
void SetPipeline(GPUPipeline* pipeline) override;
96
void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) override;
97
void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) override;
98
void SetViewport(const GSVector4i rc) override;
99
void SetScissor(const GSVector4i rc) override;
100
void Draw(u32 vertex_count, u32 base_vertex) override;
101
void DrawWithPushConstants(u32 vertex_count, u32 base_vertex, const void* push_constants,
102
u32 push_constants_size) override;
103
void DrawIndexed(u32 index_count, u32 base_index, u32 base_vertex) override;
104
void DrawIndexedWithPushConstants(u32 index_count, u32 base_index, u32 base_vertex, const void* push_constants,
105
u32 push_constants_size) override;
106
void Dispatch(u32 threads_x, u32 threads_y, u32 threads_z, u32 group_size_x, u32 group_size_y,
107
u32 group_size_z) override;
108
void DispatchWithPushConstants(u32 threads_x, u32 threads_y, u32 threads_z, u32 group_size_x, u32 group_size_y,
109
u32 group_size_z, const void* push_constants, u32 push_constants_size) override;
110
111
bool SetGPUTimingEnabled(bool enabled) override;
112
float GetAndResetAccumulatedGPUTime() override;
113
114
PresentResult BeginPresent(GPUSwapChain* swap_chain, u32 clear_color) override;
115
void EndPresent(GPUSwapChain* swap_chain, bool explicit_present, u64 present_time) override;
116
void SubmitPresent(GPUSwapChain* swap_chain) override;
117
118
void UnbindPipeline(D3D11Pipeline* pl);
119
void UnbindTexture(D3D11Texture* tex);
120
121
protected:
122
bool CreateDeviceAndMainSwapChain(std::string_view adapter, CreateFlags create_flags, const WindowInfo& wi,
123
GPUVSyncMode vsync_mode, const ExclusiveFullscreenMode* exclusive_fullscreen_mode,
124
std::optional<bool> exclusive_fullscreen_control, Error* error) override;
125
void DestroyDevice() override;
126
127
private:
128
using BlendStateMapKey = std::pair<u64, u32>;
129
struct BlendStateMapHash
130
{
131
size_t operator()(const BlendStateMapKey& key) const;
132
};
133
using RasterizationStateMap = std::unordered_map<u16, ComPtr<ID3D11RasterizerState>>;
134
using DepthStateMap = std::unordered_map<u8, ComPtr<ID3D11DepthStencilState>>;
135
using BlendStateMap = std::unordered_map<BlendStateMapKey, ComPtr<ID3D11BlendState>, BlendStateMapHash>;
136
using InputLayoutMap =
137
std::unordered_map<GPUPipeline::InputLayout, ComPtr<ID3D11InputLayout>, GPUPipeline::InputLayoutHash>;
138
139
static constexpr u32 VERTEX_BUFFER_SIZE = 8 * 1024 * 1024;
140
static constexpr u32 INDEX_BUFFER_SIZE = 4 * 1024 * 1024;
141
static constexpr u32 MAX_UNIFORM_BUFFER_SIZE = 2 * 1024 * 1024;
142
static constexpr u32 MIN_UNIFORM_BUFFER_SIZE = 16;
143
static constexpr u32 UNIFORM_BUFFER_ALIGNMENT = 256;
144
static constexpr u32 UNIFORM_BUFFER_ALIGNMENT_DISCARD = 16;
145
static constexpr u32 PUSH_CONSTANT_BUFFER_SIZE = 128;
146
static constexpr u8 NUM_TIMESTAMP_QUERIES = 3;
147
148
void SetFeatures(CreateFlags create_flags);
149
150
bool CreateBuffers(Error* error);
151
void DestroyBuffers();
152
void BindUniformBuffer(u32 offset, u32 size);
153
void PushUniformBuffer(const void* data, u32 data_size);
154
void UnbindComputePipeline();
155
156
bool IsRenderTargetBound(const D3D11Texture* tex) const;
157
158
ComPtr<ID3D11RasterizerState> GetRasterizationState(const GPUPipeline::RasterizationState& rs, Error* error);
159
ComPtr<ID3D11DepthStencilState> GetDepthState(const GPUPipeline::DepthState& ds, Error* error);
160
ComPtr<ID3D11BlendState> GetBlendState(const GPUPipeline::BlendState& bs, u32 num_rts, Error* error);
161
ComPtr<ID3D11InputLayout> GetInputLayout(const GPUPipeline::InputLayout& il, const D3D11Shader* vs, Error* error);
162
163
bool CreateTimestampQueries();
164
void DestroyTimestampQueries();
165
void PopTimestampQuery();
166
void EndTimestampQuery();
167
void StartTimestampQuery();
168
169
ComPtr<ID3D11Device1> m_device;
170
ComPtr<ID3D11DeviceContext1> m_context;
171
ComPtr<ID3DUserDefinedAnnotation> m_annotation;
172
173
ComPtr<IDXGIFactory5> m_dxgi_factory;
174
175
RasterizationStateMap m_rasterization_states;
176
DepthStateMap m_depth_states;
177
BlendStateMap m_blend_states;
178
InputLayoutMap m_input_layouts;
179
180
D3D_FEATURE_LEVEL m_max_feature_level = D3D_FEATURE_LEVEL_10_0;
181
182
D3D11StreamBuffer m_vertex_buffer;
183
D3D11StreamBuffer m_index_buffer;
184
D3D11StreamBuffer m_uniform_buffer;
185
ComPtr<ID3D11Buffer> m_push_constant_buffer;
186
187
D3D11Pipeline* m_current_pipeline = nullptr;
188
std::array<D3D11Texture*, MAX_RENDER_TARGETS> m_current_render_targets = {};
189
u32 m_num_current_render_targets = 0;
190
GPUPipeline::RenderPassFlag m_current_render_pass_flags = GPUPipeline::NoRenderPassFlags;
191
D3D11Texture* m_current_depth_target = nullptr;
192
193
ID3D11InputLayout* m_current_input_layout = nullptr;
194
ID3D11VertexShader* m_current_vertex_shader = nullptr;
195
ID3D11GeometryShader* m_current_geometry_shader = nullptr;
196
ID3D11PixelShader* m_current_pixel_shader = nullptr;
197
ID3D11ComputeShader* m_current_compute_shader = nullptr;
198
ID3D11RasterizerState* m_current_rasterizer_state = nullptr;
199
ID3D11DepthStencilState* m_current_depth_state = nullptr;
200
ID3D11BlendState* m_current_blend_state = nullptr;
201
D3D_PRIMITIVE_TOPOLOGY m_current_primitive_topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
202
u32 m_current_vertex_stride = 0;
203
u32 m_current_blend_factor = 0;
204
205
std::array<ID3D11ShaderResourceView*, MAX_TEXTURE_SAMPLERS> m_current_textures = {};
206
std::array<ID3D11SamplerState*, MAX_TEXTURE_SAMPLERS> m_current_samplers = {};
207
208
std::array<std::array<ComPtr<ID3D11Query>, 3>, NUM_TIMESTAMP_QUERIES> m_timestamp_queries = {};
209
u8 m_read_timestamp_query = 0;
210
u8 m_write_timestamp_query = 0;
211
u8 m_waiting_timestamp_queries = 0;
212
bool m_timestamp_query_started = false;
213
float m_accumulated_gpu_time = 0.0f;
214
};
215
216
class D3D11SwapChain : public GPUSwapChain
217
{
218
public:
219
template<typename T>
220
using ComPtr = Microsoft::WRL::ComPtr<T>;
221
222
friend D3D11Device;
223
224
D3D11SwapChain(const WindowInfo& wi, GPUVSyncMode vsync_mode,
225
const GPUDevice::ExclusiveFullscreenMode* fullscreen_mode);
226
~D3D11SwapChain() override;
227
228
ALWAYS_INLINE IDXGISwapChain1* GetSwapChain() const { return m_swap_chain.Get(); }
229
ALWAYS_INLINE ID3D11RenderTargetView* GetRTV() const { return m_swap_chain_rtv.Get(); }
230
ALWAYS_INLINE ID3D11RenderTargetView* const* GetRTVArray() const { return m_swap_chain_rtv.GetAddressOf(); }
231
ALWAYS_INLINE bool IsUsingAllowTearing() const { return m_using_allow_tearing; }
232
233
bool ResizeBuffers(u32 new_width, u32 new_height, Error* error) override;
234
bool SetVSyncMode(GPUVSyncMode mode, Error* error) override;
235
236
bool IsExclusiveFullscreen() const override;
237
238
private:
239
static u32 GetNewBufferCount(GPUVSyncMode vsync_mode);
240
241
bool InitializeExclusiveFullscreenMode(const GPUDevice::ExclusiveFullscreenMode* mode);
242
243
bool CreateSwapChain(Error* error);
244
bool CreateRTV(Error* error);
245
246
void DestroySwapChain();
247
248
ComPtr<IDXGISwapChain1> m_swap_chain;
249
ComPtr<ID3D11RenderTargetView> m_swap_chain_rtv;
250
251
ComPtr<IDXGIOutput> m_fullscreen_output;
252
std::optional<DXGI_MODE_DESC> m_fullscreen_mode;
253
254
bool m_using_flip_model_swap_chain = true;
255
bool m_using_allow_tearing = false;
256
};
257
258
void SetD3DDebugObjectName(ID3D11DeviceChild* obj, std::string_view name);
259
260