2015-05-23 22:55:12 -06:00
|
|
|
// Copyright 2010 Dolphin Emulator Project
|
2021-07-04 19:22:19 -06:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2010-06-13 13:50:06 -06:00
|
|
|
|
2020-09-15 06:50:34 -06:00
|
|
|
#include "VideoBackends/D3D/D3DRender.h"
|
2017-01-23 09:20:20 -07:00
|
|
|
|
2017-12-25 16:38:44 -07:00
|
|
|
#include <algorithm>
|
2017-04-09 14:15:57 -06:00
|
|
|
#include <array>
|
2013-10-26 03:55:41 -06:00
|
|
|
#include <cmath>
|
2017-04-09 15:27:20 -06:00
|
|
|
#include <cstring>
|
2015-12-22 16:47:20 -07:00
|
|
|
#include <memory>
|
2014-05-25 18:52:58 -06:00
|
|
|
#include <string>
|
2014-02-17 03:18:15 -07:00
|
|
|
#include <strsafe.h>
|
2017-04-09 13:05:24 -06:00
|
|
|
#include <tuple>
|
2010-06-13 13:50:06 -06:00
|
|
|
|
2017-09-08 03:42:56 -06:00
|
|
|
#include "Common/Assert.h"
|
2016-01-17 14:54:31 -07:00
|
|
|
#include "Common/CommonTypes.h"
|
2017-02-01 08:56:13 -07:00
|
|
|
#include "Common/Logging/Log.h"
|
2015-05-06 16:37:58 -06:00
|
|
|
#include "Common/MathUtil.h"
|
2010-06-13 13:50:06 -06:00
|
|
|
|
2014-02-19 04:14:09 -07:00
|
|
|
#include "Core/Core.h"
|
2011-01-25 09:43:08 -07:00
|
|
|
|
2014-02-17 03:18:15 -07:00
|
|
|
#include "VideoBackends/D3D/D3DBase.h"
|
2020-09-15 06:50:34 -06:00
|
|
|
#include "VideoBackends/D3D/D3DBoundingBox.h"
|
2014-06-23 00:11:07 -06:00
|
|
|
#include "VideoBackends/D3D/D3DState.h"
|
2020-09-15 06:50:34 -06:00
|
|
|
#include "VideoBackends/D3D/D3DSwapChain.h"
|
2017-09-08 03:42:56 -06:00
|
|
|
#include "VideoBackends/D3D/DXPipeline.h"
|
|
|
|
#include "VideoBackends/D3D/DXShader.h"
|
2017-05-29 16:02:09 -06:00
|
|
|
#include "VideoBackends/D3D/DXTexture.h"
|
2014-02-17 03:18:15 -07:00
|
|
|
|
|
|
|
#include "VideoCommon/BPFunctions.h"
|
2019-02-14 18:59:50 -07:00
|
|
|
#include "VideoCommon/FramebufferManager.h"
|
|
|
|
#include "VideoCommon/PostProcessing.h"
|
2023-01-26 21:03:15 -07:00
|
|
|
#include "VideoCommon/Present.h"
|
2017-04-29 08:54:22 -06:00
|
|
|
#include "VideoCommon/RenderState.h"
|
2017-09-02 20:30:34 -06:00
|
|
|
#include "VideoCommon/VideoConfig.h"
|
2017-02-01 08:56:13 -07:00
|
|
|
#include "VideoCommon/XFMemory.h"
|
2010-06-13 13:50:06 -06:00
|
|
|
|
2011-01-29 13:16:51 -07:00
|
|
|
namespace DX11
|
|
|
|
{
|
2019-03-09 06:31:36 -07:00
|
|
|
Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale)
|
|
|
|
: ::Renderer(swap_chain ? swap_chain->GetWidth() : 0, swap_chain ? swap_chain->GetHeight() : 0,
|
|
|
|
backbuffer_scale,
|
|
|
|
swap_chain ? swap_chain->GetFormat() : AbstractTextureFormat::Undefined),
|
|
|
|
m_swap_chain(std::move(swap_chain))
|
2017-11-21 02:53:38 -07:00
|
|
|
{
|
2010-06-13 13:50:06 -06:00
|
|
|
}
|
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
Renderer::~Renderer() = default;
|
|
|
|
|
2018-10-03 07:03:13 -06:00
|
|
|
bool Renderer::IsHeadless() const
|
|
|
|
{
|
2019-03-09 06:31:36 -07:00
|
|
|
return !m_swap_chain;
|
2018-10-03 07:03:13 -06:00
|
|
|
}
|
|
|
|
|
2021-08-27 23:30:05 -06:00
|
|
|
std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config,
|
|
|
|
std::string_view name)
|
2017-09-30 00:25:36 -06:00
|
|
|
{
|
2021-08-27 23:30:05 -06:00
|
|
|
return DXTexture::Create(config, name);
|
2017-09-30 00:25:36 -06:00
|
|
|
}
|
|
|
|
|
2017-10-21 08:49:40 -06:00
|
|
|
std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTextureType type,
|
|
|
|
const TextureConfig& config)
|
|
|
|
{
|
|
|
|
return DXStagingTexture::Create(type, config);
|
|
|
|
}
|
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment,
|
|
|
|
AbstractTexture* depth_attachment)
|
2018-01-21 03:22:45 -07:00
|
|
|
{
|
2019-02-14 18:59:50 -07:00
|
|
|
return DXFramebuffer::Create(static_cast<DXTexture*>(color_attachment),
|
|
|
|
static_cast<DXTexture*>(depth_attachment));
|
2018-01-21 03:22:45 -07:00
|
|
|
}
|
|
|
|
|
2021-08-27 23:30:05 -06:00
|
|
|
std::unique_ptr<AbstractShader>
|
|
|
|
Renderer::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name)
|
2017-09-08 03:42:56 -06:00
|
|
|
{
|
2019-07-26 17:34:27 -06:00
|
|
|
auto bytecode = DXShader::CompileShader(D3D::feature_level, stage, source);
|
|
|
|
if (!bytecode)
|
2019-03-09 06:31:36 -07:00
|
|
|
return nullptr;
|
|
|
|
|
2021-08-27 23:30:05 -06:00
|
|
|
return DXShader::CreateFromBytecode(stage, std::move(*bytecode), name);
|
2017-09-08 03:42:56 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage,
|
2021-08-27 23:30:05 -06:00
|
|
|
const void* data, size_t length,
|
|
|
|
std::string_view name)
|
2017-09-08 03:42:56 -06:00
|
|
|
{
|
2021-08-27 23:30:05 -06:00
|
|
|
return DXShader::CreateFromBytecode(stage, DXShader::CreateByteCode(data, length), name);
|
2017-09-08 03:42:56 -06:00
|
|
|
}
|
|
|
|
|
2019-04-15 05:55:26 -06:00
|
|
|
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config,
|
|
|
|
const void* cache_data,
|
|
|
|
size_t cache_data_length)
|
2017-09-08 03:42:56 -06:00
|
|
|
{
|
|
|
|
return DXPipeline::Create(config);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::SetPipeline(const AbstractPipeline* pipeline)
|
|
|
|
{
|
|
|
|
const DXPipeline* dx_pipeline = static_cast<const DXPipeline*>(pipeline);
|
2019-02-14 18:59:50 -07:00
|
|
|
if (m_current_pipeline == dx_pipeline)
|
2018-02-24 06:13:00 -07:00
|
|
|
return;
|
2017-09-08 03:42:56 -06:00
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
if (dx_pipeline)
|
2016-05-01 08:29:36 -06:00
|
|
|
{
|
2019-02-14 18:59:50 -07:00
|
|
|
D3D::stateman->SetRasterizerState(dx_pipeline->GetRasterizerState());
|
|
|
|
D3D::stateman->SetDepthState(dx_pipeline->GetDepthState());
|
|
|
|
D3D::stateman->SetBlendState(dx_pipeline->GetBlendState());
|
|
|
|
D3D::stateman->SetPrimitiveTopology(dx_pipeline->GetPrimitiveTopology());
|
|
|
|
D3D::stateman->SetInputLayout(dx_pipeline->GetInputLayout());
|
|
|
|
D3D::stateman->SetVertexShader(dx_pipeline->GetVertexShader());
|
|
|
|
D3D::stateman->SetGeometryShader(dx_pipeline->GetGeometryShader());
|
|
|
|
D3D::stateman->SetPixelShader(dx_pipeline->GetPixelShader());
|
|
|
|
D3D::stateman->SetIntegerRTV(dx_pipeline->UseLogicOp());
|
2016-05-01 08:29:36 -06:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-02-14 18:59:50 -07:00
|
|
|
// These will be destroyed at pipeline destruction.
|
|
|
|
D3D::stateman->SetInputLayout(nullptr);
|
|
|
|
D3D::stateman->SetVertexShader(nullptr);
|
|
|
|
D3D::stateman->SetGeometryShader(nullptr);
|
|
|
|
D3D::stateman->SetPixelShader(nullptr);
|
2010-06-13 13:50:06 -06:00
|
|
|
}
|
2015-12-18 22:45:21 -07:00
|
|
|
}
|
2010-10-22 13:40:05 -06:00
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc)
|
2015-12-18 22:45:21 -07:00
|
|
|
{
|
2019-02-14 18:59:50 -07:00
|
|
|
// TODO: Move to stateman
|
|
|
|
const CD3D11_RECT rect(rc.left, rc.top, std::max(rc.right, rc.left + 1),
|
|
|
|
std::max(rc.bottom, rc.top + 1));
|
|
|
|
D3D::context->RSSetScissorRects(1, &rect);
|
2010-06-13 13:50:06 -06:00
|
|
|
}
|
|
|
|
|
2018-01-21 05:04:15 -07:00
|
|
|
void Renderer::SetViewport(float x, float y, float width, float height, float near_depth,
|
|
|
|
float far_depth)
|
2010-06-13 13:50:06 -06:00
|
|
|
{
|
2019-02-14 18:59:50 -07:00
|
|
|
// TODO: Move to stateman
|
|
|
|
const CD3D11_VIEWPORT vp(x, y, width, height, near_depth, far_depth);
|
2011-06-11 13:37:21 -06:00
|
|
|
D3D::context->RSSetViewports(1, &vp);
|
2010-06-13 13:50:06 -06:00
|
|
|
}
|
2010-09-27 20:15:02 -06:00
|
|
|
|
2018-11-27 00:16:53 -07:00
|
|
|
void Renderer::Draw(u32 base_vertex, u32 num_vertices)
|
|
|
|
{
|
|
|
|
D3D::stateman->Apply();
|
|
|
|
D3D::context->Draw(num_vertices, base_vertex);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
|
|
|
|
{
|
|
|
|
D3D::stateman->Apply();
|
|
|
|
D3D::context->DrawIndexed(num_indices, base_index, base_vertex);
|
|
|
|
}
|
|
|
|
|
2022-06-01 03:58:13 -06:00
|
|
|
void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
|
|
|
|
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
|
2010-12-27 14:56:20 -07:00
|
|
|
{
|
2019-02-14 18:59:50 -07:00
|
|
|
D3D::stateman->SetComputeShader(static_cast<const DXShader*>(shader)->GetD3DComputeShader());
|
|
|
|
D3D::stateman->SyncComputeBindings();
|
|
|
|
D3D::context->Dispatch(groups_x, groups_y, groups_z);
|
2010-12-27 14:56:20 -07:00
|
|
|
}
|
|
|
|
|
2018-11-27 21:30:47 -07:00
|
|
|
void Renderer::BindBackbuffer(const ClearColor& clear_color)
|
2010-06-13 13:50:06 -06:00
|
|
|
{
|
2019-03-09 06:31:36 -07:00
|
|
|
CheckForSwapChainChanges();
|
|
|
|
SetAndClearFramebuffer(m_swap_chain->GetFramebuffer(), clear_color);
|
2018-11-27 21:30:47 -07:00
|
|
|
}
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2018-11-27 21:30:47 -07:00
|
|
|
void Renderer::PresentBackbuffer()
|
|
|
|
{
|
2019-03-09 06:31:36 -07:00
|
|
|
m_swap_chain->Present();
|
2018-11-27 21:30:47 -07:00
|
|
|
}
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2018-11-27 21:30:47 -07:00
|
|
|
void Renderer::OnConfigChanged(u32 bits)
|
|
|
|
{
|
2019-03-09 06:31:36 -07:00
|
|
|
// Quad-buffer changes require swap chain recreation.
|
|
|
|
if (bits & CONFIG_CHANGE_BIT_STEREO_MODE && m_swap_chain)
|
|
|
|
m_swap_chain->SetStereo(SwapChain::WantsStereo());
|
2010-06-13 13:50:06 -06:00
|
|
|
}
|
|
|
|
|
2019-03-09 06:31:36 -07:00
|
|
|
void Renderer::CheckForSwapChainChanges()
|
2018-01-25 23:23:24 -07:00
|
|
|
{
|
2023-01-26 21:03:15 -07:00
|
|
|
const bool surface_changed = g_presenter->SurfaceChangedTestAndClear();
|
2019-03-09 06:31:36 -07:00
|
|
|
const bool surface_resized =
|
2023-01-26 21:03:15 -07:00
|
|
|
g_presenter->SurfaceResizedTestAndClear() || m_swap_chain->CheckForFullscreenChange();
|
2019-03-09 06:31:36 -07:00
|
|
|
if (!surface_changed && !surface_resized)
|
2018-01-25 23:23:24 -07:00
|
|
|
return;
|
|
|
|
|
2019-03-09 06:31:36 -07:00
|
|
|
if (surface_changed)
|
2018-01-25 23:23:24 -07:00
|
|
|
{
|
2023-01-26 21:03:15 -07:00
|
|
|
m_swap_chain->ChangeSurface(g_presenter->GetNewSurfaceHandle());
|
2018-01-25 23:23:24 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-03-09 06:31:36 -07:00
|
|
|
m_swap_chain->ResizeSwapChain();
|
2018-01-25 23:23:24 -07:00
|
|
|
}
|
2019-03-09 06:31:36 -07:00
|
|
|
|
|
|
|
m_backbuffer_width = m_swap_chain->GetWidth();
|
|
|
|
m_backbuffer_height = m_swap_chain->GetHeight();
|
2018-01-25 23:23:24 -07:00
|
|
|
}
|
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
|
2010-06-13 13:50:06 -06:00
|
|
|
{
|
2019-02-14 18:59:50 -07:00
|
|
|
if (m_current_framebuffer == framebuffer)
|
|
|
|
return;
|
2010-06-13 13:50:06 -06:00
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
// We can't leave the framebuffer bound as a texture and a render target.
|
|
|
|
DXFramebuffer* fb = static_cast<DXFramebuffer*>(framebuffer);
|
|
|
|
if ((fb->GetColorAttachment() &&
|
|
|
|
D3D::stateman->UnsetTexture(
|
|
|
|
static_cast<DXTexture*>(fb->GetColorAttachment())->GetD3DSRV()) != 0) ||
|
|
|
|
(fb->GetDepthAttachment() &&
|
|
|
|
D3D::stateman->UnsetTexture(
|
|
|
|
static_cast<DXTexture*>(fb->GetDepthAttachment())->GetD3DSRV()) != 0))
|
|
|
|
{
|
|
|
|
D3D::stateman->ApplyTextures();
|
|
|
|
}
|
2010-06-13 13:50:06 -06:00
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
D3D::stateman->SetFramebuffer(fb);
|
2018-01-21 03:22:45 -07:00
|
|
|
m_current_framebuffer = fb;
|
|
|
|
}
|
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
|
2018-01-21 03:22:45 -07:00
|
|
|
{
|
|
|
|
SetFramebuffer(framebuffer);
|
|
|
|
}
|
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
|
2018-01-21 03:22:45 -07:00
|
|
|
const ClearColor& color_value, float depth_value)
|
|
|
|
{
|
|
|
|
SetFramebuffer(framebuffer);
|
2019-02-14 18:59:50 -07:00
|
|
|
D3D::stateman->Apply();
|
|
|
|
|
2018-01-21 03:22:45 -07:00
|
|
|
if (framebuffer->GetColorFormat() != AbstractTextureFormat::Undefined)
|
|
|
|
{
|
|
|
|
D3D::context->ClearRenderTargetView(
|
|
|
|
static_cast<const DXFramebuffer*>(framebuffer)->GetRTVArray()[0], color_value.data());
|
|
|
|
}
|
|
|
|
if (framebuffer->GetDepthFormat() != AbstractTextureFormat::Undefined)
|
|
|
|
{
|
|
|
|
D3D::context->ClearDepthStencilView(static_cast<const DXFramebuffer*>(framebuffer)->GetDSV(),
|
|
|
|
D3D11_CLEAR_DEPTH, depth_value, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-21 06:13:25 -07:00
|
|
|
void Renderer::SetTexture(u32 index, const AbstractTexture* texture)
|
|
|
|
{
|
2019-02-14 18:59:50 -07:00
|
|
|
D3D::stateman->SetTexture(index, texture ? static_cast<const DXTexture*>(texture)->GetD3DSRV() :
|
|
|
|
nullptr);
|
2018-01-21 06:13:25 -07:00
|
|
|
}
|
|
|
|
|
2017-09-09 02:30:15 -06:00
|
|
|
void Renderer::SetSamplerState(u32 index, const SamplerState& state)
|
2010-06-13 13:50:06 -06:00
|
|
|
{
|
2018-02-24 08:15:35 -07:00
|
|
|
D3D::stateman->SetSampler(index, m_state_cache.Get(state));
|
2010-06-13 13:50:06 -06:00
|
|
|
}
|
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
void Renderer::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
|
2018-01-21 06:13:25 -07:00
|
|
|
{
|
2019-02-14 18:59:50 -07:00
|
|
|
D3D::stateman->SetComputeUAV(texture ? static_cast<DXTexture*>(texture)->GetD3DUAV() : nullptr);
|
2018-01-21 06:13:25 -07:00
|
|
|
}
|
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
void Renderer::UnbindTexture(const AbstractTexture* texture)
|
2010-06-13 13:50:06 -06:00
|
|
|
{
|
2019-02-14 18:59:50 -07:00
|
|
|
if (D3D::stateman->UnsetTexture(static_cast<const DXTexture*>(texture)->GetD3DSRV()) != 0)
|
|
|
|
D3D::stateman->ApplyTextures();
|
2010-06-13 13:50:06 -06:00
|
|
|
}
|
|
|
|
|
2021-06-09 05:42:21 -06:00
|
|
|
std::unique_ptr<BoundingBox> Renderer::CreateBoundingBox() const
|
2014-12-04 19:01:20 -07:00
|
|
|
{
|
2021-06-09 05:42:21 -06:00
|
|
|
return std::make_unique<D3DBoundingBox>();
|
2021-04-17 11:14:43 -06:00
|
|
|
}
|
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
void Renderer::Flush()
|
|
|
|
{
|
|
|
|
D3D::context->Flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::WaitForGPUIdle()
|
|
|
|
{
|
|
|
|
// There is no glFinish() equivalent in D3D.
|
|
|
|
D3D::context->Flush();
|
|
|
|
}
|
|
|
|
|
2016-11-08 17:07:56 -07:00
|
|
|
void Renderer::SetFullscreen(bool enable_fullscreen)
|
|
|
|
{
|
2019-03-09 06:31:36 -07:00
|
|
|
if (m_swap_chain)
|
|
|
|
m_swap_chain->SetFullscreen(enable_fullscreen);
|
2016-11-08 17:07:56 -07:00
|
|
|
}
|
|
|
|
|
2016-11-13 14:16:29 -07:00
|
|
|
bool Renderer::IsFullscreen() const
|
2016-11-08 17:41:38 -07:00
|
|
|
{
|
2019-03-09 06:31:36 -07:00
|
|
|
return m_swap_chain && m_swap_chain->GetFullscreen();
|
2016-11-08 17:41:38 -07:00
|
|
|
}
|
|
|
|
|
2012-01-06 05:45:51 -07:00
|
|
|
} // namespace DX11
|