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