1 // Copyright 2010 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #include "VideoBackends/D3D/Render.h"
6 
7 #include <algorithm>
8 #include <array>
9 #include <cinttypes>
10 #include <cmath>
11 #include <cstring>
12 #include <memory>
13 #include <string>
14 #include <strsafe.h>
15 #include <tuple>
16 
17 #include "Common/Assert.h"
18 #include "Common/CommonTypes.h"
19 #include "Common/Logging/Log.h"
20 #include "Common/MathUtil.h"
21 
22 #include "Core/Core.h"
23 
24 #include "VideoBackends/D3D/BoundingBox.h"
25 #include "VideoBackends/D3D/D3DBase.h"
26 #include "VideoBackends/D3D/D3DState.h"
27 #include "VideoBackends/D3D/DXPipeline.h"
28 #include "VideoBackends/D3D/DXShader.h"
29 #include "VideoBackends/D3D/DXTexture.h"
30 #include "VideoBackends/D3D/SwapChain.h"
31 
32 #include "VideoCommon/BPFunctions.h"
33 #include "VideoCommon/FramebufferManager.h"
34 #include "VideoCommon/PostProcessing.h"
35 #include "VideoCommon/RenderState.h"
36 #include "VideoCommon/VideoConfig.h"
37 #include "VideoCommon/XFMemory.h"
38 
39 namespace DX11
40 {
Renderer(std::unique_ptr<SwapChain> swap_chain,float backbuffer_scale)41 Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale)
42     : ::Renderer(swap_chain ? swap_chain->GetWidth() : 0, swap_chain ? swap_chain->GetHeight() : 0,
43                  backbuffer_scale,
44                  swap_chain ? swap_chain->GetFormat() : AbstractTextureFormat::Undefined),
45       m_swap_chain(std::move(swap_chain))
46 {
47 }
48 
49 Renderer::~Renderer() = default;
50 
IsHeadless() const51 bool Renderer::IsHeadless() const
52 {
53   return !m_swap_chain;
54 }
55 
CreateTexture(const TextureConfig & config)56 std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config)
57 {
58   return DXTexture::Create(config);
59 }
60 
CreateStagingTexture(StagingTextureType type,const TextureConfig & config)61 std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTextureType type,
62                                                                        const TextureConfig& config)
63 {
64   return DXStagingTexture::Create(type, config);
65 }
66 
CreateFramebuffer(AbstractTexture * color_attachment,AbstractTexture * depth_attachment)67 std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment,
68                                                                  AbstractTexture* depth_attachment)
69 {
70   return DXFramebuffer::Create(static_cast<DXTexture*>(color_attachment),
71                                static_cast<DXTexture*>(depth_attachment));
72 }
73 
CreateShaderFromSource(ShaderStage stage,std::string_view source)74 std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
75                                                                  std::string_view source)
76 {
77   auto bytecode = DXShader::CompileShader(D3D::feature_level, stage, source);
78   if (!bytecode)
79     return nullptr;
80 
81   return DXShader::CreateFromBytecode(stage, std::move(*bytecode));
82 }
83 
CreateShaderFromBinary(ShaderStage stage,const void * data,size_t length)84 std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage,
85                                                                  const void* data, size_t length)
86 {
87   return DXShader::CreateFromBytecode(stage, DXShader::CreateByteCode(data, length));
88 }
89 
CreatePipeline(const AbstractPipelineConfig & config,const void * cache_data,size_t cache_data_length)90 std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config,
91                                                            const void* cache_data,
92                                                            size_t cache_data_length)
93 {
94   return DXPipeline::Create(config);
95 }
96 
SetPipeline(const AbstractPipeline * pipeline)97 void Renderer::SetPipeline(const AbstractPipeline* pipeline)
98 {
99   const DXPipeline* dx_pipeline = static_cast<const DXPipeline*>(pipeline);
100   if (m_current_pipeline == dx_pipeline)
101     return;
102 
103   if (dx_pipeline)
104   {
105     D3D::stateman->SetRasterizerState(dx_pipeline->GetRasterizerState());
106     D3D::stateman->SetDepthState(dx_pipeline->GetDepthState());
107     D3D::stateman->SetBlendState(dx_pipeline->GetBlendState());
108     D3D::stateman->SetPrimitiveTopology(dx_pipeline->GetPrimitiveTopology());
109     D3D::stateman->SetInputLayout(dx_pipeline->GetInputLayout());
110     D3D::stateman->SetVertexShader(dx_pipeline->GetVertexShader());
111     D3D::stateman->SetGeometryShader(dx_pipeline->GetGeometryShader());
112     D3D::stateman->SetPixelShader(dx_pipeline->GetPixelShader());
113     D3D::stateman->SetIntegerRTV(dx_pipeline->UseLogicOp());
114   }
115   else
116   {
117     // These will be destroyed at pipeline destruction.
118     D3D::stateman->SetInputLayout(nullptr);
119     D3D::stateman->SetVertexShader(nullptr);
120     D3D::stateman->SetGeometryShader(nullptr);
121     D3D::stateman->SetPixelShader(nullptr);
122   }
123 }
124 
SetScissorRect(const MathUtil::Rectangle<int> & rc)125 void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc)
126 {
127   // TODO: Move to stateman
128   const CD3D11_RECT rect(rc.left, rc.top, std::max(rc.right, rc.left + 1),
129                          std::max(rc.bottom, rc.top + 1));
130   D3D::context->RSSetScissorRects(1, &rect);
131 }
132 
SetViewport(float x,float y,float width,float height,float near_depth,float far_depth)133 void Renderer::SetViewport(float x, float y, float width, float height, float near_depth,
134                            float far_depth)
135 {
136   // TODO: Move to stateman
137   const CD3D11_VIEWPORT vp(x, y, width, height, near_depth, far_depth);
138   D3D::context->RSSetViewports(1, &vp);
139 }
140 
Draw(u32 base_vertex,u32 num_vertices)141 void Renderer::Draw(u32 base_vertex, u32 num_vertices)
142 {
143   D3D::stateman->Apply();
144   D3D::context->Draw(num_vertices, base_vertex);
145 }
146 
DrawIndexed(u32 base_index,u32 num_indices,u32 base_vertex)147 void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
148 {
149   D3D::stateman->Apply();
150   D3D::context->DrawIndexed(num_indices, base_index, base_vertex);
151 }
152 
DispatchComputeShader(const AbstractShader * shader,u32 groups_x,u32 groups_y,u32 groups_z)153 void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groups_x, u32 groups_y,
154                                      u32 groups_z)
155 {
156   D3D::stateman->SetComputeShader(static_cast<const DXShader*>(shader)->GetD3DComputeShader());
157   D3D::stateman->SyncComputeBindings();
158   D3D::context->Dispatch(groups_x, groups_y, groups_z);
159 }
160 
BindBackbuffer(const ClearColor & clear_color)161 void Renderer::BindBackbuffer(const ClearColor& clear_color)
162 {
163   CheckForSwapChainChanges();
164   SetAndClearFramebuffer(m_swap_chain->GetFramebuffer(), clear_color);
165 }
166 
PresentBackbuffer()167 void Renderer::PresentBackbuffer()
168 {
169   m_swap_chain->Present();
170 }
171 
OnConfigChanged(u32 bits)172 void Renderer::OnConfigChanged(u32 bits)
173 {
174   // Quad-buffer changes require swap chain recreation.
175   if (bits & CONFIG_CHANGE_BIT_STEREO_MODE && m_swap_chain)
176     m_swap_chain->SetStereo(SwapChain::WantsStereo());
177 }
178 
CheckForSwapChainChanges()179 void Renderer::CheckForSwapChainChanges()
180 {
181   const bool surface_changed = m_surface_changed.TestAndClear();
182   const bool surface_resized =
183       m_surface_resized.TestAndClear() || m_swap_chain->CheckForFullscreenChange();
184   if (!surface_changed && !surface_resized)
185     return;
186 
187   if (surface_changed)
188   {
189     m_swap_chain->ChangeSurface(m_new_surface_handle);
190     m_new_surface_handle = nullptr;
191   }
192   else
193   {
194     m_swap_chain->ResizeSwapChain();
195   }
196 
197   m_backbuffer_width = m_swap_chain->GetWidth();
198   m_backbuffer_height = m_swap_chain->GetHeight();
199 }
200 
SetFramebuffer(AbstractFramebuffer * framebuffer)201 void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
202 {
203   if (m_current_framebuffer == framebuffer)
204     return;
205 
206   // We can't leave the framebuffer bound as a texture and a render target.
207   DXFramebuffer* fb = static_cast<DXFramebuffer*>(framebuffer);
208   if ((fb->GetColorAttachment() &&
209        D3D::stateman->UnsetTexture(
210            static_cast<DXTexture*>(fb->GetColorAttachment())->GetD3DSRV()) != 0) ||
211       (fb->GetDepthAttachment() &&
212        D3D::stateman->UnsetTexture(
213            static_cast<DXTexture*>(fb->GetDepthAttachment())->GetD3DSRV()) != 0))
214   {
215     D3D::stateman->ApplyTextures();
216   }
217 
218   D3D::stateman->SetFramebuffer(fb);
219   m_current_framebuffer = fb;
220 }
221 
SetAndDiscardFramebuffer(AbstractFramebuffer * framebuffer)222 void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
223 {
224   SetFramebuffer(framebuffer);
225 }
226 
SetAndClearFramebuffer(AbstractFramebuffer * framebuffer,const ClearColor & color_value,float depth_value)227 void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
228                                       const ClearColor& color_value, float depth_value)
229 {
230   SetFramebuffer(framebuffer);
231   D3D::stateman->Apply();
232 
233   if (framebuffer->GetColorFormat() != AbstractTextureFormat::Undefined)
234   {
235     D3D::context->ClearRenderTargetView(
236         static_cast<const DXFramebuffer*>(framebuffer)->GetRTVArray()[0], color_value.data());
237   }
238   if (framebuffer->GetDepthFormat() != AbstractTextureFormat::Undefined)
239   {
240     D3D::context->ClearDepthStencilView(static_cast<const DXFramebuffer*>(framebuffer)->GetDSV(),
241                                         D3D11_CLEAR_DEPTH, depth_value, 0);
242   }
243 }
244 
SetTexture(u32 index,const AbstractTexture * texture)245 void Renderer::SetTexture(u32 index, const AbstractTexture* texture)
246 {
247   D3D::stateman->SetTexture(index, texture ? static_cast<const DXTexture*>(texture)->GetD3DSRV() :
248                                              nullptr);
249 }
250 
SetSamplerState(u32 index,const SamplerState & state)251 void Renderer::SetSamplerState(u32 index, const SamplerState& state)
252 {
253   D3D::stateman->SetSampler(index, m_state_cache.Get(state));
254 }
255 
SetComputeImageTexture(AbstractTexture * texture,bool read,bool write)256 void Renderer::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
257 {
258   D3D::stateman->SetComputeUAV(texture ? static_cast<DXTexture*>(texture)->GetD3DUAV() : nullptr);
259 }
260 
UnbindTexture(const AbstractTexture * texture)261 void Renderer::UnbindTexture(const AbstractTexture* texture)
262 {
263   if (D3D::stateman->UnsetTexture(static_cast<const DXTexture*>(texture)->GetD3DSRV()) != 0)
264     D3D::stateman->ApplyTextures();
265 }
266 
BBoxRead(int index)267 u16 Renderer::BBoxRead(int index)
268 {
269   return static_cast<u16>(BBox::Get(index));
270 }
271 
BBoxWrite(int index,u16 value)272 void Renderer::BBoxWrite(int index, u16 value)
273 {
274   BBox::Set(index, value);
275 }
276 
Flush()277 void Renderer::Flush()
278 {
279   D3D::context->Flush();
280 }
281 
WaitForGPUIdle()282 void Renderer::WaitForGPUIdle()
283 {
284   // There is no glFinish() equivalent in D3D.
285   D3D::context->Flush();
286 }
287 
SetFullscreen(bool enable_fullscreen)288 void Renderer::SetFullscreen(bool enable_fullscreen)
289 {
290   if (m_swap_chain)
291     m_swap_chain->SetFullscreen(enable_fullscreen);
292 }
293 
IsFullscreen() const294 bool Renderer::IsFullscreen() const
295 {
296   return m_swap_chain && m_swap_chain->GetFullscreen();
297 }
298 
299 }  // namespace DX11
300