Move most backend functionality to VideoCommon
This commit is contained in:
parent
933f3ba008
commit
f039149198
|
@ -10,6 +10,9 @@
|
|||
|
||||
class GLContext;
|
||||
|
||||
// Texture which we use to not disturb the other bindings.
|
||||
constexpr GLenum GL_MUTABLE_TEXTURE_INDEX = GL_TEXTURE10;
|
||||
|
||||
namespace GLUtil
|
||||
{
|
||||
GLuint CompileProgram(const std::string& vertexShader, const std::string& fragmentShader);
|
||||
|
|
|
@ -137,8 +137,6 @@ const ConfigInfo<int> GFX_STEREO_DEPTH_PERCENTAGE{
|
|||
|
||||
const ConfigInfo<bool> GFX_HACK_EFB_ACCESS_ENABLE{{System::GFX, "Hacks", "EFBAccessEnable"}, true};
|
||||
const ConfigInfo<bool> GFX_HACK_BBOX_ENABLE{{System::GFX, "Hacks", "BBoxEnable"}, false};
|
||||
const ConfigInfo<bool> GFX_HACK_BBOX_PREFER_STENCIL_IMPLEMENTATION{
|
||||
{System::GFX, "Hacks", "BBoxPreferStencilImplementation"}, false};
|
||||
const ConfigInfo<bool> GFX_HACK_FORCE_PROGRESSIVE{{System::GFX, "Hacks", "ForceProgressive"}, true};
|
||||
const ConfigInfo<bool> GFX_HACK_SKIP_EFB_COPY_TO_RAM{{System::GFX, "Hacks", "EFBToTextureEnable"},
|
||||
true};
|
||||
|
|
|
@ -102,7 +102,6 @@ extern const ConfigInfo<int> GFX_STEREO_DEPTH_PERCENTAGE;
|
|||
|
||||
extern const ConfigInfo<bool> GFX_HACK_EFB_ACCESS_ENABLE;
|
||||
extern const ConfigInfo<bool> GFX_HACK_BBOX_ENABLE;
|
||||
extern const ConfigInfo<bool> GFX_HACK_BBOX_PREFER_STENCIL_IMPLEMENTATION;
|
||||
extern const ConfigInfo<bool> GFX_HACK_FORCE_PROGRESSIVE;
|
||||
extern const ConfigInfo<bool> GFX_HACK_SKIP_EFB_COPY_TO_RAM;
|
||||
extern const ConfigInfo<bool> GFX_HACK_SKIP_XFB_COPY_TO_RAM;
|
||||
|
|
|
@ -114,7 +114,6 @@ bool IsSettingSaveable(const Config::ConfigLocation& config_location)
|
|||
|
||||
Config::GFX_HACK_EFB_ACCESS_ENABLE.location,
|
||||
Config::GFX_HACK_BBOX_ENABLE.location,
|
||||
Config::GFX_HACK_BBOX_PREFER_STENCIL_IMPLEMENTATION.location,
|
||||
Config::GFX_HACK_FORCE_PROGRESSIVE.location,
|
||||
Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM.location,
|
||||
Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM.location,
|
||||
|
|
|
@ -152,10 +152,9 @@ void EnhancementsWidget::ConnectWidgets()
|
|||
void EnhancementsWidget::LoadPPShaders()
|
||||
{
|
||||
const bool anaglyph = g_Config.stereo_mode == StereoMode::Anaglyph;
|
||||
std::vector<std::string> shaders =
|
||||
anaglyph ? PostProcessingShaderImplementation::GetAnaglyphShaderList(
|
||||
g_Config.backend_info.api_type) :
|
||||
PostProcessingShaderImplementation::GetShaderList(g_Config.backend_info.api_type);
|
||||
std::vector<std::string> shaders = anaglyph ?
|
||||
VideoCommon::PostProcessing::GetAnaglyphShaderList() :
|
||||
VideoCommon::PostProcessing::GetShaderList();
|
||||
|
||||
m_pp_effect->clear();
|
||||
|
||||
|
@ -187,7 +186,7 @@ void EnhancementsWidget::LoadPPShaders()
|
|||
tr("%1 doesn't support this feature.")
|
||||
.arg(tr(g_video_backend->GetDisplayName().c_str())));
|
||||
|
||||
PostProcessingShaderConfiguration pp_shader;
|
||||
VideoCommon::PostProcessingConfiguration pp_shader;
|
||||
if (selected_shader != "(off)" && supports_postprocessing)
|
||||
{
|
||||
pp_shader.LoadShader(selected_shader);
|
||||
|
@ -266,7 +265,7 @@ void EnhancementsWidget::SaveSettings()
|
|||
"(off)" :
|
||||
m_pp_effect->currentText().toStdString());
|
||||
|
||||
PostProcessingShaderConfiguration pp_shader;
|
||||
VideoCommon::PostProcessingConfiguration pp_shader;
|
||||
if (Config::Get(Config::GFX_ENHANCE_POST_SHADER) != "(off)")
|
||||
{
|
||||
pp_shader.LoadShader(Config::Get(Config::GFX_ENHANCE_POST_SHADER));
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
using ConfigurationOption = PostProcessingShaderConfiguration::ConfigurationOption;
|
||||
using ConfigurationOption = VideoCommon::PostProcessingConfiguration::ConfigurationOption;
|
||||
using OptionType = ConfigurationOption::OptionType;
|
||||
|
||||
PostProcessingConfigWindow::PostProcessingConfigWindow(EnhancementsWidget* parent,
|
||||
|
@ -38,7 +38,7 @@ PostProcessingConfigWindow::PostProcessingConfigWindow(EnhancementsWidget* paren
|
|||
}
|
||||
else
|
||||
{
|
||||
m_post_processor = new PostProcessingShaderConfiguration();
|
||||
m_post_processor = new VideoCommon::PostProcessingConfiguration();
|
||||
m_post_processor->LoadShader(m_shader);
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,8 @@ PostProcessingConfigWindow::~PostProcessingConfigWindow()
|
|||
|
||||
void PostProcessingConfigWindow::PopulateGroups()
|
||||
{
|
||||
const PostProcessingShaderConfiguration::ConfigMap& config_map = m_post_processor->GetOptions();
|
||||
const VideoCommon::PostProcessingConfiguration::ConfigMap& config_map =
|
||||
m_post_processor->GetOptions();
|
||||
|
||||
auto config_groups = std::vector<std::unique_ptr<ConfigGroup>>();
|
||||
for (const auto& it : config_map)
|
||||
|
|
|
@ -35,7 +35,7 @@ private:
|
|||
{
|
||||
public:
|
||||
explicit ConfigGroup(
|
||||
const PostProcessingShaderConfiguration::ConfigurationOption* config_option);
|
||||
const VideoCommon::PostProcessingConfiguration::ConfigurationOption* config_option);
|
||||
|
||||
const std::string& GetGUIName() const noexcept;
|
||||
const std::string& GetParent() const noexcept;
|
||||
|
@ -57,7 +57,7 @@ private:
|
|||
std::vector<QSlider*> m_sliders;
|
||||
std::vector<QLineEdit*> m_value_boxes;
|
||||
|
||||
const PostProcessingShaderConfiguration::ConfigurationOption* m_config_option;
|
||||
const VideoCommon::PostProcessingConfiguration::ConfigurationOption* m_config_option;
|
||||
std::vector<std::unique_ptr<ConfigGroup>> m_subgroups;
|
||||
};
|
||||
void Create();
|
||||
|
@ -72,7 +72,7 @@ private:
|
|||
QDialogButtonBox* m_buttons;
|
||||
|
||||
const std::string& m_shader;
|
||||
PostProcessingShaderConfiguration* m_post_processor;
|
||||
VideoCommon::PostProcessingConfiguration* m_post_processor;
|
||||
std::unordered_map<std::string, ConfigGroup*> m_config_map;
|
||||
std::vector<std::unique_ptr<ConfigGroup>> m_config_groups;
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "VideoBackends/D3D/BoundingBox.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace DX11
|
||||
|
@ -54,6 +55,7 @@ void BBox::Init()
|
|||
hr = D3D::device->CreateUnorderedAccessView(s_bbox_buffer, &UAVdesc, &s_bbox_uav);
|
||||
CHECK(SUCCEEDED(hr), "Create BoundingBox UAV.");
|
||||
D3D::SetDebugObjectName(s_bbox_uav, "BoundingBox UAV");
|
||||
D3D::stateman->SetOMUAV(s_bbox_uav);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,4 +85,4 @@ int BBox::Get(int index)
|
|||
D3D::context->Unmap(s_bbox_staging_buffer, 0);
|
||||
return data;
|
||||
}
|
||||
};
|
||||
}; // namespace DX11
|
||||
|
|
|
@ -3,42 +3,22 @@ add_library(videod3d
|
|||
BoundingBox.h
|
||||
D3DBase.cpp
|
||||
D3DBase.h
|
||||
D3DBlob.cpp
|
||||
D3DBlob.h
|
||||
D3DShader.cpp
|
||||
D3DShader.h
|
||||
D3DState.cpp
|
||||
D3DState.h
|
||||
D3DTexture.cpp
|
||||
D3DTexture.h
|
||||
D3DUtil.cpp
|
||||
D3DUtil.h
|
||||
DXPipeline.cpp
|
||||
DXPipeline.h
|
||||
DXShader.cpp
|
||||
DXShader.h
|
||||
DXTexture.cpp
|
||||
DXTexture.h
|
||||
FramebufferManager.cpp
|
||||
FramebufferManager.h
|
||||
GeometryShaderCache.cpp
|
||||
GeometryShaderCache.h
|
||||
main.cpp
|
||||
NativeVertexFormat.cpp
|
||||
PerfQuery.cpp
|
||||
PerfQuery.h
|
||||
PixelShaderCache.cpp
|
||||
PixelShaderCache.h
|
||||
PSTextureEncoder.cpp
|
||||
PSTextureEncoder.h
|
||||
Render.cpp
|
||||
Render.h
|
||||
TextureCache.cpp
|
||||
TextureCache.h
|
||||
VertexManager.cpp
|
||||
VertexManager.h
|
||||
VertexShaderCache.cpp
|
||||
VertexShaderCache.h
|
||||
VideoBackend.h
|
||||
)
|
||||
|
||||
|
|
|
@ -38,46 +38,26 @@
|
|||
<ItemGroup>
|
||||
<ClCompile Include="BoundingBox.cpp" />
|
||||
<ClCompile Include="D3DBase.cpp" />
|
||||
<ClCompile Include="D3DBlob.cpp" />
|
||||
<ClCompile Include="D3DShader.cpp" />
|
||||
<ClCompile Include="D3DState.cpp" />
|
||||
<ClCompile Include="D3DTexture.cpp" />
|
||||
<ClCompile Include="D3DUtil.cpp" />
|
||||
<ClCompile Include="DXPipeline.cpp" />
|
||||
<ClCompile Include="DXShader.cpp" />
|
||||
<ClCompile Include="DXTexture.cpp" />
|
||||
<ClCompile Include="FramebufferManager.cpp" />
|
||||
<ClCompile Include="GeometryShaderCache.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="NativeVertexFormat.cpp" />
|
||||
<ClCompile Include="PerfQuery.cpp" />
|
||||
<ClCompile Include="PixelShaderCache.cpp" />
|
||||
<ClCompile Include="PSTextureEncoder.cpp" />
|
||||
<ClCompile Include="Render.cpp" />
|
||||
<ClCompile Include="TextureCache.cpp" />
|
||||
<ClCompile Include="VertexManager.cpp" />
|
||||
<ClCompile Include="VertexShaderCache.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="BoundingBox.h" />
|
||||
<ClInclude Include="D3DBase.h" />
|
||||
<ClInclude Include="D3DBlob.h" />
|
||||
<ClInclude Include="D3DShader.h" />
|
||||
<ClInclude Include="D3DState.h" />
|
||||
<ClInclude Include="D3DTexture.h" />
|
||||
<ClInclude Include="D3DUtil.h" />
|
||||
<ClInclude Include="DXPipeline.h" />
|
||||
<ClInclude Include="DXShader.h" />
|
||||
<ClInclude Include="DXTexture.h" />
|
||||
<ClInclude Include="FramebufferManager.h" />
|
||||
<ClInclude Include="GeometryShaderCache.h" />
|
||||
<ClInclude Include="PerfQuery.h" />
|
||||
<ClInclude Include="PixelShaderCache.h" />
|
||||
<ClInclude Include="PSTextureEncoder.h" />
|
||||
<ClInclude Include="Render.h" />
|
||||
<ClInclude Include="TextureCache.h" />
|
||||
<ClInclude Include="VertexManager.h" />
|
||||
<ClInclude Include="VertexShaderCache.h" />
|
||||
<ClInclude Include="VideoBackend.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -12,51 +12,21 @@
|
|||
<ClCompile Include="D3DBase.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="D3DBlob.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="D3DShader.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="D3DTexture.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="D3DUtil.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="D3DState.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FramebufferManager.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeometryShaderCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NativeVertexFormat.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PerfQuery.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PixelShaderCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PSTextureEncoder.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Render.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TextureCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VertexManager.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VertexShaderCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="BoundingBox.cpp">
|
||||
<Filter>Render</Filter>
|
||||
|
@ -75,48 +45,18 @@
|
|||
<ClInclude Include="D3DBase.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="D3DBlob.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="D3DShader.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="D3DTexture.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="D3DUtil.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="D3DState.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FramebufferManager.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GeometryShaderCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PerfQuery.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PixelShaderCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PSTextureEncoder.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Render.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TextureCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VertexManager.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VertexShaderCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VideoBackend.h" />
|
||||
<ClInclude Include="BoundingBox.h">
|
||||
<Filter>Render</Filter>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "Core/ConfigManager.h"
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/D3DTexture.h"
|
||||
#include "VideoBackends/D3D/DXTexture.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace DX11
|
||||
|
@ -42,7 +42,8 @@ IDXGISwapChain1* swapchain = nullptr;
|
|||
static IDXGIFactory2* s_dxgi_factory;
|
||||
static ID3D11Debug* s_debug;
|
||||
static D3D_FEATURE_LEVEL s_featlevel;
|
||||
static D3DTexture2D* s_backbuf;
|
||||
static std::unique_ptr<DXTexture> s_swap_chain_texture;
|
||||
static std::unique_ptr<DXFramebuffer> s_swap_chain_framebuffer;
|
||||
|
||||
static std::vector<DXGI_SAMPLE_DESC> s_aa_modes; // supported AA modes of the current adapter
|
||||
|
||||
|
@ -244,18 +245,40 @@ static bool SupportsBPTCTextures(ID3D11Device* dev)
|
|||
return (bc7_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0;
|
||||
}
|
||||
|
||||
static bool CreateSwapChainTextures()
|
||||
static bool CreateSwapChainFramebuffer()
|
||||
{
|
||||
ID3D11Texture2D* buf;
|
||||
HRESULT hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf);
|
||||
ID3D11Texture2D* texture;
|
||||
HRESULT hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&texture);
|
||||
CHECK(SUCCEEDED(hr), "GetBuffer for swap chain failed with HRESULT %08X", hr);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
s_backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
|
||||
SAFE_RELEASE(buf);
|
||||
SetDebugObjectName(s_backbuf->GetTex(), "backbuffer texture");
|
||||
SetDebugObjectName(s_backbuf->GetRTV(), "backbuffer render target view");
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
texture->GetDesc(&desc);
|
||||
|
||||
s_swap_chain_texture = std::make_unique<DXTexture>(
|
||||
TextureConfig(desc.Width, desc.Height, desc.MipLevels, desc.ArraySize, desc.SampleDesc.Count,
|
||||
AbstractTextureFormat::RGBA8, AbstractTextureFlag_RenderTarget),
|
||||
texture, nullptr, nullptr);
|
||||
|
||||
ID3D11RenderTargetView* rtv;
|
||||
CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(texture, D3D11_RTV_DIMENSION_TEXTURE2DARRAY, desc.Format,
|
||||
0, 0, desc.ArraySize);
|
||||
hr = device->CreateRenderTargetView(texture, &rtv_desc, &rtv);
|
||||
CHECK(SUCCEEDED(hr), "Create render target view for swap chain");
|
||||
if (FAILED(hr))
|
||||
{
|
||||
s_swap_chain_texture.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
SetDebugObjectName(texture, "backbuffer texture");
|
||||
SetDebugObjectName(rtv, "backbuffer render target view");
|
||||
s_swap_chain_framebuffer = std::make_unique<DXFramebuffer>(
|
||||
s_swap_chain_texture.get(), nullptr, AbstractTextureFormat::RGBA8,
|
||||
AbstractTextureFormat::Undefined, desc.Width, desc.Height, desc.ArraySize,
|
||||
desc.SampleDesc.Count, rtv, nullptr, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -300,7 +323,7 @@ static bool CreateSwapChain(HWND hWnd)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!CreateSwapChainTextures())
|
||||
if (!CreateSwapChainFramebuffer())
|
||||
{
|
||||
SAFE_RELEASE(swapchain);
|
||||
return false;
|
||||
|
@ -451,7 +474,8 @@ void Close()
|
|||
|
||||
// release all bound resources
|
||||
context->ClearState();
|
||||
SAFE_RELEASE(s_backbuf);
|
||||
s_swap_chain_framebuffer.reset();
|
||||
s_swap_chain_texture.reset();
|
||||
SAFE_RELEASE(swapchain);
|
||||
SAFE_DELETE(stateman);
|
||||
context->Flush(); // immediately destroy device objects
|
||||
|
@ -527,9 +551,13 @@ const char* ComputeShaderVersionString()
|
|||
return "cs_4_0";
|
||||
}
|
||||
|
||||
D3DTexture2D* GetBackBuffer()
|
||||
DXTexture* GetSwapChainTexture()
|
||||
{
|
||||
return s_backbuf;
|
||||
return s_swap_chain_texture.get();
|
||||
}
|
||||
DXFramebuffer* GetSwapChainFramebuffer()
|
||||
{
|
||||
return s_swap_chain_framebuffer.get();
|
||||
}
|
||||
bool BGRATexturesSupported()
|
||||
{
|
||||
|
@ -568,7 +596,8 @@ u32 GetMaxTextureSize(D3D_FEATURE_LEVEL feature_level)
|
|||
|
||||
void Reset(HWND new_wnd)
|
||||
{
|
||||
SAFE_RELEASE(s_backbuf);
|
||||
s_swap_chain_framebuffer.reset();
|
||||
s_swap_chain_texture.reset();
|
||||
|
||||
if (swapchain)
|
||||
{
|
||||
|
@ -583,10 +612,11 @@ void Reset(HWND new_wnd)
|
|||
|
||||
void ResizeSwapChain()
|
||||
{
|
||||
SAFE_RELEASE(s_backbuf);
|
||||
s_swap_chain_framebuffer.reset();
|
||||
s_swap_chain_texture.reset();
|
||||
const UINT swap_chain_flags = AllowTearingSupported() ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
|
||||
swapchain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_R8G8B8A8_UNORM, swap_chain_flags);
|
||||
if (!CreateSwapChainTextures())
|
||||
if (!CreateSwapChainFramebuffer())
|
||||
{
|
||||
PanicAlert("Failed to get swap chain textures");
|
||||
SAFE_RELEASE(swapchain);
|
||||
|
|
|
@ -38,7 +38,8 @@ namespace DX11
|
|||
PanicAlert("%s failed in %s at line %d: " Message, __func__, __FILE__, __LINE__, __VA_ARGS__); \
|
||||
}
|
||||
|
||||
class D3DTexture2D;
|
||||
class DXTexture;
|
||||
class DXFramebuffer;
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
|
@ -64,7 +65,8 @@ void Reset(HWND new_wnd);
|
|||
void ResizeSwapChain();
|
||||
void Present();
|
||||
|
||||
D3DTexture2D* GetBackBuffer();
|
||||
DXTexture* GetSwapChainTexture();
|
||||
DXFramebuffer* GetSwapChainFramebuffer();
|
||||
const char* PixelShaderVersionString();
|
||||
const char* GeometryShaderVersionString();
|
||||
const char* VertexShaderVersionString();
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <d3d11.h>
|
||||
|
||||
#include "VideoBackends/D3D/D3DBlob.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
D3DBlob::D3DBlob(unsigned int blob_size, const u8* init_data)
|
||||
: ref(1), size(blob_size), blob(nullptr)
|
||||
{
|
||||
data = new u8[blob_size];
|
||||
if (init_data)
|
||||
memcpy(data, init_data, size);
|
||||
}
|
||||
|
||||
D3DBlob::D3DBlob(ID3D10Blob* d3dblob) : ref(1)
|
||||
{
|
||||
blob = d3dblob;
|
||||
data = (u8*)blob->GetBufferPointer();
|
||||
size = (unsigned int)blob->GetBufferSize();
|
||||
d3dblob->AddRef();
|
||||
}
|
||||
|
||||
D3DBlob::~D3DBlob()
|
||||
{
|
||||
if (blob)
|
||||
blob->Release();
|
||||
else
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
void D3DBlob::AddRef()
|
||||
{
|
||||
++ref;
|
||||
}
|
||||
|
||||
unsigned int D3DBlob::Release()
|
||||
{
|
||||
if (--ref == 0)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
unsigned int D3DBlob::Size() const
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
u8* D3DBlob::Data()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
} // namespace DX11
|
|
@ -1,39 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
struct ID3D10Blob;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
// use this class instead ID3D10Blob or ID3D11Blob whenever possible
|
||||
class D3DBlob
|
||||
{
|
||||
public:
|
||||
// memory will be copied into an own buffer
|
||||
D3DBlob(unsigned int blob_size, const u8* init_data = nullptr);
|
||||
|
||||
// d3dblob will be AddRef'd
|
||||
D3DBlob(ID3D10Blob* d3dblob);
|
||||
|
||||
void AddRef();
|
||||
unsigned int Release();
|
||||
|
||||
unsigned int Size() const;
|
||||
u8* Data();
|
||||
|
||||
private:
|
||||
~D3DBlob();
|
||||
|
||||
unsigned int ref;
|
||||
unsigned int size;
|
||||
|
||||
u8* data;
|
||||
ID3D10Blob* blob;
|
||||
};
|
||||
|
||||
} // namespace
|
|
@ -1,304 +0,0 @@
|
|||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DShader.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
namespace D3D
|
||||
{
|
||||
// bytecode->shader
|
||||
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, size_t len)
|
||||
{
|
||||
ID3D11VertexShader* v_shader;
|
||||
HRESULT hr = D3D::device->CreateVertexShader(bytecode, len, nullptr, &v_shader);
|
||||
if (FAILED(hr))
|
||||
return nullptr;
|
||||
|
||||
return v_shader;
|
||||
}
|
||||
|
||||
// code->bytecode
|
||||
bool CompileVertexShader(const std::string& code, D3DBlob** blob)
|
||||
{
|
||||
ID3D10Blob* shaderBuffer = nullptr;
|
||||
ID3D10Blob* errorBuffer = nullptr;
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | D3D10_SHADER_DEBUG;
|
||||
#else
|
||||
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | D3D10_SHADER_OPTIMIZATION_LEVEL3 |
|
||||
D3D10_SHADER_SKIP_VALIDATION;
|
||||
#endif
|
||||
HRESULT hr = PD3DCompile(code.c_str(), code.length(), nullptr, nullptr, nullptr, "main",
|
||||
D3D::VertexShaderVersionString(), flags, 0, &shaderBuffer, &errorBuffer);
|
||||
if (errorBuffer)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Vertex shader compiler messages:\n%s",
|
||||
(const char*)errorBuffer->GetBufferPointer());
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
static int num_failures = 0;
|
||||
std::string filename = StringFromFormat("%sbad_vs_%04i.txt",
|
||||
File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
|
||||
std::ofstream file;
|
||||
File::OpenFStream(file, filename, std::ios_base::out);
|
||||
file << code;
|
||||
file.close();
|
||||
|
||||
PanicAlert("Failed to compile vertex shader: %s\nDebug info (%s):\n%s", filename.c_str(),
|
||||
D3D::VertexShaderVersionString(), (const char*)errorBuffer->GetBufferPointer());
|
||||
|
||||
*blob = nullptr;
|
||||
errorBuffer->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
*blob = new D3DBlob(shaderBuffer);
|
||||
shaderBuffer->Release();
|
||||
}
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
// bytecode->shader
|
||||
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, size_t len)
|
||||
{
|
||||
ID3D11GeometryShader* g_shader;
|
||||
HRESULT hr = D3D::device->CreateGeometryShader(bytecode, len, nullptr, &g_shader);
|
||||
if (FAILED(hr))
|
||||
return nullptr;
|
||||
|
||||
return g_shader;
|
||||
}
|
||||
|
||||
// code->bytecode
|
||||
bool CompileGeometryShader(const std::string& code, D3DBlob** blob,
|
||||
const D3D_SHADER_MACRO* pDefines)
|
||||
{
|
||||
ID3D10Blob* shaderBuffer = nullptr;
|
||||
ID3D10Blob* errorBuffer = nullptr;
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | D3D10_SHADER_DEBUG;
|
||||
#else
|
||||
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | D3D10_SHADER_OPTIMIZATION_LEVEL3 |
|
||||
D3D10_SHADER_SKIP_VALIDATION;
|
||||
#endif
|
||||
HRESULT hr =
|
||||
PD3DCompile(code.c_str(), code.length(), nullptr, pDefines, nullptr, "main",
|
||||
D3D::GeometryShaderVersionString(), flags, 0, &shaderBuffer, &errorBuffer);
|
||||
|
||||
if (errorBuffer)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Geometry shader compiler messages:\n%s",
|
||||
(const char*)errorBuffer->GetBufferPointer());
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
static int num_failures = 0;
|
||||
std::string filename = StringFromFormat("%sbad_gs_%04i.txt",
|
||||
File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
|
||||
std::ofstream file;
|
||||
File::OpenFStream(file, filename, std::ios_base::out);
|
||||
file << code;
|
||||
file.close();
|
||||
|
||||
PanicAlert("Failed to compile geometry shader: %s\nDebug info (%s):\n%s", filename.c_str(),
|
||||
D3D::GeometryShaderVersionString(), (const char*)errorBuffer->GetBufferPointer());
|
||||
|
||||
*blob = nullptr;
|
||||
errorBuffer->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
*blob = new D3DBlob(shaderBuffer);
|
||||
shaderBuffer->Release();
|
||||
}
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
// bytecode->shader
|
||||
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, size_t len)
|
||||
{
|
||||
ID3D11PixelShader* p_shader;
|
||||
HRESULT hr = D3D::device->CreatePixelShader(bytecode, len, nullptr, &p_shader);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
PanicAlert("CreatePixelShaderFromByteCode failed at %s %d\n", __FILE__, __LINE__);
|
||||
p_shader = nullptr;
|
||||
}
|
||||
return p_shader;
|
||||
}
|
||||
|
||||
// code->bytecode
|
||||
bool CompilePixelShader(const std::string& code, D3DBlob** blob, const D3D_SHADER_MACRO* pDefines)
|
||||
{
|
||||
ID3D10Blob* shaderBuffer = nullptr;
|
||||
ID3D10Blob* errorBuffer = nullptr;
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
UINT flags = D3D10_SHADER_DEBUG;
|
||||
#else
|
||||
UINT flags = D3D10_SHADER_OPTIMIZATION_LEVEL3;
|
||||
#endif
|
||||
HRESULT hr = PD3DCompile(code.c_str(), code.length(), nullptr, pDefines, nullptr, "main",
|
||||
D3D::PixelShaderVersionString(), flags, 0, &shaderBuffer, &errorBuffer);
|
||||
|
||||
if (errorBuffer)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Pixel shader compiler messages:\n%s",
|
||||
(const char*)errorBuffer->GetBufferPointer());
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
static int num_failures = 0;
|
||||
std::string filename = StringFromFormat("%sbad_ps_%04i.txt",
|
||||
File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
|
||||
std::ofstream file;
|
||||
File::OpenFStream(file, filename, std::ios_base::out);
|
||||
file << code;
|
||||
file.close();
|
||||
|
||||
PanicAlert("Failed to compile pixel shader: %s\nDebug info (%s):\n%s", filename.c_str(),
|
||||
D3D::PixelShaderVersionString(), (const char*)errorBuffer->GetBufferPointer());
|
||||
|
||||
*blob = nullptr;
|
||||
errorBuffer->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
*blob = new D3DBlob(shaderBuffer);
|
||||
shaderBuffer->Release();
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
// bytecode->shader
|
||||
ID3D11ComputeShader* CreateComputeShaderFromByteCode(const void* bytecode, size_t len)
|
||||
{
|
||||
ID3D11ComputeShader* shader;
|
||||
HRESULT hr = D3D::device->CreateComputeShader(bytecode, len, nullptr, &shader);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
PanicAlert("CreateComputeShaderFromByteCode failed at %s %d\n", __FILE__, __LINE__);
|
||||
return nullptr;
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
// code->bytecode
|
||||
bool CompileComputeShader(const std::string& code, D3DBlob** blob, const D3D_SHADER_MACRO* pDefines)
|
||||
{
|
||||
ID3D10Blob* shaderBuffer = nullptr;
|
||||
ID3D10Blob* errorBuffer = nullptr;
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
UINT flags = D3D10_SHADER_DEBUG;
|
||||
#else
|
||||
UINT flags = D3D10_SHADER_OPTIMIZATION_LEVEL3;
|
||||
#endif
|
||||
HRESULT hr =
|
||||
PD3DCompile(code.c_str(), code.length(), nullptr, pDefines, nullptr, "main",
|
||||
D3D::ComputeShaderVersionString(), flags, 0, &shaderBuffer, &errorBuffer);
|
||||
|
||||
if (errorBuffer)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Compute shader compiler messages:\n%s",
|
||||
(const char*)errorBuffer->GetBufferPointer());
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
static int num_failures = 0;
|
||||
std::string filename = StringFromFormat("%sbad_cs_%04i.txt",
|
||||
File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
|
||||
std::ofstream file;
|
||||
File::OpenFStream(file, filename, std::ios_base::out);
|
||||
file << code;
|
||||
file.close();
|
||||
|
||||
PanicAlert("Failed to compile compute shader: %s\nDebug info (%s):\n%s", filename.c_str(),
|
||||
D3D::ComputeShaderVersionString(),
|
||||
reinterpret_cast<const char*>(errorBuffer->GetBufferPointer()));
|
||||
|
||||
*blob = nullptr;
|
||||
errorBuffer->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
*blob = new D3DBlob(shaderBuffer);
|
||||
shaderBuffer->Release();
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
ID3D11VertexShader* CompileAndCreateVertexShader(const std::string& code)
|
||||
{
|
||||
D3DBlob* blob = nullptr;
|
||||
if (CompileVertexShader(code, &blob))
|
||||
{
|
||||
ID3D11VertexShader* v_shader = CreateVertexShaderFromByteCode(blob);
|
||||
blob->Release();
|
||||
return v_shader;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11GeometryShader* CompileAndCreateGeometryShader(const std::string& code,
|
||||
const D3D_SHADER_MACRO* pDefines)
|
||||
{
|
||||
D3DBlob* blob = nullptr;
|
||||
if (CompileGeometryShader(code, &blob, pDefines))
|
||||
{
|
||||
ID3D11GeometryShader* g_shader = CreateGeometryShaderFromByteCode(blob);
|
||||
blob->Release();
|
||||
return g_shader;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11PixelShader* CompileAndCreatePixelShader(const std::string& code)
|
||||
{
|
||||
D3DBlob* blob = nullptr;
|
||||
CompilePixelShader(code, &blob);
|
||||
if (blob)
|
||||
{
|
||||
ID3D11PixelShader* p_shader = CreatePixelShaderFromByteCode(blob);
|
||||
blob->Release();
|
||||
return p_shader;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11ComputeShader* CompileAndCreateComputeShader(const std::string& code)
|
||||
{
|
||||
D3DBlob* blob = nullptr;
|
||||
CompileComputeShader(code, &blob);
|
||||
if (blob)
|
||||
{
|
||||
ID3D11ComputeShader* shader = CreateComputeShaderFromByteCode(blob);
|
||||
blob->Release();
|
||||
return shader;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace DX11
|
|
@ -1,78 +0,0 @@
|
|||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DBlob.h"
|
||||
|
||||
struct ID3D11PixelShader;
|
||||
struct ID3D11VertexShader;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
namespace D3D
|
||||
{
|
||||
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, size_t len);
|
||||
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, size_t len);
|
||||
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, size_t len);
|
||||
ID3D11ComputeShader* CreateComputeShaderFromByteCode(const void* bytecode, size_t len);
|
||||
|
||||
// The returned bytecode buffers should be Release()d.
|
||||
bool CompileVertexShader(const std::string& code, D3DBlob** blob);
|
||||
bool CompileGeometryShader(const std::string& code, D3DBlob** blob,
|
||||
const D3D_SHADER_MACRO* pDefines = nullptr);
|
||||
bool CompilePixelShader(const std::string& code, D3DBlob** blob,
|
||||
const D3D_SHADER_MACRO* pDefines = nullptr);
|
||||
bool CompileComputeShader(const std::string& code, D3DBlob** blob,
|
||||
const D3D_SHADER_MACRO* pDefines = nullptr);
|
||||
|
||||
// Utility functions
|
||||
ID3D11VertexShader* CompileAndCreateVertexShader(const std::string& code);
|
||||
ID3D11GeometryShader* CompileAndCreateGeometryShader(const std::string& code,
|
||||
const D3D_SHADER_MACRO* pDefines = nullptr);
|
||||
ID3D11PixelShader* CompileAndCreatePixelShader(const std::string& code);
|
||||
ID3D11ComputeShader* CompileAndCreateComputeShader(const std::string& code);
|
||||
|
||||
inline ID3D11VertexShader* CreateVertexShaderFromByteCode(D3DBlob* bytecode)
|
||||
{
|
||||
return CreateVertexShaderFromByteCode(bytecode->Data(), bytecode->Size());
|
||||
}
|
||||
inline ID3D11GeometryShader* CreateGeometryShaderFromByteCode(D3DBlob* bytecode)
|
||||
{
|
||||
return CreateGeometryShaderFromByteCode(bytecode->Data(), bytecode->Size());
|
||||
}
|
||||
inline ID3D11PixelShader* CreatePixelShaderFromByteCode(D3DBlob* bytecode)
|
||||
{
|
||||
return CreatePixelShaderFromByteCode(bytecode->Data(), bytecode->Size());
|
||||
}
|
||||
inline ID3D11ComputeShader* CreateComputeShaderFromByteCode(D3DBlob* bytecode)
|
||||
{
|
||||
return CreateComputeShaderFromByteCode(bytecode->Data(), bytecode->Size());
|
||||
}
|
||||
|
||||
inline ID3D11VertexShader* CompileAndCreateVertexShader(D3DBlob* code)
|
||||
{
|
||||
return CompileAndCreateVertexShader(reinterpret_cast<const char*>(code->Data()));
|
||||
}
|
||||
|
||||
inline ID3D11GeometryShader*
|
||||
CompileAndCreateGeometryShader(D3DBlob* code, const D3D_SHADER_MACRO* pDefines = nullptr)
|
||||
{
|
||||
return CompileAndCreateGeometryShader(reinterpret_cast<const char*>(code->Data()), pDefines);
|
||||
}
|
||||
|
||||
inline ID3D11PixelShader* CompileAndCreatePixelShader(D3DBlob* code)
|
||||
{
|
||||
return CompileAndCreatePixelShader(reinterpret_cast<const char*>(code->Data()));
|
||||
}
|
||||
inline ID3D11ComputeShader* CompileAndCreateComputeShader(D3DBlob* code)
|
||||
{
|
||||
return CompileAndCreateComputeShader(reinterpret_cast<const char*>(code->Data()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace DX11
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/DXTexture.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace DX11
|
||||
|
@ -28,19 +29,31 @@ void StateManager::Apply()
|
|||
if (!m_dirtyFlags)
|
||||
return;
|
||||
|
||||
const int textureMaskShift = Common::LeastSignificantSetBit((u32)DirtyFlag_Texture0);
|
||||
const int samplerMaskShift = Common::LeastSignificantSetBit((u32)DirtyFlag_Sampler0);
|
||||
// Framebuffer changes must occur before texture changes, otherwise the D3D runtime messes with
|
||||
// our bindings and sets them to null to prevent hazards.
|
||||
if (m_dirtyFlags & DirtyFlag_Framebuffer)
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.bSupportsBBox)
|
||||
{
|
||||
D3D::context->OMSetRenderTargetsAndUnorderedAccessViews(
|
||||
m_pending.framebuffer->GetNumRTVs(),
|
||||
m_pending.use_integer_rtv ? m_pending.framebuffer->GetIntegerRTVArray() :
|
||||
m_pending.framebuffer->GetRTVArray(),
|
||||
m_pending.framebuffer->GetDSV(), 2, 1, &m_pending.uav, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
D3D::context->OMSetRenderTargets(m_pending.framebuffer->GetNumRTVs(),
|
||||
m_pending.use_integer_rtv ?
|
||||
m_pending.framebuffer->GetIntegerRTVArray() :
|
||||
m_pending.framebuffer->GetRTVArray(),
|
||||
m_pending.framebuffer->GetDSV());
|
||||
}
|
||||
m_current.framebuffer = m_pending.framebuffer;
|
||||
m_current.uav = m_pending.uav;
|
||||
m_current.use_integer_rtv = m_pending.use_integer_rtv;
|
||||
}
|
||||
|
||||
u32 dirtyTextures =
|
||||
(m_dirtyFlags &
|
||||
(DirtyFlag_Texture0 | DirtyFlag_Texture1 | DirtyFlag_Texture2 | DirtyFlag_Texture3 |
|
||||
DirtyFlag_Texture4 | DirtyFlag_Texture5 | DirtyFlag_Texture6 | DirtyFlag_Texture7)) >>
|
||||
textureMaskShift;
|
||||
u32 dirtySamplers =
|
||||
(m_dirtyFlags &
|
||||
(DirtyFlag_Sampler0 | DirtyFlag_Sampler1 | DirtyFlag_Sampler2 | DirtyFlag_Sampler3 |
|
||||
DirtyFlag_Sampler4 | DirtyFlag_Sampler5 | DirtyFlag_Sampler6 | DirtyFlag_Sampler7)) >>
|
||||
samplerMaskShift;
|
||||
u32 dirtyConstants = m_dirtyFlags & (DirtyFlag_PixelConstants | DirtyFlag_VertexConstants |
|
||||
DirtyFlag_GeometryConstants);
|
||||
u32 dirtyShaders =
|
||||
|
@ -103,30 +116,6 @@ void StateManager::Apply()
|
|||
}
|
||||
}
|
||||
|
||||
while (dirtyTextures)
|
||||
{
|
||||
const int index = Common::LeastSignificantSetBit(dirtyTextures);
|
||||
if (m_current.textures[index] != m_pending.textures[index])
|
||||
{
|
||||
D3D::context->PSSetShaderResources(index, 1, &m_pending.textures[index]);
|
||||
m_current.textures[index] = m_pending.textures[index];
|
||||
}
|
||||
|
||||
dirtyTextures &= ~(1 << index);
|
||||
}
|
||||
|
||||
while (dirtySamplers)
|
||||
{
|
||||
const int index = Common::LeastSignificantSetBit(dirtySamplers);
|
||||
if (m_current.samplers[index] != m_pending.samplers[index])
|
||||
{
|
||||
D3D::context->PSSetSamplers(index, 1, &m_pending.samplers[index]);
|
||||
m_current.samplers[index] = m_pending.samplers[index];
|
||||
}
|
||||
|
||||
dirtySamplers &= ~(1 << index);
|
||||
}
|
||||
|
||||
if (dirtyShaders)
|
||||
{
|
||||
if (m_current.pixelShader != m_pending.pixelShader)
|
||||
|
@ -164,9 +153,51 @@ void StateManager::Apply()
|
|||
m_current.rasterizerState = m_pending.rasterizerState;
|
||||
}
|
||||
|
||||
ApplyTextures();
|
||||
|
||||
m_dirtyFlags = 0;
|
||||
}
|
||||
|
||||
void StateManager::ApplyTextures()
|
||||
{
|
||||
const int textureMaskShift = Common::LeastSignificantSetBit((u32)DirtyFlag_Texture0);
|
||||
const int samplerMaskShift = Common::LeastSignificantSetBit((u32)DirtyFlag_Sampler0);
|
||||
|
||||
u32 dirtyTextures =
|
||||
(m_dirtyFlags &
|
||||
(DirtyFlag_Texture0 | DirtyFlag_Texture1 | DirtyFlag_Texture2 | DirtyFlag_Texture3 |
|
||||
DirtyFlag_Texture4 | DirtyFlag_Texture5 | DirtyFlag_Texture6 | DirtyFlag_Texture7)) >>
|
||||
textureMaskShift;
|
||||
u32 dirtySamplers =
|
||||
(m_dirtyFlags &
|
||||
(DirtyFlag_Sampler0 | DirtyFlag_Sampler1 | DirtyFlag_Sampler2 | DirtyFlag_Sampler3 |
|
||||
DirtyFlag_Sampler4 | DirtyFlag_Sampler5 | DirtyFlag_Sampler6 | DirtyFlag_Sampler7)) >>
|
||||
samplerMaskShift;
|
||||
while (dirtyTextures)
|
||||
{
|
||||
const int index = Common::LeastSignificantSetBit(dirtyTextures);
|
||||
if (m_current.textures[index] != m_pending.textures[index])
|
||||
{
|
||||
D3D::context->PSSetShaderResources(index, 1, &m_pending.textures[index]);
|
||||
m_current.textures[index] = m_pending.textures[index];
|
||||
}
|
||||
|
||||
dirtyTextures &= ~(1 << index);
|
||||
}
|
||||
|
||||
while (dirtySamplers)
|
||||
{
|
||||
const int index = Common::LeastSignificantSetBit(dirtySamplers);
|
||||
if (m_current.samplers[index] != m_pending.samplers[index])
|
||||
{
|
||||
D3D::context->PSSetSamplers(index, 1, &m_pending.samplers[index]);
|
||||
m_current.samplers[index] = m_pending.samplers[index];
|
||||
}
|
||||
|
||||
dirtySamplers &= ~(1 << index);
|
||||
}
|
||||
}
|
||||
|
||||
u32 StateManager::UnsetTexture(ID3D11ShaderResourceView* srv)
|
||||
{
|
||||
u32 mask = 0;
|
||||
|
@ -193,6 +224,78 @@ void StateManager::SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceVie
|
|||
}
|
||||
}
|
||||
|
||||
void StateManager::SetComputeUAV(ID3D11UnorderedAccessView* uav)
|
||||
{
|
||||
if (m_compute_image == uav)
|
||||
return;
|
||||
|
||||
m_compute_image = uav;
|
||||
D3D::context->CSSetUnorderedAccessViews(0, 1, &uav, nullptr);
|
||||
}
|
||||
|
||||
void StateManager::SetComputeShader(ID3D11ComputeShader* shader)
|
||||
{
|
||||
if (m_compute_shader == shader)
|
||||
return;
|
||||
|
||||
m_compute_shader = shader;
|
||||
D3D::context->CSSetShader(shader, nullptr, 0);
|
||||
}
|
||||
|
||||
void StateManager::SyncComputeBindings()
|
||||
{
|
||||
if (m_compute_constants != m_pending.pixelConstants[0])
|
||||
{
|
||||
m_compute_constants = m_pending.pixelConstants[0];
|
||||
D3D::context->CSSetConstantBuffers(0, 1, &m_compute_constants);
|
||||
}
|
||||
|
||||
for (u32 start = 0; start < static_cast<u32>(m_compute_textures.size());)
|
||||
{
|
||||
if (m_compute_textures[start] == m_pending.textures[start])
|
||||
{
|
||||
start++;
|
||||
continue;
|
||||
}
|
||||
|
||||
m_compute_textures[start] = m_pending.textures[start];
|
||||
|
||||
u32 end = start + 1;
|
||||
for (; end < static_cast<u32>(m_compute_textures.size()); end++)
|
||||
{
|
||||
if (m_compute_textures[end] == m_pending.textures[end])
|
||||
break;
|
||||
|
||||
m_compute_textures[end] = m_pending.textures[end];
|
||||
}
|
||||
|
||||
D3D::context->CSSetShaderResources(start, end - start, &m_compute_textures[start]);
|
||||
start = end;
|
||||
}
|
||||
|
||||
for (u32 start = 0; start < static_cast<u32>(m_compute_samplers.size());)
|
||||
{
|
||||
if (m_compute_samplers[start] == m_pending.samplers[start])
|
||||
{
|
||||
start++;
|
||||
continue;
|
||||
}
|
||||
|
||||
m_compute_samplers[start] = m_pending.samplers[start];
|
||||
|
||||
u32 end = start + 1;
|
||||
for (; end < static_cast<u32>(m_compute_samplers.size()); end++)
|
||||
{
|
||||
if (m_compute_samplers[end] == m_pending.samplers[end])
|
||||
break;
|
||||
|
||||
m_compute_samplers[end] = m_pending.samplers[end];
|
||||
}
|
||||
|
||||
D3D::context->CSSetSamplers(start, end - start, &m_compute_samplers[start]);
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
} // namespace D3D
|
||||
|
||||
StateCache::~StateCache()
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
namespace DX11
|
||||
{
|
||||
class DXFramebuffer;
|
||||
|
||||
class StateCache
|
||||
{
|
||||
public:
|
||||
|
@ -112,14 +114,6 @@ public:
|
|||
m_pending.geometryConstants = buffer;
|
||||
}
|
||||
|
||||
void SetComputeConstants(ID3D11Buffer* buffer)
|
||||
{
|
||||
if (m_current.computeConstants != buffer)
|
||||
m_dirtyFlags |= DirtyFlag_ComputeConstants;
|
||||
|
||||
m_pending.computeConstants = buffer;
|
||||
}
|
||||
|
||||
void SetVertexBuffer(ID3D11Buffer* buffer, u32 stride, u32 offset)
|
||||
{
|
||||
if (m_current.vertexBuffer != buffer || m_current.vertexBufferStride != stride ||
|
||||
|
@ -187,22 +181,45 @@ public:
|
|||
m_pending.geometryShader = shader;
|
||||
}
|
||||
|
||||
void SetComputeShader(ID3D11ComputeShader* shader)
|
||||
void SetFramebuffer(DXFramebuffer* fb)
|
||||
{
|
||||
if (m_current.computeShader != shader)
|
||||
m_dirtyFlags |= DirtyFlag_ComputeShader;
|
||||
if (m_current.framebuffer != fb)
|
||||
m_dirtyFlags |= DirtyFlag_Framebuffer;
|
||||
|
||||
m_pending.computeShader = shader;
|
||||
m_pending.framebuffer = fb;
|
||||
}
|
||||
|
||||
void SetOMUAV(ID3D11UnorderedAccessView* uav)
|
||||
{
|
||||
if (m_current.uav != uav)
|
||||
m_dirtyFlags |= DirtyFlag_Framebuffer;
|
||||
|
||||
m_pending.uav = uav;
|
||||
}
|
||||
|
||||
void SetIntegerRTV(bool enable)
|
||||
{
|
||||
if (m_current.use_integer_rtv != enable)
|
||||
m_dirtyFlags |= DirtyFlag_Framebuffer;
|
||||
|
||||
m_pending.use_integer_rtv = enable;
|
||||
}
|
||||
|
||||
// removes currently set texture from all slots, returns mask of previously bound slots
|
||||
u32 UnsetTexture(ID3D11ShaderResourceView* srv);
|
||||
void SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceView* srv);
|
||||
void ApplyTextures();
|
||||
|
||||
// call this immediately before any drawing operation or to explicitly apply pending resource
|
||||
// state changes
|
||||
void Apply();
|
||||
|
||||
// Binds constant buffers/textures/samplers to the compute shader stage.
|
||||
// We don't track these explicitly because it's not often-used.
|
||||
void SetComputeUAV(ID3D11UnorderedAccessView* uav);
|
||||
void SetComputeShader(ID3D11ComputeShader* shader);
|
||||
void SyncComputeBindings();
|
||||
|
||||
private:
|
||||
enum DirtyFlags
|
||||
{
|
||||
|
@ -227,20 +244,19 @@ private:
|
|||
DirtyFlag_PixelConstants = 1 << 16,
|
||||
DirtyFlag_VertexConstants = 1 << 17,
|
||||
DirtyFlag_GeometryConstants = 1 << 18,
|
||||
DirtyFlag_ComputeConstants = 1 << 19,
|
||||
|
||||
DirtyFlag_VertexBuffer = 1 << 20,
|
||||
DirtyFlag_IndexBuffer = 1 << 21,
|
||||
DirtyFlag_VertexBuffer = 1 << 19,
|
||||
DirtyFlag_IndexBuffer = 1 << 20,
|
||||
|
||||
DirtyFlag_PixelShader = 1 << 22,
|
||||
DirtyFlag_VertexShader = 1 << 23,
|
||||
DirtyFlag_GeometryShader = 1 << 24,
|
||||
DirtyFlag_ComputeShader = 1 << 25,
|
||||
DirtyFlag_PixelShader = 1 << 21,
|
||||
DirtyFlag_VertexShader = 1 << 22,
|
||||
DirtyFlag_GeometryShader = 1 << 23,
|
||||
|
||||
DirtyFlag_InputAssembler = 1 << 26,
|
||||
DirtyFlag_BlendState = 1 << 27,
|
||||
DirtyFlag_DepthState = 1 << 28,
|
||||
DirtyFlag_RasterizerState = 1 << 29,
|
||||
DirtyFlag_InputAssembler = 1 << 24,
|
||||
DirtyFlag_BlendState = 1 << 25,
|
||||
DirtyFlag_DepthState = 1 << 26,
|
||||
DirtyFlag_RasterizerState = 1 << 27,
|
||||
DirtyFlag_Framebuffer = 1 << 28
|
||||
};
|
||||
|
||||
u32 m_dirtyFlags = ~0u;
|
||||
|
@ -252,7 +268,6 @@ private:
|
|||
std::array<ID3D11Buffer*, 2> pixelConstants;
|
||||
ID3D11Buffer* vertexConstants;
|
||||
ID3D11Buffer* geometryConstants;
|
||||
ID3D11Buffer* computeConstants;
|
||||
ID3D11Buffer* vertexBuffer;
|
||||
ID3D11Buffer* indexBuffer;
|
||||
u32 vertexBufferStride;
|
||||
|
@ -262,18 +277,27 @@ private:
|
|||
ID3D11PixelShader* pixelShader;
|
||||
ID3D11VertexShader* vertexShader;
|
||||
ID3D11GeometryShader* geometryShader;
|
||||
ID3D11ComputeShader* computeShader;
|
||||
ID3D11BlendState* blendState;
|
||||
ID3D11DepthStencilState* depthState;
|
||||
ID3D11RasterizerState* rasterizerState;
|
||||
DXFramebuffer* framebuffer;
|
||||
ID3D11UnorderedAccessView* uav;
|
||||
bool use_integer_rtv;
|
||||
};
|
||||
|
||||
Resources m_pending = {};
|
||||
Resources m_current = {};
|
||||
|
||||
// Compute resources are synced with the graphics resources when we need them.
|
||||
ID3D11Buffer* m_compute_constants = nullptr;
|
||||
std::array<ID3D11ShaderResourceView*, 8> m_compute_textures{};
|
||||
std::array<ID3D11SamplerState*, 8> m_compute_samplers{};
|
||||
ID3D11UnorderedAccessView* m_compute_image = nullptr;
|
||||
ID3D11ComputeShader* m_compute_shader = nullptr;
|
||||
};
|
||||
|
||||
extern StateManager* stateman;
|
||||
|
||||
} // namespace
|
||||
} // namespace D3D
|
||||
|
||||
} // namespace DX11
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DTexture.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind,
|
||||
D3D11_USAGE usage, DXGI_FORMAT fmt, unsigned int levels,
|
||||
unsigned int slices, D3D11_SUBRESOURCE_DATA* data)
|
||||
{
|
||||
ID3D11Texture2D* pTexture = nullptr;
|
||||
HRESULT hr;
|
||||
|
||||
D3D11_CPU_ACCESS_FLAG cpuflags;
|
||||
if (usage == D3D11_USAGE_STAGING)
|
||||
cpuflags = (D3D11_CPU_ACCESS_FLAG)((int)D3D11_CPU_ACCESS_WRITE | (int)D3D11_CPU_ACCESS_READ);
|
||||
else if (usage == D3D11_USAGE_DYNAMIC)
|
||||
cpuflags = D3D11_CPU_ACCESS_WRITE;
|
||||
else
|
||||
cpuflags = (D3D11_CPU_ACCESS_FLAG)0;
|
||||
D3D11_TEXTURE2D_DESC texdesc =
|
||||
CD3D11_TEXTURE2D_DESC(fmt, width, height, slices, levels, bind, usage, cpuflags);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, data, &pTexture);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
PanicAlert("Failed to create texture at %s, line %d: hr=%#x\n", __FILE__, __LINE__, hr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
D3DTexture2D* ret = new D3DTexture2D(pTexture, bind);
|
||||
SAFE_RELEASE(pTexture);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void D3DTexture2D::AddRef()
|
||||
{
|
||||
++ref;
|
||||
}
|
||||
|
||||
UINT D3DTexture2D::Release()
|
||||
{
|
||||
--ref;
|
||||
if (ref == 0)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
ID3D11Texture2D*& D3DTexture2D::GetTex()
|
||||
{
|
||||
return tex;
|
||||
}
|
||||
ID3D11ShaderResourceView*& D3DTexture2D::GetSRV()
|
||||
{
|
||||
return srv;
|
||||
}
|
||||
ID3D11RenderTargetView*& D3DTexture2D::GetRTV()
|
||||
{
|
||||
return rtv;
|
||||
}
|
||||
ID3D11DepthStencilView*& D3DTexture2D::GetDSV()
|
||||
{
|
||||
return dsv;
|
||||
}
|
||||
|
||||
D3DTexture2D::D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind, DXGI_FORMAT srv_format,
|
||||
DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format, bool multisampled)
|
||||
: tex{texptr}
|
||||
{
|
||||
D3D11_SRV_DIMENSION srv_dim =
|
||||
multisampled ? D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY : D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
|
||||
D3D11_DSV_DIMENSION dsv_dim =
|
||||
multisampled ? D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY : D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
|
||||
D3D11_RTV_DIMENSION rtv_dim =
|
||||
multisampled ? D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = CD3D11_SHADER_RESOURCE_VIEW_DESC(srv_dim, srv_format);
|
||||
D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc = CD3D11_DEPTH_STENCIL_VIEW_DESC(dsv_dim, dsv_format);
|
||||
D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = CD3D11_RENDER_TARGET_VIEW_DESC(rtv_dim, rtv_format);
|
||||
if (bind & D3D11_BIND_SHADER_RESOURCE)
|
||||
D3D::device->CreateShaderResourceView(tex, &srv_desc, &srv);
|
||||
if (bind & D3D11_BIND_RENDER_TARGET)
|
||||
D3D::device->CreateRenderTargetView(tex, &rtv_desc, &rtv);
|
||||
if (bind & D3D11_BIND_DEPTH_STENCIL)
|
||||
D3D::device->CreateDepthStencilView(tex, &dsv_desc, &dsv);
|
||||
tex->AddRef();
|
||||
}
|
||||
|
||||
D3DTexture2D::~D3DTexture2D()
|
||||
{
|
||||
SAFE_RELEASE(srv);
|
||||
SAFE_RELEASE(rtv);
|
||||
SAFE_RELEASE(dsv);
|
||||
SAFE_RELEASE(tex);
|
||||
}
|
||||
|
||||
} // namespace DX11
|
|
@ -1,48 +0,0 @@
|
|||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
class D3DTexture2D
|
||||
{
|
||||
public:
|
||||
// there are two ways to create a D3DTexture2D object:
|
||||
// either create an ID3D11Texture2D object, pass it to the constructor and specify what views
|
||||
// to create
|
||||
// or let the texture automatically be created by D3DTexture2D::Create
|
||||
|
||||
D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind,
|
||||
DXGI_FORMAT srv_format = DXGI_FORMAT_UNKNOWN,
|
||||
DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN,
|
||||
DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN, bool multisampled = false);
|
||||
static D3DTexture2D* Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind,
|
||||
D3D11_USAGE usage, DXGI_FORMAT, unsigned int levels = 1,
|
||||
unsigned int slices = 1, D3D11_SUBRESOURCE_DATA* data = nullptr);
|
||||
|
||||
// reference counting, use AddRef() when creating a new reference and Release() it when you don't
|
||||
// need it anymore
|
||||
void AddRef();
|
||||
UINT Release();
|
||||
|
||||
ID3D11Texture2D*& GetTex();
|
||||
ID3D11ShaderResourceView*& GetSRV();
|
||||
ID3D11RenderTargetView*& GetRTV();
|
||||
ID3D11DepthStencilView*& GetDSV();
|
||||
|
||||
private:
|
||||
~D3DTexture2D();
|
||||
|
||||
ID3D11Texture2D* tex;
|
||||
ID3D11ShaderResourceView* srv = nullptr;
|
||||
ID3D11RenderTargetView* rtv = nullptr;
|
||||
ID3D11DepthStencilView* dsv = nullptr;
|
||||
UINT ref = 1;
|
||||
};
|
||||
|
||||
} // namespace DX11
|
|
@ -1,407 +0,0 @@
|
|||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/D3D/D3DUtil.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "Common/Align.h"
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DShader.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/GeometryShaderCache.h"
|
||||
#include "VideoBackends/D3D/PixelShaderCache.h"
|
||||
#include "VideoBackends/D3D/VertexShaderCache.h"
|
||||
#include "VideoCommon/VideoBackendBase.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
namespace D3D
|
||||
{
|
||||
// Ring buffer class, shared between the draw* functions
|
||||
class UtilVertexBuffer
|
||||
{
|
||||
public:
|
||||
UtilVertexBuffer(unsigned int size) : max_size(size)
|
||||
{
|
||||
D3D11_BUFFER_DESC desc = CD3D11_BUFFER_DESC(max_size, D3D11_BIND_VERTEX_BUFFER,
|
||||
D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
|
||||
device->CreateBuffer(&desc, nullptr, &buf);
|
||||
}
|
||||
~UtilVertexBuffer() { buf->Release(); }
|
||||
int GetSize() const { return max_size; }
|
||||
// returns vertex offset to the new data
|
||||
int AppendData(void* data, unsigned int size, unsigned int vertex_size)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
if (offset + size >= max_size)
|
||||
{
|
||||
// wrap buffer around and notify observers
|
||||
offset = 0;
|
||||
context->Map(buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
|
||||
for (bool* observer : observers)
|
||||
*observer = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
context->Map(buf, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map);
|
||||
}
|
||||
offset = Common::AlignUp(offset, vertex_size);
|
||||
memcpy((u8*)map.pData + offset, data, size);
|
||||
context->Unmap(buf, 0);
|
||||
|
||||
offset += size;
|
||||
return (offset - size) / vertex_size;
|
||||
}
|
||||
|
||||
int BeginAppendData(void** write_ptr, unsigned int size, unsigned int vertex_size)
|
||||
{
|
||||
DEBUG_ASSERT(size < max_size);
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
unsigned int aligned_offset = Common::AlignUp(offset, vertex_size);
|
||||
if (aligned_offset + size > max_size)
|
||||
{
|
||||
// wrap buffer around and notify observers
|
||||
offset = 0;
|
||||
aligned_offset = 0;
|
||||
context->Map(buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
|
||||
for (bool* observer : observers)
|
||||
*observer = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
context->Map(buf, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map);
|
||||
}
|
||||
|
||||
*write_ptr = reinterpret_cast<byte*>(map.pData) + aligned_offset;
|
||||
offset = aligned_offset + size;
|
||||
return aligned_offset / vertex_size;
|
||||
}
|
||||
|
||||
void EndAppendData() { context->Unmap(buf, 0); }
|
||||
void AddWrapObserver(bool* observer) { observers.push_back(observer); }
|
||||
inline ID3D11Buffer*& GetBuffer() { return buf; }
|
||||
|
||||
private:
|
||||
ID3D11Buffer* buf = nullptr;
|
||||
unsigned int offset = 0;
|
||||
unsigned int max_size;
|
||||
|
||||
std::list<bool*> observers;
|
||||
};
|
||||
|
||||
static UtilVertexBuffer* util_vbuf = nullptr;
|
||||
static ID3D11SamplerState* linear_copy_sampler = nullptr;
|
||||
static ID3D11SamplerState* point_copy_sampler = nullptr;
|
||||
|
||||
struct STQVertex
|
||||
{
|
||||
float x, y, z, u, v, w;
|
||||
};
|
||||
struct ClearVertex
|
||||
{
|
||||
float x, y, z;
|
||||
u32 col;
|
||||
};
|
||||
struct ColVertex
|
||||
{
|
||||
float x, y, z;
|
||||
u32 col;
|
||||
};
|
||||
|
||||
struct TexQuadData
|
||||
{
|
||||
float u1, v1, u2, v2, S, G;
|
||||
};
|
||||
static TexQuadData tex_quad_data;
|
||||
|
||||
struct DrawQuadData
|
||||
{
|
||||
float x1, y1, x2, y2, z;
|
||||
u32 col;
|
||||
};
|
||||
static DrawQuadData draw_quad_data;
|
||||
|
||||
struct ClearQuadData
|
||||
{
|
||||
u32 col;
|
||||
float z;
|
||||
};
|
||||
static ClearQuadData clear_quad_data;
|
||||
|
||||
// ring buffer offsets
|
||||
static int stq_offset, cq_offset, clearq_offset;
|
||||
|
||||
// observer variables for ring buffer wraps
|
||||
static bool stq_observer, cq_observer, clearq_observer;
|
||||
|
||||
void InitUtils()
|
||||
{
|
||||
util_vbuf = new UtilVertexBuffer(65536); // 64KiB
|
||||
|
||||
float border[4] = {0.f, 0.f, 0.f, 0.f};
|
||||
D3D11_SAMPLER_DESC samDesc = CD3D11_SAMPLER_DESC(
|
||||
D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER,
|
||||
D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f);
|
||||
HRESULT hr = D3D::device->CreateSamplerState(&samDesc, &point_copy_sampler);
|
||||
if (FAILED(hr))
|
||||
PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__);
|
||||
else
|
||||
SetDebugObjectName(point_copy_sampler, "point copy sampler state");
|
||||
|
||||
samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_BORDER,
|
||||
D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1,
|
||||
D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f);
|
||||
hr = D3D::device->CreateSamplerState(&samDesc, &linear_copy_sampler);
|
||||
if (FAILED(hr))
|
||||
PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__);
|
||||
else
|
||||
SetDebugObjectName(linear_copy_sampler, "linear copy sampler state");
|
||||
|
||||
// cached data used to avoid unnecessarily reloading the vertex buffers
|
||||
memset(&tex_quad_data, 0, sizeof(tex_quad_data));
|
||||
memset(&draw_quad_data, 0, sizeof(draw_quad_data));
|
||||
memset(&clear_quad_data, 0, sizeof(clear_quad_data));
|
||||
|
||||
// make sure to properly load the vertex data whenever the corresponding functions get called the
|
||||
// first time
|
||||
stq_observer = cq_observer = clearq_observer = true;
|
||||
util_vbuf->AddWrapObserver(&stq_observer);
|
||||
util_vbuf->AddWrapObserver(&cq_observer);
|
||||
util_vbuf->AddWrapObserver(&clearq_observer);
|
||||
}
|
||||
|
||||
void ShutdownUtils()
|
||||
{
|
||||
SAFE_RELEASE(point_copy_sampler);
|
||||
SAFE_RELEASE(linear_copy_sampler);
|
||||
SAFE_DELETE(util_vbuf);
|
||||
}
|
||||
|
||||
void SetPointCopySampler()
|
||||
{
|
||||
D3D::stateman->SetSampler(0, point_copy_sampler);
|
||||
}
|
||||
|
||||
void SetLinearCopySampler()
|
||||
{
|
||||
D3D::stateman->SetSampler(0, linear_copy_sampler);
|
||||
}
|
||||
|
||||
void drawShadedTexQuad(ID3D11ShaderResourceView* texture, const D3D11_RECT* rSource,
|
||||
int SourceWidth, int SourceHeight, ID3D11PixelShader* PShader,
|
||||
ID3D11VertexShader* VShader, ID3D11InputLayout* layout,
|
||||
ID3D11GeometryShader* GShader, u32 slice)
|
||||
{
|
||||
float sw = 1.0f / (float)SourceWidth;
|
||||
float sh = 1.0f / (float)SourceHeight;
|
||||
float u1 = ((float)rSource->left) * sw;
|
||||
float u2 = ((float)rSource->right) * sw;
|
||||
float v1 = ((float)rSource->top) * sh;
|
||||
float v2 = ((float)rSource->bottom) * sh;
|
||||
float S = (float)slice;
|
||||
|
||||
STQVertex coords[4] = {
|
||||
{-1.0f, 1.0f, 0.0f, u1, v1, S},
|
||||
{1.0f, 1.0f, 0.0f, u2, v1, S},
|
||||
{-1.0f, -1.0f, 0.0f, u1, v2, S},
|
||||
{1.0f, -1.0f, 0.0f, u2, v2, S},
|
||||
};
|
||||
|
||||
// only upload the data to VRAM if it changed
|
||||
if (stq_observer || tex_quad_data.u1 != u1 || tex_quad_data.v1 != v1 || tex_quad_data.u2 != u2 ||
|
||||
tex_quad_data.v2 != v2 || tex_quad_data.S != S)
|
||||
{
|
||||
stq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(STQVertex));
|
||||
stq_observer = false;
|
||||
|
||||
tex_quad_data.u1 = u1;
|
||||
tex_quad_data.v1 = v1;
|
||||
tex_quad_data.u2 = u2;
|
||||
tex_quad_data.v2 = v2;
|
||||
tex_quad_data.S = S;
|
||||
}
|
||||
UINT stride = sizeof(STQVertex);
|
||||
UINT offset = 0;
|
||||
|
||||
D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
D3D::stateman->SetInputLayout(layout);
|
||||
D3D::stateman->SetVertexBuffer(util_vbuf->GetBuffer(), stride, offset);
|
||||
D3D::stateman->SetPixelShader(PShader);
|
||||
D3D::stateman->SetTexture(0, texture);
|
||||
D3D::stateman->SetVertexShader(VShader);
|
||||
D3D::stateman->SetGeometryShader(GShader);
|
||||
|
||||
D3D::stateman->Apply();
|
||||
D3D::context->Draw(4, stq_offset);
|
||||
|
||||
D3D::stateman->SetTexture(0, nullptr); // immediately unbind the texture
|
||||
D3D::stateman->Apply();
|
||||
|
||||
D3D::stateman->SetGeometryShader(nullptr);
|
||||
}
|
||||
|
||||
// Fills a certain area of the current render target with the specified color
|
||||
// destination coordinates normalized to (-1;1)
|
||||
void drawColorQuad(u32 Color, float z, float x1, float y1, float x2, float y2)
|
||||
{
|
||||
ColVertex coords[4] = {
|
||||
{x1, y1, z, Color},
|
||||
{x2, y1, z, Color},
|
||||
{x1, y2, z, Color},
|
||||
{x2, y2, z, Color},
|
||||
};
|
||||
|
||||
if (cq_observer || draw_quad_data.x1 != x1 || draw_quad_data.y1 != y1 ||
|
||||
draw_quad_data.x2 != x2 || draw_quad_data.y2 != y2 || draw_quad_data.col != Color ||
|
||||
draw_quad_data.z != z)
|
||||
{
|
||||
cq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(ColVertex));
|
||||
cq_observer = false;
|
||||
|
||||
draw_quad_data.x1 = x1;
|
||||
draw_quad_data.y1 = y1;
|
||||
draw_quad_data.x2 = x2;
|
||||
draw_quad_data.y2 = y2;
|
||||
draw_quad_data.col = Color;
|
||||
draw_quad_data.z = z;
|
||||
}
|
||||
|
||||
stateman->SetVertexShader(VertexShaderCache::GetClearVertexShader());
|
||||
stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader());
|
||||
stateman->SetPixelShader(PixelShaderCache::GetClearProgram());
|
||||
stateman->SetInputLayout(VertexShaderCache::GetClearInputLayout());
|
||||
|
||||
UINT stride = sizeof(ColVertex);
|
||||
UINT offset = 0;
|
||||
stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
stateman->SetVertexBuffer(util_vbuf->GetBuffer(), stride, offset);
|
||||
|
||||
stateman->Apply();
|
||||
context->Draw(4, cq_offset);
|
||||
|
||||
stateman->SetGeometryShader(nullptr);
|
||||
}
|
||||
|
||||
void drawClearQuad(u32 Color, float z)
|
||||
{
|
||||
ClearVertex coords[4] = {
|
||||
{-1.0f, 1.0f, z, Color},
|
||||
{1.0f, 1.0f, z, Color},
|
||||
{-1.0f, -1.0f, z, Color},
|
||||
{1.0f, -1.0f, z, Color},
|
||||
};
|
||||
|
||||
if (clearq_observer || clear_quad_data.col != Color || clear_quad_data.z != z)
|
||||
{
|
||||
clearq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(ClearVertex));
|
||||
clearq_observer = false;
|
||||
|
||||
clear_quad_data.col = Color;
|
||||
clear_quad_data.z = z;
|
||||
}
|
||||
|
||||
stateman->SetVertexShader(VertexShaderCache::GetClearVertexShader());
|
||||
stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader());
|
||||
stateman->SetPixelShader(PixelShaderCache::GetClearProgram());
|
||||
stateman->SetInputLayout(VertexShaderCache::GetClearInputLayout());
|
||||
|
||||
UINT stride = sizeof(ClearVertex);
|
||||
UINT offset = 0;
|
||||
stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
stateman->SetVertexBuffer(util_vbuf->GetBuffer(), stride, offset);
|
||||
|
||||
stateman->Apply();
|
||||
context->Draw(4, clearq_offset);
|
||||
|
||||
stateman->SetGeometryShader(nullptr);
|
||||
}
|
||||
|
||||
static void InitColVertex(ColVertex* vert, float x, float y, float z, u32 col)
|
||||
{
|
||||
vert->x = x;
|
||||
vert->y = y;
|
||||
vert->z = z;
|
||||
vert->col = col;
|
||||
}
|
||||
|
||||
void DrawEFBPokeQuads(EFBAccessType type, const EfbPokeData* points, size_t num_points)
|
||||
{
|
||||
const size_t COL_QUAD_SIZE = sizeof(ColVertex) * 6;
|
||||
|
||||
// Set common state
|
||||
stateman->SetVertexShader(VertexShaderCache::GetClearVertexShader());
|
||||
stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader());
|
||||
stateman->SetPixelShader(PixelShaderCache::GetClearProgram());
|
||||
stateman->SetInputLayout(VertexShaderCache::GetClearInputLayout());
|
||||
stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
stateman->SetVertexBuffer(util_vbuf->GetBuffer(), sizeof(ColVertex), 0);
|
||||
stateman->Apply();
|
||||
|
||||
// if drawing a large number of points at once, this will have to be split into multiple passes.
|
||||
size_t points_per_draw = util_vbuf->GetSize() / COL_QUAD_SIZE;
|
||||
size_t current_point_index = 0;
|
||||
while (current_point_index < num_points)
|
||||
{
|
||||
size_t points_to_draw = std::min(num_points - current_point_index, points_per_draw);
|
||||
size_t required_bytes = COL_QUAD_SIZE * points_to_draw;
|
||||
|
||||
// map and reserve enough buffer space for this draw
|
||||
void* buffer_ptr;
|
||||
int base_vertex_index =
|
||||
util_vbuf->BeginAppendData(&buffer_ptr, (int)required_bytes, sizeof(ColVertex));
|
||||
|
||||
// generate quads for each efb point
|
||||
ColVertex* base_vertex_ptr = reinterpret_cast<ColVertex*>(buffer_ptr);
|
||||
for (size_t i = 0; i < points_to_draw; i++)
|
||||
{
|
||||
// generate quad from the single point (clip-space coordinates)
|
||||
const EfbPokeData* point = &points[current_point_index];
|
||||
float x1 = float(point->x) * 2.0f / EFB_WIDTH - 1.0f;
|
||||
float y1 = -float(point->y) * 2.0f / EFB_HEIGHT + 1.0f;
|
||||
float x2 = float(point->x + 1) * 2.0f / EFB_WIDTH - 1.0f;
|
||||
float y2 = -float(point->y + 1) * 2.0f / EFB_HEIGHT + 1.0f;
|
||||
float z = 0.0f;
|
||||
u32 col = 0;
|
||||
|
||||
if (type == EFBAccessType::PokeZ)
|
||||
{
|
||||
z = 1.0f - static_cast<float>(point->data & 0xFFFFFF) / 16777216.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
col = ((point->data & 0xFF00FF00) | ((point->data >> 16) & 0xFF) |
|
||||
((point->data << 16) & 0xFF0000));
|
||||
}
|
||||
|
||||
current_point_index++;
|
||||
|
||||
// quad -> triangles
|
||||
ColVertex* vertex = &base_vertex_ptr[i * 6];
|
||||
InitColVertex(&vertex[0], x1, y1, z, col);
|
||||
InitColVertex(&vertex[1], x2, y1, z, col);
|
||||
InitColVertex(&vertex[2], x1, y2, z, col);
|
||||
InitColVertex(&vertex[3], x1, y2, z, col);
|
||||
InitColVertex(&vertex[4], x2, y1, z, col);
|
||||
InitColVertex(&vertex[5], x2, y2, z, col);
|
||||
}
|
||||
|
||||
// unmap the util buffer, and issue the draw
|
||||
util_vbuf->EndAppendData();
|
||||
context->Draw(6 * (UINT)points_to_draw, base_vertex_index);
|
||||
}
|
||||
|
||||
stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader());
|
||||
}
|
||||
|
||||
} // namespace D3D
|
||||
|
||||
} // namespace DX11
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <string>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
namespace D3D
|
||||
{
|
||||
void InitUtils();
|
||||
void ShutdownUtils();
|
||||
|
||||
void SetPointCopySampler();
|
||||
void SetLinearCopySampler();
|
||||
|
||||
void drawShadedTexQuad(ID3D11ShaderResourceView* texture, const D3D11_RECT* rSource,
|
||||
int SourceWidth, int SourceHeight, ID3D11PixelShader* PShader,
|
||||
ID3D11VertexShader* VShader, ID3D11InputLayout* layout,
|
||||
ID3D11GeometryShader* GShader = nullptr, u32 slice = 0);
|
||||
void drawClearQuad(u32 Color, float z);
|
||||
void drawColorQuad(u32 Color, float z, float x1, float y1, float x2, float y2);
|
||||
|
||||
void DrawEFBPokeQuads(EFBAccessType type, const EfbPokeData* points, size_t num_points);
|
||||
}
|
||||
}
|
|
@ -22,11 +22,11 @@ DXPipeline::DXPipeline(ID3D11InputLayout* input_layout, ID3D11VertexShader* vert
|
|||
ID3D11GeometryShader* geometry_shader, ID3D11PixelShader* pixel_shader,
|
||||
ID3D11RasterizerState* rasterizer_state,
|
||||
ID3D11DepthStencilState* depth_state, ID3D11BlendState* blend_state,
|
||||
D3D11_PRIMITIVE_TOPOLOGY primitive_topology)
|
||||
D3D11_PRIMITIVE_TOPOLOGY primitive_topology, bool use_logic_op)
|
||||
: m_input_layout(input_layout), m_vertex_shader(vertex_shader),
|
||||
m_geometry_shader(geometry_shader), m_pixel_shader(pixel_shader),
|
||||
m_rasterizer_state(rasterizer_state), m_depth_state(depth_state), m_blend_state(blend_state),
|
||||
m_primitive_topology(primitive_topology)
|
||||
m_primitive_topology(primitive_topology), m_use_logic_op(use_logic_op)
|
||||
{
|
||||
if (m_input_layout)
|
||||
m_input_layout->AddRef();
|
||||
|
@ -84,13 +84,16 @@ std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& con
|
|||
ASSERT(vertex_shader != nullptr && pixel_shader != nullptr);
|
||||
|
||||
ID3D11InputLayout* input_layout =
|
||||
const_cast<D3DVertexFormat*>(static_cast<const D3DVertexFormat*>(config.vertex_format))
|
||||
->GetInputLayout(vertex_shader->GetByteCode());
|
||||
config.vertex_format ?
|
||||
const_cast<D3DVertexFormat*>(static_cast<const D3DVertexFormat*>(config.vertex_format))
|
||||
->GetInputLayout(vertex_shader->GetByteCode().data(),
|
||||
vertex_shader->GetByteCode().size()) :
|
||||
nullptr;
|
||||
|
||||
return std::make_unique<DXPipeline>(input_layout, vertex_shader->GetD3DVertexShader(),
|
||||
geometry_shader ? geometry_shader->GetD3DGeometryShader() :
|
||||
nullptr,
|
||||
pixel_shader->GetD3DPixelShader(), rasterizer_state,
|
||||
depth_state, blend_state, primitive_topology);
|
||||
return std::make_unique<DXPipeline>(
|
||||
input_layout, vertex_shader->GetD3DVertexShader(),
|
||||
geometry_shader ? geometry_shader->GetD3DGeometryShader() : nullptr,
|
||||
pixel_shader->GetD3DPixelShader(), rasterizer_state, depth_state, blend_state,
|
||||
primitive_topology, config.blending_state.logicopenable);
|
||||
}
|
||||
} // namespace DX11
|
||||
|
|
|
@ -16,7 +16,8 @@ public:
|
|||
DXPipeline(ID3D11InputLayout* input_layout, ID3D11VertexShader* vertex_shader,
|
||||
ID3D11GeometryShader* geometry_shader, ID3D11PixelShader* pixel_shader,
|
||||
ID3D11RasterizerState* rasterizer_state, ID3D11DepthStencilState* depth_state,
|
||||
ID3D11BlendState* blend_state, D3D11_PRIMITIVE_TOPOLOGY primitive_topology);
|
||||
ID3D11BlendState* blend_state, D3D11_PRIMITIVE_TOPOLOGY primitive_topology,
|
||||
bool use_logic_op);
|
||||
~DXPipeline() override;
|
||||
|
||||
ID3D11InputLayout* GetInputLayout() const { return m_input_layout; }
|
||||
|
@ -28,6 +29,8 @@ public:
|
|||
ID3D11BlendState* GetBlendState() const { return m_blend_state; }
|
||||
D3D11_PRIMITIVE_TOPOLOGY GetPrimitiveTopology() const { return m_primitive_topology; }
|
||||
bool HasGeometryShader() const { return m_geometry_shader != nullptr; }
|
||||
bool UseLogicOp() const { return m_use_logic_op; }
|
||||
|
||||
static std::unique_ptr<DXPipeline> Create(const AbstractPipelineConfig& config);
|
||||
|
||||
private:
|
||||
|
@ -39,5 +42,6 @@ private:
|
|||
ID3D11DepthStencilState* m_depth_state;
|
||||
ID3D11BlendState* m_blend_state;
|
||||
D3D11_PRIMITIVE_TOPOLOGY m_primitive_topology;
|
||||
bool m_use_logic_op;
|
||||
};
|
||||
} // namespace DX11
|
||||
|
|
|
@ -2,43 +2,28 @@
|
|||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DShader.h"
|
||||
#include "VideoBackends/D3D/DXShader.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
DXShader::DXShader(D3DBlob* bytecode, ID3D11VertexShader* vs)
|
||||
: AbstractShader(ShaderStage::Vertex), m_bytecode(bytecode), m_shader(vs)
|
||||
{
|
||||
}
|
||||
|
||||
DXShader::DXShader(D3DBlob* bytecode, ID3D11GeometryShader* gs)
|
||||
: AbstractShader(ShaderStage::Geometry), m_bytecode(bytecode), m_shader(gs)
|
||||
{
|
||||
}
|
||||
|
||||
DXShader::DXShader(D3DBlob* bytecode, ID3D11PixelShader* ps)
|
||||
: AbstractShader(ShaderStage::Pixel), m_bytecode(bytecode), m_shader(ps)
|
||||
{
|
||||
}
|
||||
|
||||
DXShader::DXShader(D3DBlob* bytecode, ID3D11ComputeShader* cs)
|
||||
: AbstractShader(ShaderStage::Compute), m_bytecode(bytecode), m_shader(cs)
|
||||
DXShader::DXShader(ShaderStage stage, BinaryData bytecode, ID3D11DeviceChild* shader)
|
||||
: AbstractShader(stage), m_bytecode(bytecode), m_shader(shader)
|
||||
{
|
||||
}
|
||||
|
||||
DXShader::~DXShader()
|
||||
{
|
||||
m_shader->Release();
|
||||
m_bytecode->Release();
|
||||
}
|
||||
|
||||
D3DBlob* DXShader::GetByteCode() const
|
||||
{
|
||||
return m_bytecode;
|
||||
}
|
||||
|
||||
ID3D11VertexShader* DXShader::GetD3DVertexShader() const
|
||||
|
@ -67,48 +52,62 @@ ID3D11ComputeShader* DXShader::GetD3DComputeShader() const
|
|||
|
||||
bool DXShader::HasBinary() const
|
||||
{
|
||||
ASSERT(m_bytecode);
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractShader::BinaryData DXShader::GetBinary() const
|
||||
{
|
||||
return BinaryData(m_bytecode->Data(), m_bytecode->Data() + m_bytecode->Size());
|
||||
return m_bytecode;
|
||||
}
|
||||
|
||||
std::unique_ptr<DXShader> DXShader::CreateFromBlob(ShaderStage stage, D3DBlob* bytecode)
|
||||
std::unique_ptr<DXShader> DXShader::CreateFromBytecode(ShaderStage stage, BinaryData bytecode)
|
||||
{
|
||||
switch (stage)
|
||||
{
|
||||
case ShaderStage::Vertex:
|
||||
{
|
||||
ID3D11VertexShader* vs = D3D::CreateVertexShaderFromByteCode(bytecode);
|
||||
if (vs)
|
||||
return std::make_unique<DXShader>(bytecode, vs);
|
||||
ID3D11VertexShader* vs;
|
||||
HRESULT hr = D3D::device->CreateVertexShader(bytecode.data(), bytecode.size(), nullptr, &vs);
|
||||
CHECK(SUCCEEDED(hr), "Create vertex shader");
|
||||
if (FAILED(hr))
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<DXShader>(ShaderStage::Vertex, std::move(bytecode), vs);
|
||||
}
|
||||
break;
|
||||
|
||||
case ShaderStage::Geometry:
|
||||
{
|
||||
ID3D11GeometryShader* gs = D3D::CreateGeometryShaderFromByteCode(bytecode);
|
||||
if (gs)
|
||||
return std::make_unique<DXShader>(bytecode, gs);
|
||||
ID3D11GeometryShader* gs;
|
||||
HRESULT hr = D3D::device->CreateGeometryShader(bytecode.data(), bytecode.size(), nullptr, &gs);
|
||||
CHECK(SUCCEEDED(hr), "Create geometry shader");
|
||||
if (FAILED(hr))
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<DXShader>(ShaderStage::Geometry, std::move(bytecode), gs);
|
||||
}
|
||||
break;
|
||||
|
||||
case ShaderStage::Pixel:
|
||||
{
|
||||
ID3D11PixelShader* ps = D3D::CreatePixelShaderFromByteCode(bytecode);
|
||||
if (ps)
|
||||
return std::make_unique<DXShader>(bytecode, ps);
|
||||
ID3D11PixelShader* ps;
|
||||
HRESULT hr = D3D::device->CreatePixelShader(bytecode.data(), bytecode.size(), nullptr, &ps);
|
||||
CHECK(SUCCEEDED(hr), "Create pixel shader");
|
||||
if (FAILED(hr))
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<DXShader>(ShaderStage::Pixel, std::move(bytecode), ps);
|
||||
}
|
||||
break;
|
||||
|
||||
case ShaderStage::Compute:
|
||||
{
|
||||
ID3D11ComputeShader* cs = D3D::CreateComputeShaderFromByteCode(bytecode);
|
||||
if (cs)
|
||||
return std::make_unique<DXShader>(bytecode, cs);
|
||||
ID3D11ComputeShader* cs;
|
||||
HRESULT hr = D3D::device->CreateComputeShader(bytecode.data(), bytecode.size(), nullptr, &cs);
|
||||
CHECK(SUCCEEDED(hr), "Create compute shader");
|
||||
if (FAILED(hr))
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<DXShader>(ShaderStage::Compute, std::move(bytecode), cs);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -119,65 +118,85 @@ std::unique_ptr<DXShader> DXShader::CreateFromBlob(ShaderStage stage, D3DBlob* b
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<DXShader> DXShader::CreateFromSource(ShaderStage stage, const char* source,
|
||||
size_t length)
|
||||
static const char* GetCompileTarget(ShaderStage stage)
|
||||
{
|
||||
D3DBlob* bytecode;
|
||||
switch (stage)
|
||||
{
|
||||
case ShaderStage::Vertex:
|
||||
{
|
||||
if (!D3D::CompileVertexShader(std::string(source, length), &bytecode))
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
|
||||
return D3D::VertexShaderVersionString();
|
||||
case ShaderStage::Geometry:
|
||||
{
|
||||
if (!D3D::CompileGeometryShader(std::string(source, length), &bytecode))
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
|
||||
return D3D::GeometryShaderVersionString();
|
||||
case ShaderStage::Pixel:
|
||||
{
|
||||
if (!D3D::CompilePixelShader(std::string(source, length), &bytecode))
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
|
||||
return D3D::PixelShaderVersionString();
|
||||
case ShaderStage::Compute:
|
||||
{
|
||||
if (!D3D::CompileComputeShader(std::string(source, length), &bytecode))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return D3D::ComputeShaderVersionString();
|
||||
default:
|
||||
return nullptr;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<DXShader> shader = CreateFromBlob(stage, bytecode);
|
||||
if (!shader)
|
||||
bool DXShader::CompileShader(BinaryData* out_bytecode, ShaderStage stage, const char* source,
|
||||
size_t length)
|
||||
{
|
||||
static constexpr D3D_SHADER_MACRO macros[] = {{"API_D3D", "1"}, {nullptr, nullptr}};
|
||||
const UINT flags = g_ActiveConfig.bEnableValidationLayer ?
|
||||
(D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION) :
|
||||
(D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_SKIP_VALIDATION);
|
||||
const char* target = GetCompileTarget(stage);
|
||||
|
||||
ID3DBlob* code = nullptr;
|
||||
ID3DBlob* errors = nullptr;
|
||||
HRESULT hr = PD3DCompile(source, length, nullptr, macros, nullptr, "main", target, flags, 0,
|
||||
&code, &errors);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
bytecode->Release();
|
||||
return nullptr;
|
||||
static int num_failures = 0;
|
||||
std::string filename = StringFromFormat(
|
||||
"%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), target, num_failures++);
|
||||
std::ofstream file;
|
||||
File::OpenFStream(file, filename, std::ios_base::out);
|
||||
file.write(source, length);
|
||||
file << "\n";
|
||||
file.write(static_cast<const char*>(errors->GetBufferPointer()), errors->GetBufferSize());
|
||||
file.close();
|
||||
|
||||
PanicAlert("Failed to compile %s:\nDebug info (%s):\n%s", filename.c_str(), target,
|
||||
static_cast<const char*>(errors->GetBufferPointer()));
|
||||
errors->Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
return shader;
|
||||
if (errors && errors->GetBufferSize() > 0)
|
||||
{
|
||||
WARN_LOG(VIDEO, "%s compilation succeeded with warnings:\n%s", target,
|
||||
static_cast<const char*>(errors->GetBufferPointer()));
|
||||
}
|
||||
SAFE_RELEASE(errors);
|
||||
|
||||
out_bytecode->resize(code->GetBufferSize());
|
||||
std::memcpy(out_bytecode->data(), code->GetBufferPointer(), code->GetBufferSize());
|
||||
code->Release();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<DXShader> DXShader::CreateFromSource(ShaderStage stage, const char* source,
|
||||
size_t length)
|
||||
{
|
||||
BinaryData bytecode;
|
||||
if (!CompileShader(&bytecode, stage, source, length))
|
||||
return nullptr;
|
||||
|
||||
return CreateFromBytecode(stage, std::move(bytecode));
|
||||
}
|
||||
|
||||
std::unique_ptr<DXShader> DXShader::CreateFromBinary(ShaderStage stage, const void* data,
|
||||
size_t length)
|
||||
{
|
||||
D3DBlob* bytecode = new D3DBlob(static_cast<unsigned int>(length), static_cast<const u8*>(data));
|
||||
std::unique_ptr<DXShader> shader = CreateFromBlob(stage, bytecode);
|
||||
if (!shader)
|
||||
{
|
||||
bytecode->Release();
|
||||
if (length == 0)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return shader;
|
||||
BinaryData bytecode(length);
|
||||
std::memcpy(bytecode.data(), data, length);
|
||||
return CreateFromBytecode(stage, std::move(bytecode));
|
||||
}
|
||||
|
||||
} // namespace DX11
|
||||
|
|
|
@ -3,13 +3,9 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <d3d11.h>
|
||||
#include <memory>
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
#include "VideoBackends/D3D/D3DBlob.h"
|
||||
#include "VideoCommon/AbstractShader.h"
|
||||
|
||||
namespace DX11
|
||||
|
@ -17,14 +13,11 @@ namespace DX11
|
|||
class DXShader final : public AbstractShader
|
||||
{
|
||||
public:
|
||||
// Note: vs/gs/ps/cs references are transferred.
|
||||
DXShader(D3DBlob* bytecode, ID3D11VertexShader* vs);
|
||||
DXShader(D3DBlob* bytecode, ID3D11GeometryShader* gs);
|
||||
DXShader(D3DBlob* bytecode, ID3D11PixelShader* ps);
|
||||
DXShader(D3DBlob* bytecode, ID3D11ComputeShader* cs);
|
||||
DXShader(ShaderStage stage, BinaryData bytecode, ID3D11DeviceChild* shader);
|
||||
~DXShader() override;
|
||||
|
||||
D3DBlob* GetByteCode() const;
|
||||
const BinaryData& GetByteCode() const { return m_bytecode; }
|
||||
|
||||
ID3D11VertexShader* GetD3DVertexShader() const;
|
||||
ID3D11GeometryShader* GetD3DGeometryShader() const;
|
||||
ID3D11PixelShader* GetD3DPixelShader() const;
|
||||
|
@ -33,8 +26,11 @@ public:
|
|||
bool HasBinary() const override;
|
||||
BinaryData GetBinary() const override;
|
||||
|
||||
// Creates a new shader object. The reference to bytecode is not transfered upon failure.
|
||||
static std::unique_ptr<DXShader> CreateFromBlob(ShaderStage stage, D3DBlob* bytecode);
|
||||
// Creates a new shader object.
|
||||
static std::unique_ptr<DXShader> CreateFromBytecode(ShaderStage stage, BinaryData bytecode);
|
||||
static bool CompileShader(BinaryData* out_bytecode, ShaderStage stage, const char* source,
|
||||
size_t length);
|
||||
|
||||
static std::unique_ptr<DXShader> CreateFromBinary(ShaderStage stage, const void* data,
|
||||
size_t length);
|
||||
static std::unique_ptr<DXShader> CreateFromSource(ShaderStage stage, const char* source,
|
||||
|
@ -42,7 +38,7 @@ public:
|
|||
|
||||
private:
|
||||
ID3D11DeviceChild* m_shader;
|
||||
D3DBlob* m_bytecode;
|
||||
BinaryData m_bytecode;
|
||||
};
|
||||
|
||||
} // namespace DX11
|
||||
|
|
|
@ -9,25 +9,47 @@
|
|||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/D3DTexture.h"
|
||||
#include "VideoBackends/D3D/D3DUtil.h"
|
||||
#include "VideoBackends/D3D/DXTexture.h"
|
||||
#include "VideoBackends/D3D/FramebufferManager.h"
|
||||
#include "VideoBackends/D3D/GeometryShaderCache.h"
|
||||
#include "VideoBackends/D3D/PixelShaderCache.h"
|
||||
#include "VideoBackends/D3D/TextureCache.h"
|
||||
#include "VideoBackends/D3D/VertexShaderCache.h"
|
||||
|
||||
#include "VideoCommon/ImageWrite.h"
|
||||
#include "VideoCommon/TextureConfig.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
namespace
|
||||
{
|
||||
DXGI_FORMAT GetDXGIFormatForHostFormat(AbstractTextureFormat format)
|
||||
DXGI_FORMAT GetDXGIFormatForHostFormat(AbstractTextureFormat format, bool typeless)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case AbstractTextureFormat::DXT1:
|
||||
return DXGI_FORMAT_BC1_UNORM;
|
||||
case AbstractTextureFormat::DXT3:
|
||||
return DXGI_FORMAT_BC2_UNORM;
|
||||
case AbstractTextureFormat::DXT5:
|
||||
return DXGI_FORMAT_BC3_UNORM;
|
||||
case AbstractTextureFormat::BPTC:
|
||||
return DXGI_FORMAT_BC7_UNORM;
|
||||
case AbstractTextureFormat::RGBA8:
|
||||
return typeless ? DXGI_FORMAT_R8G8B8A8_TYPELESS : DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case AbstractTextureFormat::BGRA8:
|
||||
return typeless ? DXGI_FORMAT_B8G8R8A8_TYPELESS : DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
case AbstractTextureFormat::R16:
|
||||
return typeless ? DXGI_FORMAT_R16_TYPELESS : DXGI_FORMAT_R16_UNORM;
|
||||
case AbstractTextureFormat::R32F:
|
||||
return typeless ? DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_R32_FLOAT;
|
||||
case AbstractTextureFormat::D16:
|
||||
return DXGI_FORMAT_R16_TYPELESS;
|
||||
case AbstractTextureFormat::D24_S8:
|
||||
return DXGI_FORMAT_R24G8_TYPELESS;
|
||||
case AbstractTextureFormat::D32F:
|
||||
return DXGI_FORMAT_R32_TYPELESS;
|
||||
case AbstractTextureFormat::D32F_S8:
|
||||
return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
|
||||
default:
|
||||
PanicAlert("Unhandled texture format.");
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
}
|
||||
}
|
||||
DXGI_FORMAT GetSRVFormatForHostFormat(AbstractTextureFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
|
@ -47,23 +69,6 @@ DXGI_FORMAT GetDXGIFormatForHostFormat(AbstractTextureFormat format)
|
|||
return DXGI_FORMAT_R16_UNORM;
|
||||
case AbstractTextureFormat::R32F:
|
||||
return DXGI_FORMAT_R32_FLOAT;
|
||||
case AbstractTextureFormat::D16:
|
||||
return DXGI_FORMAT_R16_TYPELESS;
|
||||
case AbstractTextureFormat::D24_S8:
|
||||
return DXGI_FORMAT_R24G8_TYPELESS;
|
||||
case AbstractTextureFormat::D32F:
|
||||
return DXGI_FORMAT_R32_TYPELESS;
|
||||
case AbstractTextureFormat::D32F_S8:
|
||||
return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
|
||||
default:
|
||||
PanicAlert("Unhandled texture format.");
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
}
|
||||
}
|
||||
DXGI_FORMAT GetSRVFormatForHostFormat(AbstractTextureFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case AbstractTextureFormat::D16:
|
||||
return DXGI_FORMAT_R16_UNORM;
|
||||
case AbstractTextureFormat::D24_S8:
|
||||
|
@ -73,7 +78,25 @@ DXGI_FORMAT GetSRVFormatForHostFormat(AbstractTextureFormat format)
|
|||
case AbstractTextureFormat::D32F_S8:
|
||||
return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
|
||||
default:
|
||||
return GetDXGIFormatForHostFormat(format);
|
||||
PanicAlert("Unhandled SRV format");
|
||||
return DXGI_FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
DXGI_FORMAT GetRTVFormatForHostFormat(AbstractTextureFormat format, bool integer)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case AbstractTextureFormat::RGBA8:
|
||||
return integer ? DXGI_FORMAT_R8G8B8A8_UINT : DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case AbstractTextureFormat::BGRA8:
|
||||
return DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
case AbstractTextureFormat::R16:
|
||||
return integer ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R16_UNORM;
|
||||
case AbstractTextureFormat::R32F:
|
||||
return DXGI_FORMAT_R32_FLOAT;
|
||||
default:
|
||||
PanicAlert("Unhandled RTV format");
|
||||
return DXGI_FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
DXGI_FORMAT GetDSVFormatForHostFormat(AbstractTextureFormat format)
|
||||
|
@ -89,55 +112,87 @@ DXGI_FORMAT GetDSVFormatForHostFormat(AbstractTextureFormat format)
|
|||
case AbstractTextureFormat::D32F_S8:
|
||||
return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
|
||||
default:
|
||||
return GetDXGIFormatForHostFormat(format);
|
||||
PanicAlert("Unhandled DSV format");
|
||||
return DXGI_FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
DXTexture::DXTexture(const TextureConfig& tex_config) : AbstractTexture(tex_config)
|
||||
DXTexture::DXTexture(const TextureConfig& tex_config, ID3D11Texture2D* d3d_texture,
|
||||
ID3D11ShaderResourceView* d3d_srv, ID3D11UnorderedAccessView* d3d_uav)
|
||||
: AbstractTexture(tex_config), m_d3d_texture(d3d_texture), m_d3d_srv(d3d_srv),
|
||||
m_d3d_uav(d3d_uav)
|
||||
{
|
||||
DXGI_FORMAT tex_format = GetDXGIFormatForHostFormat(m_config.format);
|
||||
DXGI_FORMAT srv_format = GetSRVFormatForHostFormat(m_config.format);
|
||||
DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN;
|
||||
DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN;
|
||||
UINT bind_flags = D3D11_BIND_SHADER_RESOURCE;
|
||||
if (tex_config.rendertarget)
|
||||
{
|
||||
if (IsDepthFormat(tex_config.format))
|
||||
{
|
||||
bind_flags |= D3D11_BIND_DEPTH_STENCIL;
|
||||
dsv_format = GetDSVFormatForHostFormat(m_config.format);
|
||||
}
|
||||
else
|
||||
{
|
||||
bind_flags |= D3D11_BIND_RENDER_TARGET;
|
||||
rtv_format = tex_format;
|
||||
}
|
||||
}
|
||||
|
||||
CD3D11_TEXTURE2D_DESC texdesc(tex_format, tex_config.width, tex_config.height, tex_config.layers,
|
||||
tex_config.levels, bind_flags, D3D11_USAGE_DEFAULT, 0,
|
||||
tex_config.samples, 0, 0);
|
||||
|
||||
ID3D11Texture2D* pTexture;
|
||||
HRESULT hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &pTexture);
|
||||
CHECK(SUCCEEDED(hr), "Create backing DXTexture");
|
||||
|
||||
m_texture = new D3DTexture2D(pTexture, static_cast<D3D11_BIND_FLAG>(bind_flags), srv_format,
|
||||
dsv_format, rtv_format, tex_config.samples > 1);
|
||||
|
||||
SAFE_RELEASE(pTexture);
|
||||
}
|
||||
|
||||
DXTexture::~DXTexture()
|
||||
{
|
||||
g_renderer->UnbindTexture(this);
|
||||
m_texture->Release();
|
||||
if (m_d3d_uav)
|
||||
m_d3d_uav->Release();
|
||||
|
||||
if (m_d3d_srv)
|
||||
{
|
||||
if (D3D::stateman->UnsetTexture(m_d3d_srv) != 0)
|
||||
D3D::stateman->ApplyTextures();
|
||||
|
||||
m_d3d_srv->Release();
|
||||
}
|
||||
m_d3d_texture->Release();
|
||||
}
|
||||
|
||||
D3DTexture2D* DXTexture::GetRawTexIdentifier() const
|
||||
std::unique_ptr<DXTexture> DXTexture::Create(const TextureConfig& config)
|
||||
{
|
||||
return m_texture;
|
||||
// Use typeless to create the texture when it's a render target, so we can alias it with an
|
||||
// integer format (for EFB).
|
||||
const DXGI_FORMAT tex_format = GetDXGIFormatForHostFormat(config.format, config.IsRenderTarget());
|
||||
const DXGI_FORMAT srv_format = GetSRVFormatForHostFormat(config.format);
|
||||
UINT bindflags = D3D11_BIND_SHADER_RESOURCE;
|
||||
if (config.IsRenderTarget())
|
||||
bindflags |= IsDepthFormat(config.format) ? D3D11_BIND_DEPTH_STENCIL : D3D11_BIND_RENDER_TARGET;
|
||||
if (config.IsComputeImage())
|
||||
bindflags |= D3D11_BIND_UNORDERED_ACCESS;
|
||||
|
||||
CD3D11_TEXTURE2D_DESC desc(tex_format, config.width, config.height, config.layers, config.levels,
|
||||
bindflags, D3D11_USAGE_DEFAULT, 0, config.samples, 0, 0);
|
||||
ID3D11Texture2D* d3d_texture;
|
||||
HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, &d3d_texture);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
PanicAlert("Failed to create %ux%ux%u D3D backing texture", config.width, config.height,
|
||||
config.layers);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11ShaderResourceView* d3d_srv;
|
||||
const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(d3d_texture,
|
||||
config.IsMultisampled() ?
|
||||
D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY :
|
||||
D3D11_SRV_DIMENSION_TEXTURE2DARRAY,
|
||||
srv_format, 0, config.levels, 0, config.layers);
|
||||
hr = D3D::device->CreateShaderResourceView(d3d_texture, &srv_desc, &d3d_srv);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
PanicAlert("Failed to create %ux%ux%u D3D SRV", config.width, config.height, config.layers);
|
||||
d3d_texture->Release();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11UnorderedAccessView* d3d_uav = nullptr;
|
||||
if (config.IsComputeImage())
|
||||
{
|
||||
const CD3D11_UNORDERED_ACCESS_VIEW_DESC uav_desc(
|
||||
d3d_texture, D3D11_UAV_DIMENSION_TEXTURE2DARRAY, srv_format, 0, 0, config.layers);
|
||||
hr = D3D::device->CreateUnorderedAccessView(d3d_texture, &uav_desc, &d3d_uav);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
PanicAlert("Failed to create %ux%ux%u D3D UAV", config.width, config.height, config.layers);
|
||||
d3d_uav->Release();
|
||||
d3d_texture->Release();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_unique<DXTexture>(config, d3d_texture, d3d_srv, d3d_uav);
|
||||
}
|
||||
|
||||
void DXTexture::CopyRectangleFromTexture(const AbstractTexture* src,
|
||||
|
@ -158,42 +213,11 @@ void DXTexture::CopyRectangleFromTexture(const AbstractTexture* src,
|
|||
src_box.back = 1;
|
||||
|
||||
D3D::context->CopySubresourceRegion(
|
||||
m_texture->GetTex(), D3D11CalcSubresource(dst_level, dst_layer, m_config.levels),
|
||||
dst_rect.left, dst_rect.top, 0, srcentry->m_texture->GetTex(),
|
||||
m_d3d_texture, D3D11CalcSubresource(dst_level, dst_layer, m_config.levels), dst_rect.left,
|
||||
dst_rect.top, 0, srcentry->m_d3d_texture,
|
||||
D3D11CalcSubresource(src_level, src_layer, srcentry->m_config.levels), &src_box);
|
||||
}
|
||||
|
||||
void DXTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
const MathUtil::Rectangle<int>& srcrect,
|
||||
const MathUtil::Rectangle<int>& dstrect)
|
||||
{
|
||||
const DXTexture* srcentry = static_cast<const DXTexture*>(source);
|
||||
ASSERT(m_config.rendertarget);
|
||||
|
||||
g_renderer->ResetAPIState(); // reset any game specific settings
|
||||
|
||||
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(float(dstrect.left), float(dstrect.top),
|
||||
float(dstrect.GetWidth()), float(dstrect.GetHeight()));
|
||||
|
||||
D3D::stateman->UnsetTexture(m_texture->GetSRV());
|
||||
D3D::stateman->Apply();
|
||||
|
||||
D3D::context->OMSetRenderTargets(1, &m_texture->GetRTV(), nullptr);
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
D3D::SetLinearCopySampler();
|
||||
D3D11_RECT srcRC;
|
||||
srcRC.left = srcrect.left;
|
||||
srcRC.right = srcrect.right;
|
||||
srcRC.top = srcrect.top;
|
||||
srcRC.bottom = srcrect.bottom;
|
||||
D3D::drawShadedTexQuad(
|
||||
srcentry->m_texture->GetSRV(), &srcRC, srcentry->m_config.width, srcentry->m_config.height,
|
||||
PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader(), 0);
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
void DXTexture::ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
|
||||
u32 layer, u32 level)
|
||||
{
|
||||
|
@ -204,16 +228,16 @@ void DXTexture::ResolveFromTexture(const AbstractTexture* src, const MathUtil::R
|
|||
rect.top + rect.GetHeight() <= static_cast<int>(srcentry->m_config.height));
|
||||
|
||||
D3D::context->ResolveSubresource(
|
||||
m_texture->GetTex(), D3D11CalcSubresource(level, layer, m_config.levels),
|
||||
srcentry->m_texture->GetTex(), D3D11CalcSubresource(level, layer, srcentry->m_config.levels),
|
||||
GetDXGIFormatForHostFormat(m_config.format));
|
||||
m_d3d_texture, D3D11CalcSubresource(level, layer, m_config.levels), srcentry->m_d3d_texture,
|
||||
D3D11CalcSubresource(level, layer, srcentry->m_config.levels),
|
||||
GetDXGIFormatForHostFormat(m_config.format, false));
|
||||
}
|
||||
|
||||
void DXTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
size_t buffer_size)
|
||||
{
|
||||
size_t src_pitch = CalculateStrideForFormat(m_config.format, row_length);
|
||||
D3D::context->UpdateSubresource(m_texture->GetTex(), level, nullptr, buffer,
|
||||
D3D::context->UpdateSubresource(m_d3d_texture, level, nullptr, buffer,
|
||||
static_cast<UINT>(src_pitch), 0);
|
||||
}
|
||||
|
||||
|
@ -251,8 +275,8 @@ std::unique_ptr<DXStagingTexture> DXStagingTexture::Create(StagingTextureType ty
|
|||
cpu_flags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
|
||||
}
|
||||
|
||||
CD3D11_TEXTURE2D_DESC desc(GetDXGIFormatForHostFormat(config.format), config.width, config.height,
|
||||
1, 1, 0, usage, cpu_flags);
|
||||
CD3D11_TEXTURE2D_DESC desc(GetDXGIFormatForHostFormat(config.format, false), config.width,
|
||||
config.height, 1, 1, 0, usage, cpu_flags);
|
||||
|
||||
ID3D11Texture2D* texture;
|
||||
HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, &texture);
|
||||
|
@ -267,22 +291,33 @@ void DXStagingTexture::CopyFromTexture(const AbstractTexture* src,
|
|||
const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
|
||||
u32 src_level, const MathUtil::Rectangle<int>& dst_rect)
|
||||
{
|
||||
ASSERT(m_type == StagingTextureType::Readback);
|
||||
ASSERT(m_type == StagingTextureType::Readback || m_type == StagingTextureType::Mutable);
|
||||
ASSERT(src_rect.GetWidth() == dst_rect.GetWidth() &&
|
||||
src_rect.GetHeight() == dst_rect.GetHeight());
|
||||
ASSERT(src_rect.left >= 0 && static_cast<u32>(src_rect.right) <= src->GetConfig().width &&
|
||||
src_rect.top >= 0 && static_cast<u32>(src_rect.bottom) <= src->GetConfig().height);
|
||||
ASSERT(src_rect.left >= 0 && static_cast<u32>(src_rect.right) <= src->GetWidth() &&
|
||||
src_rect.top >= 0 && static_cast<u32>(src_rect.bottom) <= src->GetHeight());
|
||||
ASSERT(dst_rect.left >= 0 && static_cast<u32>(dst_rect.right) <= m_config.width &&
|
||||
dst_rect.top >= 0 && static_cast<u32>(dst_rect.bottom) <= m_config.height);
|
||||
|
||||
if (IsMapped())
|
||||
DXStagingTexture::Unmap();
|
||||
|
||||
CD3D11_BOX src_box(src_rect.left, src_rect.top, 0, src_rect.right, src_rect.bottom, 1);
|
||||
D3D::context->CopySubresourceRegion(
|
||||
m_tex, 0, static_cast<u32>(dst_rect.left), static_cast<u32>(dst_rect.top), 0,
|
||||
static_cast<const DXTexture*>(src)->GetRawTexIdentifier()->GetTex(),
|
||||
D3D11CalcSubresource(src_level, src_layer, src->GetConfig().levels), &src_box);
|
||||
if (static_cast<u32>(src_rect.GetWidth()) == GetWidth() &&
|
||||
static_cast<u32>(src_rect.GetHeight()) == GetHeight())
|
||||
{
|
||||
// Copy whole resource, needed for depth textures.
|
||||
D3D::context->CopySubresourceRegion(
|
||||
m_tex, 0, 0, 0, 0, static_cast<const DXTexture*>(src)->GetD3DTexture(),
|
||||
D3D11CalcSubresource(src_level, src_layer, src->GetLevels()), nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
CD3D11_BOX src_box(src_rect.left, src_rect.top, 0, src_rect.right, src_rect.bottom, 1);
|
||||
D3D::context->CopySubresourceRegion(
|
||||
m_tex, 0, static_cast<u32>(dst_rect.left), static_cast<u32>(dst_rect.top), 0,
|
||||
static_cast<const DXTexture*>(src)->GetD3DTexture(),
|
||||
D3D11CalcSubresource(src_level, src_layer, src->GetLevels()), &src_box);
|
||||
}
|
||||
|
||||
m_needs_flush = true;
|
||||
}
|
||||
|
@ -294,19 +329,29 @@ void DXStagingTexture::CopyToTexture(const MathUtil::Rectangle<int>& src_rect, A
|
|||
ASSERT(m_type == StagingTextureType::Upload);
|
||||
ASSERT(src_rect.GetWidth() == dst_rect.GetWidth() &&
|
||||
src_rect.GetHeight() == dst_rect.GetHeight());
|
||||
ASSERT(src_rect.left >= 0 && static_cast<u32>(src_rect.right) <= m_config.width &&
|
||||
src_rect.top >= 0 && static_cast<u32>(src_rect.bottom) <= m_config.height);
|
||||
ASSERT(dst_rect.left >= 0 && static_cast<u32>(dst_rect.right) <= dst->GetConfig().width &&
|
||||
dst_rect.top >= 0 && static_cast<u32>(dst_rect.bottom) <= dst->GetConfig().height);
|
||||
ASSERT(src_rect.left >= 0 && static_cast<u32>(src_rect.right) <= GetWidth() &&
|
||||
src_rect.top >= 0 && static_cast<u32>(src_rect.bottom) <= GetHeight());
|
||||
ASSERT(dst_rect.left >= 0 && static_cast<u32>(dst_rect.right) <= dst->GetWidth() &&
|
||||
dst_rect.top >= 0 && static_cast<u32>(dst_rect.bottom) <= dst->GetHeight());
|
||||
|
||||
if (IsMapped())
|
||||
DXStagingTexture::Unmap();
|
||||
|
||||
CD3D11_BOX src_box(src_rect.left, src_rect.top, 0, src_rect.right, src_rect.bottom, 1);
|
||||
D3D::context->CopySubresourceRegion(
|
||||
static_cast<const DXTexture*>(dst)->GetRawTexIdentifier()->GetTex(),
|
||||
D3D11CalcSubresource(dst_level, dst_layer, dst->GetConfig().levels),
|
||||
static_cast<u32>(dst_rect.left), static_cast<u32>(dst_rect.top), 0, m_tex, 0, &src_box);
|
||||
if (static_cast<u32>(src_rect.GetWidth()) == dst->GetWidth() &&
|
||||
static_cast<u32>(src_rect.GetHeight()) == dst->GetHeight())
|
||||
{
|
||||
D3D::context->CopySubresourceRegion(
|
||||
static_cast<const DXTexture*>(dst)->GetD3DTexture(),
|
||||
D3D11CalcSubresource(dst_level, dst_layer, dst->GetLevels()), 0, 0, 0, m_tex, 0, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
CD3D11_BOX src_box(src_rect.left, src_rect.top, 0, src_rect.right, src_rect.bottom, 1);
|
||||
D3D::context->CopySubresourceRegion(
|
||||
static_cast<const DXTexture*>(dst)->GetD3DTexture(),
|
||||
D3D11CalcSubresource(dst_level, dst_layer, dst->GetLevels()),
|
||||
static_cast<u32>(dst_rect.left), static_cast<u32>(dst_rect.top), 0, m_tex, 0, &src_box);
|
||||
}
|
||||
}
|
||||
|
||||
bool DXStagingTexture::Map()
|
||||
|
@ -348,11 +393,14 @@ void DXStagingTexture::Flush()
|
|||
m_needs_flush = false;
|
||||
}
|
||||
|
||||
DXFramebuffer::DXFramebuffer(AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
|
||||
DXFramebuffer::DXFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
||||
AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
|
||||
u32 width, u32 height, u32 layers, u32 samples,
|
||||
ID3D11RenderTargetView* rtv, ID3D11DepthStencilView* dsv)
|
||||
: AbstractFramebuffer(color_format, depth_format, width, height, layers, samples), m_rtv(rtv),
|
||||
m_dsv(dsv)
|
||||
ID3D11RenderTargetView* rtv, ID3D11RenderTargetView* integer_rtv,
|
||||
ID3D11DepthStencilView* dsv)
|
||||
: AbstractFramebuffer(color_attachment, depth_attachment, color_format, depth_format, width,
|
||||
height, layers, samples),
|
||||
m_rtv(rtv), m_integer_rtv(integer_rtv), m_dsv(dsv)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -360,12 +408,14 @@ DXFramebuffer::~DXFramebuffer()
|
|||
{
|
||||
if (m_rtv)
|
||||
m_rtv->Release();
|
||||
if (m_integer_rtv)
|
||||
m_integer_rtv->Release();
|
||||
if (m_dsv)
|
||||
m_dsv->Release();
|
||||
}
|
||||
|
||||
std::unique_ptr<DXFramebuffer> DXFramebuffer::Create(const DXTexture* color_attachment,
|
||||
const DXTexture* depth_attachment)
|
||||
std::unique_ptr<DXFramebuffer> DXFramebuffer::Create(DXTexture* color_attachment,
|
||||
DXTexture* depth_attachment)
|
||||
{
|
||||
if (!ValidateConfig(color_attachment, depth_attachment))
|
||||
return nullptr;
|
||||
|
@ -381,55 +431,45 @@ std::unique_ptr<DXFramebuffer> DXFramebuffer::Create(const DXTexture* color_atta
|
|||
const u32 samples = either_attachment->GetSamples();
|
||||
|
||||
ID3D11RenderTargetView* rtv = nullptr;
|
||||
ID3D11RenderTargetView* integer_rtv = nullptr;
|
||||
if (color_attachment)
|
||||
{
|
||||
D3D11_RENDER_TARGET_VIEW_DESC desc;
|
||||
desc.Format = GetDXGIFormatForHostFormat(color_attachment->GetConfig().format);
|
||||
if (color_attachment->GetConfig().IsMultisampled())
|
||||
{
|
||||
desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY;
|
||||
desc.Texture2DMSArray.ArraySize = color_attachment->GetConfig().layers;
|
||||
desc.Texture2DMSArray.FirstArraySlice = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
|
||||
desc.Texture2DArray.ArraySize = color_attachment->GetConfig().layers;
|
||||
desc.Texture2DArray.FirstArraySlice = 0;
|
||||
desc.Texture2DArray.MipSlice = 0;
|
||||
}
|
||||
|
||||
HRESULT hr = D3D::device->CreateRenderTargetView(
|
||||
color_attachment->GetRawTexIdentifier()->GetTex(), &desc, &rtv);
|
||||
CD3D11_RENDER_TARGET_VIEW_DESC desc(
|
||||
color_attachment->IsMultisampled() ? D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY :
|
||||
D3D11_RTV_DIMENSION_TEXTURE2DARRAY,
|
||||
GetRTVFormatForHostFormat(color_attachment->GetFormat(), false), 0, 0,
|
||||
color_attachment->GetLayers());
|
||||
HRESULT hr =
|
||||
D3D::device->CreateRenderTargetView(color_attachment->GetD3DTexture(), &desc, &rtv);
|
||||
CHECK(SUCCEEDED(hr), "Create render target view for framebuffer");
|
||||
|
||||
// Only create the integer RTV on Win8+.
|
||||
DXGI_FORMAT integer_format = GetRTVFormatForHostFormat(color_attachment->GetFormat(), true);
|
||||
if (D3D::device1 && integer_format != desc.Format)
|
||||
{
|
||||
desc.Format = integer_format;
|
||||
hr = D3D::device->CreateRenderTargetView(color_attachment->GetD3DTexture(), &desc,
|
||||
&integer_rtv);
|
||||
CHECK(SUCCEEDED(hr), "Create integer render target view for framebuffer");
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11DepthStencilView* dsv = nullptr;
|
||||
if (depth_attachment)
|
||||
{
|
||||
D3D11_DEPTH_STENCIL_VIEW_DESC desc;
|
||||
desc.Format = GetDXGIFormatForHostFormat(depth_attachment->GetConfig().format);
|
||||
if (depth_attachment->GetConfig().IsMultisampled())
|
||||
{
|
||||
desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY;
|
||||
desc.Texture2DMSArray.ArraySize = depth_attachment->GetConfig().layers;
|
||||
desc.Texture2DMSArray.FirstArraySlice = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
|
||||
desc.Texture2DArray.ArraySize = depth_attachment->GetConfig().layers;
|
||||
desc.Texture2DArray.FirstArraySlice = 0;
|
||||
desc.Texture2DArray.MipSlice = 0;
|
||||
}
|
||||
|
||||
HRESULT hr = D3D::device->CreateDepthStencilView(
|
||||
depth_attachment->GetRawTexIdentifier()->GetTex(), &desc, &dsv);
|
||||
const CD3D11_DEPTH_STENCIL_VIEW_DESC desc(
|
||||
depth_attachment->GetConfig().IsMultisampled() ? D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY :
|
||||
D3D11_DSV_DIMENSION_TEXTURE2DARRAY,
|
||||
GetDSVFormatForHostFormat(depth_attachment->GetFormat()), 0, 0,
|
||||
depth_attachment->GetLayers(), 0);
|
||||
HRESULT hr =
|
||||
D3D::device->CreateDepthStencilView(depth_attachment->GetD3DTexture(), &desc, &dsv);
|
||||
CHECK(SUCCEEDED(hr), "Create depth stencil view for framebuffer");
|
||||
}
|
||||
|
||||
return std::make_unique<DXFramebuffer>(color_format, depth_format, width, height, layers, samples,
|
||||
rtv, dsv);
|
||||
return std::make_unique<DXFramebuffer>(color_attachment, depth_attachment, color_format,
|
||||
depth_format, width, height, layers, samples, rtv,
|
||||
integer_rtv, dsv);
|
||||
}
|
||||
|
||||
} // namespace DX11
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <memory>
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
|
@ -11,32 +12,34 @@
|
|||
#include "VideoCommon/AbstractStagingTexture.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
|
||||
class D3DTexture2D;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
class DXTexture final : public AbstractTexture
|
||||
{
|
||||
public:
|
||||
explicit DXTexture(const TextureConfig& tex_config);
|
||||
explicit DXTexture(const TextureConfig& tex_config, ID3D11Texture2D* d3d_texture,
|
||||
ID3D11ShaderResourceView* d3d_srv, ID3D11UnorderedAccessView* d3d_uav);
|
||||
~DXTexture();
|
||||
|
||||
static std::unique_ptr<DXTexture> Create(const TextureConfig& config);
|
||||
|
||||
void CopyRectangleFromTexture(const AbstractTexture* src,
|
||||
const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
|
||||
u32 src_level, const MathUtil::Rectangle<int>& dst_rect,
|
||||
u32 dst_layer, u32 dst_level) override;
|
||||
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
const MathUtil::Rectangle<int>& srcrect,
|
||||
const MathUtil::Rectangle<int>& dstrect) override;
|
||||
void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
|
||||
u32 layer, u32 level) override;
|
||||
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
size_t buffer_size) override;
|
||||
|
||||
D3DTexture2D* GetRawTexIdentifier() const;
|
||||
ID3D11Texture2D* GetD3DTexture() const { return m_d3d_texture; }
|
||||
ID3D11ShaderResourceView* GetD3DSRV() const { return m_d3d_srv; }
|
||||
ID3D11UnorderedAccessView* GetD3DUAV() const { return m_d3d_uav; }
|
||||
|
||||
private:
|
||||
D3DTexture2D* m_texture;
|
||||
ID3D11Texture2D* m_d3d_texture;
|
||||
ID3D11ShaderResourceView* m_d3d_srv;
|
||||
ID3D11UnorderedAccessView* m_d3d_uav;
|
||||
};
|
||||
|
||||
class DXStagingTexture final : public AbstractStagingTexture
|
||||
|
@ -68,19 +71,22 @@ private:
|
|||
class DXFramebuffer final : public AbstractFramebuffer
|
||||
{
|
||||
public:
|
||||
DXFramebuffer(AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
|
||||
DXFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
||||
AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
|
||||
u32 height, u32 layers, u32 samples, ID3D11RenderTargetView* rtv,
|
||||
ID3D11DepthStencilView* dsv);
|
||||
ID3D11RenderTargetView* integer_rtv, ID3D11DepthStencilView* dsv);
|
||||
~DXFramebuffer() override;
|
||||
|
||||
ID3D11RenderTargetView* const* GetRTVArray() const { return &m_rtv; }
|
||||
ID3D11RenderTargetView* const* GetIntegerRTVArray() const { return &m_integer_rtv; }
|
||||
UINT GetNumRTVs() const { return m_rtv ? 1 : 0; }
|
||||
ID3D11DepthStencilView* GetDSV() const { return m_dsv; }
|
||||
static std::unique_ptr<DXFramebuffer> Create(const DXTexture* color_attachment,
|
||||
const DXTexture* depth_attachment);
|
||||
static std::unique_ptr<DXFramebuffer> Create(DXTexture* color_attachment,
|
||||
DXTexture* depth_attachment);
|
||||
|
||||
protected:
|
||||
ID3D11RenderTargetView* m_rtv;
|
||||
ID3D11RenderTargetView* m_integer_rtv;
|
||||
ID3D11DepthStencilView* m_dsv;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,303 +0,0 @@
|
|||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/D3D/FramebufferManager.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/D3DUtil.h"
|
||||
#include "VideoBackends/D3D/GeometryShaderCache.h"
|
||||
#include "VideoBackends/D3D/PixelShaderCache.h"
|
||||
#include "VideoBackends/D3D/Render.h"
|
||||
#include "VideoBackends/D3D/VertexShaderCache.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
static bool s_integer_efb_render_target = false;
|
||||
|
||||
FramebufferManager::Efb FramebufferManager::m_efb;
|
||||
unsigned int FramebufferManager::m_target_width;
|
||||
unsigned int FramebufferManager::m_target_height;
|
||||
|
||||
D3DTexture2D*& FramebufferManager::GetEFBColorTexture()
|
||||
{
|
||||
return m_efb.color_tex;
|
||||
}
|
||||
|
||||
D3DTexture2D*& FramebufferManager::GetEFBColorReadTexture()
|
||||
{
|
||||
return m_efb.color_read_texture;
|
||||
}
|
||||
ID3D11Texture2D*& FramebufferManager::GetEFBColorStagingBuffer()
|
||||
{
|
||||
return m_efb.color_staging_buf;
|
||||
}
|
||||
|
||||
D3DTexture2D*& FramebufferManager::GetEFBDepthTexture()
|
||||
{
|
||||
return m_efb.depth_tex;
|
||||
}
|
||||
D3DTexture2D*& FramebufferManager::GetEFBDepthReadTexture()
|
||||
{
|
||||
return m_efb.depth_read_texture;
|
||||
}
|
||||
ID3D11Texture2D*& FramebufferManager::GetEFBDepthStagingBuffer()
|
||||
{
|
||||
return m_efb.depth_staging_buf;
|
||||
}
|
||||
|
||||
D3DTexture2D*& FramebufferManager::GetResolvedEFBColorTexture()
|
||||
{
|
||||
if (g_ActiveConfig.iMultisamples > 1)
|
||||
{
|
||||
for (int i = 0; i < m_efb.slices; i++)
|
||||
D3D::context->ResolveSubresource(m_efb.resolved_color_tex->GetTex(),
|
||||
D3D11CalcSubresource(0, i, 1), m_efb.color_tex->GetTex(),
|
||||
D3D11CalcSubresource(0, i, 1), DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
return m_efb.resolved_color_tex;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_efb.color_tex;
|
||||
}
|
||||
}
|
||||
|
||||
D3DTexture2D*& FramebufferManager::GetResolvedEFBDepthTexture()
|
||||
{
|
||||
if (g_ActiveConfig.iMultisamples > 1)
|
||||
{
|
||||
// ResolveSubresource does not work with depth textures.
|
||||
// Instead, we use a shader that selects the minimum depth from all samples.
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
CD3D11_VIEWPORT viewport(0.f, 0.f, (float)m_target_width, (float)m_target_height);
|
||||
D3D::context->RSSetViewports(1, &viewport);
|
||||
D3D::context->OMSetRenderTargets(1, &m_efb.resolved_depth_tex->GetRTV(), nullptr);
|
||||
|
||||
const D3D11_RECT source_rect = CD3D11_RECT(0, 0, m_target_width, m_target_height);
|
||||
D3D::drawShadedTexQuad(
|
||||
m_efb.depth_tex->GetSRV(), &source_rect, m_target_width, m_target_height,
|
||||
PixelShaderCache::GetDepthResolveProgram(), VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader());
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
return m_efb.resolved_depth_tex;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_efb.depth_tex;
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManager::SwapReinterpretTexture()
|
||||
{
|
||||
std::swap(m_efb.color_tex, m_efb.color_temp_tex);
|
||||
std::swap(m_efb.color_int_rtv, m_efb.color_temp_int_rtv);
|
||||
}
|
||||
|
||||
void FramebufferManager::SetIntegerEFBRenderTarget(bool enabled)
|
||||
{
|
||||
if (s_integer_efb_render_target == enabled)
|
||||
return;
|
||||
|
||||
// We only use UINT render targets for logic ops, which is only supported with D3D11.1.
|
||||
if (!D3D::device1)
|
||||
return;
|
||||
|
||||
s_integer_efb_render_target = enabled;
|
||||
BindEFBRenderTarget();
|
||||
}
|
||||
|
||||
void FramebufferManager::BindEFBRenderTarget(bool bind_depth)
|
||||
{
|
||||
ID3D11RenderTargetView* rtv =
|
||||
s_integer_efb_render_target ? m_efb.color_int_rtv : m_efb.color_tex->GetRTV();
|
||||
ID3D11DepthStencilView* dsv = bind_depth ? m_efb.depth_tex->GetDSV() : nullptr;
|
||||
D3D::context->OMSetRenderTargets(1, &rtv, dsv);
|
||||
}
|
||||
|
||||
FramebufferManager::FramebufferManager(int target_width, int target_height)
|
||||
{
|
||||
static constexpr std::array<float, 4> clear_color = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
m_target_width = static_cast<unsigned int>(std::max(target_width, 1));
|
||||
m_target_height = static_cast<unsigned int>(std::max(target_height, 1));
|
||||
DXGI_SAMPLE_DESC sample_desc;
|
||||
sample_desc.Count = g_ActiveConfig.iMultisamples;
|
||||
sample_desc.Quality = 0;
|
||||
|
||||
ID3D11Texture2D* buf;
|
||||
D3D11_TEXTURE2D_DESC texdesc;
|
||||
HRESULT hr;
|
||||
|
||||
m_EFBLayers = m_efb.slices = (g_ActiveConfig.stereo_mode != StereoMode::Off) ? 2 : 1;
|
||||
|
||||
// EFB color texture - primary render target
|
||||
texdesc =
|
||||
CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_TYPELESS, m_target_width, m_target_height,
|
||||
m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET,
|
||||
D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf);
|
||||
CHECK(hr == S_OK, "create EFB color texture (size: %dx%d; hr=%#x)", m_target_width,
|
||||
m_target_height, hr);
|
||||
m_efb.color_tex = new D3DTexture2D(
|
||||
buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET),
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
(sample_desc.Count > 1));
|
||||
|
||||
SAFE_RELEASE(buf);
|
||||
D3D::SetDebugObjectName(m_efb.color_tex->GetTex(), "EFB color texture");
|
||||
D3D::SetDebugObjectName(m_efb.color_tex->GetSRV(), "EFB color texture shader resource view");
|
||||
D3D::SetDebugObjectName(m_efb.color_tex->GetRTV(), "EFB color texture render target view");
|
||||
D3D::context->ClearRenderTargetView(m_efb.color_tex->GetRTV(), clear_color.data());
|
||||
|
||||
// Temporary EFB color texture - used in ReinterpretPixelData
|
||||
texdesc =
|
||||
CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_TYPELESS, m_target_width, m_target_height,
|
||||
m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET,
|
||||
D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf);
|
||||
CHECK(hr == S_OK, "create EFB color temp texture (size: %dx%d; hr=%#x)", m_target_width,
|
||||
m_target_height, hr);
|
||||
m_efb.color_temp_tex = new D3DTexture2D(
|
||||
buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET),
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
(sample_desc.Count > 1));
|
||||
SAFE_RELEASE(buf);
|
||||
D3D::SetDebugObjectName(m_efb.color_temp_tex->GetTex(), "EFB color temp texture");
|
||||
D3D::SetDebugObjectName(m_efb.color_temp_tex->GetSRV(),
|
||||
"EFB color temp texture shader resource view");
|
||||
D3D::SetDebugObjectName(m_efb.color_temp_tex->GetRTV(),
|
||||
"EFB color temp texture render target view");
|
||||
D3D::context->ClearRenderTargetView(m_efb.color_temp_tex->GetRTV(), clear_color.data());
|
||||
|
||||
// Integer render targets for EFB, used for logic op
|
||||
CD3D11_RENDER_TARGET_VIEW_DESC int_rtv_desc(m_efb.color_tex->GetTex(),
|
||||
g_ActiveConfig.iMultisamples > 1 ?
|
||||
D3D11_RTV_DIMENSION_TEXTURE2DMS :
|
||||
D3D11_RTV_DIMENSION_TEXTURE2D,
|
||||
DXGI_FORMAT_R8G8B8A8_UINT);
|
||||
hr = D3D::device->CreateRenderTargetView(m_efb.color_tex->GetTex(), &int_rtv_desc,
|
||||
&m_efb.color_int_rtv);
|
||||
CHECK(hr == S_OK, "create EFB integer RTV(hr=%#x)", hr);
|
||||
hr = D3D::device->CreateRenderTargetView(m_efb.color_temp_tex->GetTex(), &int_rtv_desc,
|
||||
&m_efb.color_temp_int_rtv);
|
||||
CHECK(hr == S_OK, "create EFB integer RTV(hr=%#x)", hr);
|
||||
|
||||
// Render buffer for AccessEFB (color data)
|
||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, D3D11_BIND_RENDER_TARGET);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf);
|
||||
CHECK(hr == S_OK, "create EFB color read texture (hr=%#x)", hr);
|
||||
m_efb.color_read_texture = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
|
||||
SAFE_RELEASE(buf);
|
||||
D3D::SetDebugObjectName(m_efb.color_read_texture->GetTex(),
|
||||
"EFB color read texture (used in Renderer::AccessEFB)");
|
||||
D3D::SetDebugObjectName(
|
||||
m_efb.color_read_texture->GetRTV(),
|
||||
"EFB color read texture render target view (used in Renderer::AccessEFB)");
|
||||
|
||||
// AccessEFB - Sysmem buffer used to retrieve the pixel data from depth_read_texture
|
||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, 0, D3D11_USAGE_STAGING,
|
||||
D3D11_CPU_ACCESS_READ);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &m_efb.color_staging_buf);
|
||||
CHECK(hr == S_OK, "create EFB color staging buffer (hr=%#x)", hr);
|
||||
D3D::SetDebugObjectName(m_efb.color_staging_buf,
|
||||
"EFB color staging texture (used for Renderer::AccessEFB)");
|
||||
|
||||
// EFB depth buffer - primary depth buffer
|
||||
texdesc =
|
||||
CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_TYPELESS, m_target_width, m_target_height, m_efb.slices,
|
||||
1, D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE,
|
||||
D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf);
|
||||
CHECK(hr == S_OK, "create EFB depth texture (size: %dx%d; hr=%#x)", m_target_width,
|
||||
m_target_height, hr);
|
||||
m_efb.depth_tex = new D3DTexture2D(
|
||||
buf, (D3D11_BIND_FLAG)(D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE),
|
||||
DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_D32_FLOAT, DXGI_FORMAT_UNKNOWN, (sample_desc.Count > 1));
|
||||
SAFE_RELEASE(buf);
|
||||
D3D::SetDebugObjectName(m_efb.depth_tex->GetTex(), "EFB depth texture");
|
||||
D3D::SetDebugObjectName(m_efb.depth_tex->GetDSV(), "EFB depth texture depth stencil view");
|
||||
D3D::SetDebugObjectName(m_efb.depth_tex->GetSRV(), "EFB depth texture shader resource view");
|
||||
D3D::context->ClearDepthStencilView(m_efb.depth_tex->GetDSV(), D3D11_CLEAR_DEPTH, 0.0f, 0);
|
||||
|
||||
// Render buffer for AccessEFB (depth data)
|
||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 1, 1, 1, 1, D3D11_BIND_RENDER_TARGET);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf);
|
||||
CHECK(hr == S_OK, "create EFB depth read texture (hr=%#x)", hr);
|
||||
m_efb.depth_read_texture = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
|
||||
SAFE_RELEASE(buf);
|
||||
D3D::SetDebugObjectName(m_efb.depth_read_texture->GetTex(),
|
||||
"EFB depth read texture (used in Renderer::AccessEFB)");
|
||||
D3D::SetDebugObjectName(
|
||||
m_efb.depth_read_texture->GetRTV(),
|
||||
"EFB depth read texture render target view (used in Renderer::AccessEFB)");
|
||||
|
||||
// AccessEFB - Sysmem buffer used to retrieve the pixel data from depth_read_texture
|
||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 1, 1, 1, 1, 0, D3D11_USAGE_STAGING,
|
||||
D3D11_CPU_ACCESS_READ);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &m_efb.depth_staging_buf);
|
||||
CHECK(hr == S_OK, "create EFB depth staging buffer (hr=%#x)", hr);
|
||||
D3D::SetDebugObjectName(m_efb.depth_staging_buf,
|
||||
"EFB depth staging texture (used for Renderer::AccessEFB)");
|
||||
|
||||
if (g_ActiveConfig.iMultisamples > 1)
|
||||
{
|
||||
// Framebuffer resolve textures (color+depth)
|
||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height,
|
||||
m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE,
|
||||
D3D11_USAGE_DEFAULT, 0, 1);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf);
|
||||
CHECK(hr == S_OK, "create EFB color resolve texture (size: %dx%d; hr=%#x)", m_target_width,
|
||||
m_target_height, hr);
|
||||
m_efb.resolved_color_tex =
|
||||
new D3DTexture2D(buf, D3D11_BIND_SHADER_RESOURCE, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
SAFE_RELEASE(buf);
|
||||
D3D::SetDebugObjectName(m_efb.resolved_color_tex->GetTex(), "EFB color resolve texture");
|
||||
D3D::SetDebugObjectName(m_efb.resolved_color_tex->GetSRV(),
|
||||
"EFB color resolve texture shader resource view");
|
||||
|
||||
texdesc =
|
||||
CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, m_target_width, m_target_height, m_efb.slices,
|
||||
1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf);
|
||||
CHECK(hr == S_OK, "create EFB depth resolve texture (size: %dx%d; hr=%#x)", m_target_width,
|
||||
m_target_height, hr);
|
||||
m_efb.resolved_depth_tex = new D3DTexture2D(
|
||||
buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET),
|
||||
DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32_FLOAT);
|
||||
SAFE_RELEASE(buf);
|
||||
D3D::SetDebugObjectName(m_efb.resolved_depth_tex->GetTex(), "EFB depth resolve texture");
|
||||
D3D::SetDebugObjectName(m_efb.resolved_depth_tex->GetSRV(),
|
||||
"EFB depth resolve texture shader resource view");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_efb.resolved_color_tex = nullptr;
|
||||
m_efb.resolved_depth_tex = nullptr;
|
||||
}
|
||||
s_integer_efb_render_target = false;
|
||||
}
|
||||
|
||||
FramebufferManager::~FramebufferManager()
|
||||
{
|
||||
SAFE_RELEASE(m_efb.color_tex);
|
||||
SAFE_RELEASE(m_efb.color_int_rtv);
|
||||
SAFE_RELEASE(m_efb.color_temp_tex);
|
||||
SAFE_RELEASE(m_efb.color_temp_int_rtv);
|
||||
SAFE_RELEASE(m_efb.color_staging_buf);
|
||||
SAFE_RELEASE(m_efb.color_read_texture);
|
||||
SAFE_RELEASE(m_efb.resolved_color_tex);
|
||||
SAFE_RELEASE(m_efb.depth_tex);
|
||||
SAFE_RELEASE(m_efb.depth_staging_buf);
|
||||
SAFE_RELEASE(m_efb.depth_read_texture);
|
||||
SAFE_RELEASE(m_efb.resolved_depth_tex);
|
||||
}
|
||||
|
||||
} // namespace DX11
|
|
@ -1,96 +0,0 @@
|
|||
// Copyright 2009 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoBackends/D3D/D3DTexture.h"
|
||||
#include "VideoCommon/FramebufferManagerBase.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
// On the GameCube, the game sends a request for the graphics processor to
|
||||
// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM
|
||||
// called the XFB (External Framebuffer). The size and location of the XFB is
|
||||
// decided at the time of the copy, and the format is always YUYV. The video
|
||||
// interface is given a pointer to the XFB, which will be decoded and
|
||||
// displayed on the TV.
|
||||
//
|
||||
// There are two ways for Dolphin to emulate this:
|
||||
//
|
||||
// Real XFB mode:
|
||||
//
|
||||
// Dolphin will behave like the GameCube and encode the EFB to
|
||||
// a portion of GameCube RAM. The emulated video interface will decode the data
|
||||
// for output to the screen.
|
||||
//
|
||||
// Advantages: Behaves exactly like the GameCube.
|
||||
// Disadvantages: Resolution will be limited.
|
||||
//
|
||||
// Virtual XFB mode:
|
||||
//
|
||||
// When a request is made to copy the EFB to an XFB, Dolphin
|
||||
// will remember the RAM location and size of the XFB in a Virtual XFB list.
|
||||
// The video interface will look up the XFB in the list and use the enhanced
|
||||
// data stored there, if available.
|
||||
//
|
||||
// Advantages: Enables high resolution graphics, better than real hardware.
|
||||
// Disadvantages: If the GameCube CPU writes directly to the XFB (which is
|
||||
// possible but uncommon), the Virtual XFB will not capture this information.
|
||||
|
||||
// There may be multiple XFBs in GameCube RAM. This is the maximum number to
|
||||
// virtualize.
|
||||
|
||||
class FramebufferManager : public FramebufferManagerBase
|
||||
{
|
||||
public:
|
||||
FramebufferManager(int target_width, int target_height);
|
||||
~FramebufferManager();
|
||||
|
||||
static D3DTexture2D*& GetEFBColorTexture();
|
||||
static D3DTexture2D*& GetEFBColorReadTexture();
|
||||
static ID3D11Texture2D*& GetEFBColorStagingBuffer();
|
||||
|
||||
static D3DTexture2D*& GetEFBDepthTexture();
|
||||
static D3DTexture2D*& GetEFBDepthReadTexture();
|
||||
static ID3D11Texture2D*& GetEFBDepthStagingBuffer();
|
||||
|
||||
static D3DTexture2D*& GetResolvedEFBColorTexture();
|
||||
static D3DTexture2D*& GetResolvedEFBDepthTexture();
|
||||
|
||||
static D3DTexture2D*& GetEFBColorTempTexture() { return m_efb.color_temp_tex; }
|
||||
static void SwapReinterpretTexture();
|
||||
static void SetIntegerEFBRenderTarget(bool enabled);
|
||||
static void BindEFBRenderTarget(bool bind_depth = true);
|
||||
|
||||
private:
|
||||
static struct Efb
|
||||
{
|
||||
D3DTexture2D* color_tex;
|
||||
ID3D11RenderTargetView* color_int_rtv;
|
||||
ID3D11Texture2D* color_staging_buf;
|
||||
D3DTexture2D* color_read_texture;
|
||||
|
||||
D3DTexture2D* depth_tex;
|
||||
ID3D11Texture2D* depth_staging_buf;
|
||||
D3DTexture2D* depth_read_texture;
|
||||
|
||||
D3DTexture2D* color_temp_tex;
|
||||
ID3D11RenderTargetView* color_temp_int_rtv;
|
||||
|
||||
D3DTexture2D* resolved_color_tex;
|
||||
D3DTexture2D* resolved_depth_tex;
|
||||
|
||||
int slices;
|
||||
} m_efb;
|
||||
|
||||
static unsigned int m_target_width;
|
||||
static unsigned int m_target_height;
|
||||
};
|
||||
|
||||
} // namespace DX11
|
|
@ -1,113 +0,0 @@
|
|||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/ConfigManager.h"
|
||||
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DShader.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/FramebufferManager.h"
|
||||
#include "VideoBackends/D3D/GeometryShaderCache.h"
|
||||
|
||||
#include "VideoCommon/Debugger.h"
|
||||
#include "VideoCommon/GeometryShaderGen.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
ID3D11GeometryShader* ClearGeometryShader = nullptr;
|
||||
ID3D11GeometryShader* CopyGeometryShader = nullptr;
|
||||
|
||||
ID3D11GeometryShader* GeometryShaderCache::GetClearGeometryShader()
|
||||
{
|
||||
return (g_ActiveConfig.stereo_mode != StereoMode::Off) ? ClearGeometryShader : nullptr;
|
||||
}
|
||||
ID3D11GeometryShader* GeometryShaderCache::GetCopyGeometryShader()
|
||||
{
|
||||
return (g_ActiveConfig.stereo_mode != StereoMode::Off) ? CopyGeometryShader : nullptr;
|
||||
}
|
||||
|
||||
const char clear_shader_code[] = {
|
||||
"struct VSOUTPUT\n"
|
||||
"{\n"
|
||||
" float4 vPosition : POSITION;\n"
|
||||
" float4 vColor0 : COLOR0;\n"
|
||||
"};\n"
|
||||
"struct GSOUTPUT\n"
|
||||
"{\n"
|
||||
" float4 vPosition : POSITION;\n"
|
||||
" float4 vColor0 : COLOR0;\n"
|
||||
" uint slice : SV_RenderTargetArrayIndex;\n"
|
||||
"};\n"
|
||||
"[maxvertexcount(6)]\n"
|
||||
"void main(triangle VSOUTPUT o[3], inout TriangleStream<GSOUTPUT> Output)\n"
|
||||
"{\n"
|
||||
"for(int slice = 0; slice < 2; slice++)\n"
|
||||
"{\n"
|
||||
" for(int i = 0; i < 3; i++)\n"
|
||||
" {\n"
|
||||
" GSOUTPUT OUT;\n"
|
||||
" OUT.vPosition = o[i].vPosition;\n"
|
||||
" OUT.vColor0 = o[i].vColor0;\n"
|
||||
" OUT.slice = slice;\n"
|
||||
" Output.Append(OUT);\n"
|
||||
" }\n"
|
||||
" Output.RestartStrip();\n"
|
||||
"}\n"
|
||||
"}\n"};
|
||||
|
||||
const char copy_shader_code[] = {
|
||||
"struct VSOUTPUT\n"
|
||||
"{\n"
|
||||
" float4 vPosition : POSITION;\n"
|
||||
" float3 vTexCoord : TEXCOORD0;\n"
|
||||
"};\n"
|
||||
"struct GSOUTPUT\n"
|
||||
"{\n"
|
||||
" float4 vPosition : POSITION;\n"
|
||||
" float3 vTexCoord : TEXCOORD0;\n"
|
||||
" uint slice : SV_RenderTargetArrayIndex;\n"
|
||||
"};\n"
|
||||
"[maxvertexcount(6)]\n"
|
||||
"void main(triangle VSOUTPUT o[3], inout TriangleStream<GSOUTPUT> Output)\n"
|
||||
"{\n"
|
||||
"for(int slice = 0; slice < 2; slice++)\n"
|
||||
"{\n"
|
||||
" for(int i = 0; i < 3; i++)\n"
|
||||
" {\n"
|
||||
" GSOUTPUT OUT;\n"
|
||||
" OUT.vPosition = o[i].vPosition;\n"
|
||||
" OUT.vTexCoord = o[i].vTexCoord;\n"
|
||||
" OUT.vTexCoord.z = float(slice);\n"
|
||||
" OUT.slice = slice;\n"
|
||||
" Output.Append(OUT);\n"
|
||||
" }\n"
|
||||
" Output.RestartStrip();\n"
|
||||
"}\n"
|
||||
"}\n"};
|
||||
|
||||
void GeometryShaderCache::Init()
|
||||
{
|
||||
// used when drawing clear quads
|
||||
ClearGeometryShader = D3D::CompileAndCreateGeometryShader(clear_shader_code);
|
||||
CHECK(ClearGeometryShader != nullptr, "Create clear geometry shader");
|
||||
D3D::SetDebugObjectName(ClearGeometryShader, "clear geometry shader");
|
||||
|
||||
// used for buffer copy
|
||||
CopyGeometryShader = D3D::CompileAndCreateGeometryShader(copy_shader_code);
|
||||
CHECK(CopyGeometryShader != nullptr, "Create copy geometry shader");
|
||||
D3D::SetDebugObjectName(CopyGeometryShader, "copy geometry shader");
|
||||
}
|
||||
|
||||
void GeometryShaderCache::Shutdown()
|
||||
{
|
||||
SAFE_RELEASE(ClearGeometryShader);
|
||||
SAFE_RELEASE(CopyGeometryShader);
|
||||
}
|
||||
} // DX11
|
|
@ -1,27 +0,0 @@
|
|||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <map>
|
||||
|
||||
#include "VideoCommon/GeometryShaderGen.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
class GeometryShaderCache
|
||||
{
|
||||
public:
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
static ID3D11GeometryShader* GetClearGeometryShader();
|
||||
static ID3D11GeometryShader* GetCopyGeometryShader();
|
||||
|
||||
static ID3D11Buffer* GetConstantBuffer();
|
||||
static void UpdateConstantBuffer(const void* data, u32 data_size);
|
||||
};
|
||||
|
||||
} // namespace DX11
|
|
@ -5,10 +5,10 @@
|
|||
#include <array>
|
||||
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DBlob.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/DXShader.h"
|
||||
#include "VideoBackends/D3D/Render.h"
|
||||
#include "VideoBackends/D3D/VertexManager.h"
|
||||
#include "VideoBackends/D3D/VertexShaderCache.h"
|
||||
#include "VideoCommon/NativeVertexFormat.h"
|
||||
|
||||
namespace DX11
|
||||
|
@ -16,7 +16,7 @@ namespace DX11
|
|||
std::mutex s_input_layout_lock;
|
||||
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
{
|
||||
return std::make_unique<D3DVertexFormat>(vtx_decl);
|
||||
}
|
||||
|
@ -77,11 +77,11 @@ DXGI_FORMAT VarToD3D(VarType t, int size, bool integer)
|
|||
return retval;
|
||||
}
|
||||
|
||||
D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& _vtx_decl)
|
||||
{
|
||||
this->vtx_decl = _vtx_decl;
|
||||
D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
: NativeVertexFormat(vtx_decl)
|
||||
|
||||
const AttributeFormat* format = &_vtx_decl.position;
|
||||
{
|
||||
const AttributeFormat* format = &vtx_decl.position;
|
||||
if (format->enable)
|
||||
{
|
||||
m_elems[m_num_elems].SemanticName = "POSITION";
|
||||
|
@ -93,7 +93,7 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& _vtx_decl)
|
|||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
format = &_vtx_decl.normals[i];
|
||||
format = &vtx_decl.normals[i];
|
||||
if (format->enable)
|
||||
{
|
||||
m_elems[m_num_elems].SemanticName = "NORMAL";
|
||||
|
@ -107,7 +107,7 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& _vtx_decl)
|
|||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
format = &_vtx_decl.colors[i];
|
||||
format = &vtx_decl.colors[i];
|
||||
if (format->enable)
|
||||
{
|
||||
m_elems[m_num_elems].SemanticName = "COLOR";
|
||||
|
@ -121,7 +121,7 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& _vtx_decl)
|
|||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
format = &_vtx_decl.texcoords[i];
|
||||
format = &vtx_decl.texcoords[i];
|
||||
if (format->enable)
|
||||
{
|
||||
m_elems[m_num_elems].SemanticName = "TEXCOORD";
|
||||
|
@ -133,7 +133,7 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& _vtx_decl)
|
|||
}
|
||||
}
|
||||
|
||||
format = &_vtx_decl.posmtx;
|
||||
format = &vtx_decl.posmtx;
|
||||
if (format->enable)
|
||||
{
|
||||
m_elems[m_num_elems].SemanticName = "BLENDINDICES";
|
||||
|
@ -150,7 +150,7 @@ D3DVertexFormat::~D3DVertexFormat()
|
|||
SAFE_RELEASE(layout);
|
||||
}
|
||||
|
||||
ID3D11InputLayout* D3DVertexFormat::GetInputLayout(D3DBlob* vs_bytecode)
|
||||
ID3D11InputLayout* D3DVertexFormat::GetInputLayout(const void* vs_bytecode, size_t vs_bytecode_size)
|
||||
{
|
||||
// CreateInputLayout requires a shader input, but it only looks at the signature of the shader,
|
||||
// so we don't need to recompute it if the shader changes.
|
||||
|
@ -158,8 +158,8 @@ ID3D11InputLayout* D3DVertexFormat::GetInputLayout(D3DBlob* vs_bytecode)
|
|||
if (layout)
|
||||
return layout;
|
||||
|
||||
HRESULT hr = DX11::D3D::device->CreateInputLayout(
|
||||
m_elems.data(), m_num_elems, vs_bytecode->Data(), vs_bytecode->Size(), &layout);
|
||||
HRESULT hr = D3D::device->CreateInputLayout(m_elems.data(), m_num_elems, vs_bytecode,
|
||||
vs_bytecode_size, &layout);
|
||||
if (FAILED(hr))
|
||||
PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__);
|
||||
DX11::D3D::SetDebugObjectName(m_layout, "input layout used to emulate the GX pipeline");
|
||||
|
|
|
@ -1,160 +0,0 @@
|
|||
// Copyright 2011 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/D3D/PSTextureEncoder.h"
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DShader.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/D3DUtil.h"
|
||||
#include "VideoBackends/D3D/DXTexture.h"
|
||||
#include "VideoBackends/D3D/FramebufferManager.h"
|
||||
#include "VideoBackends/D3D/Render.h"
|
||||
#include "VideoBackends/D3D/TextureCache.h"
|
||||
#include "VideoBackends/D3D/VertexShaderCache.h"
|
||||
|
||||
#include "VideoCommon/AbstractStagingTexture.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
#include "VideoCommon/TextureConversionShader.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
struct EFBEncodeParams
|
||||
{
|
||||
s32 SrcLeft;
|
||||
s32 SrcTop;
|
||||
u32 DestWidth;
|
||||
u32 ScaleFactor;
|
||||
float y_scale;
|
||||
float gamma_rcp;
|
||||
float clamp_top;
|
||||
float clamp_bottom;
|
||||
float filter_coefficients[3];
|
||||
u32 padding;
|
||||
};
|
||||
|
||||
PSTextureEncoder::PSTextureEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
PSTextureEncoder::~PSTextureEncoder() = default;
|
||||
|
||||
void PSTextureEncoder::Init()
|
||||
{
|
||||
m_encoding_render_texture = g_renderer->CreateTexture(TextureCache::GetEncodingTextureConfig());
|
||||
ASSERT(m_encoding_render_texture);
|
||||
|
||||
// Create constant buffer for uploading data to shaders
|
||||
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(EFBEncodeParams), D3D11_BIND_CONSTANT_BUFFER);
|
||||
HRESULT hr = D3D::device->CreateBuffer(&bd, nullptr, &m_encode_params);
|
||||
CHECK(SUCCEEDED(hr), "create efb encode params buffer");
|
||||
D3D::SetDebugObjectName(m_encode_params, "efb encoder params buffer");
|
||||
}
|
||||
|
||||
void PSTextureEncoder::Shutdown()
|
||||
{
|
||||
for (auto& it : m_encoding_shaders)
|
||||
SAFE_RELEASE(it.second);
|
||||
m_encoding_shaders.clear();
|
||||
|
||||
SAFE_RELEASE(m_encode_params);
|
||||
}
|
||||
|
||||
void PSTextureEncoder::Encode(
|
||||
AbstractStagingTexture* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row,
|
||||
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half,
|
||||
float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const TextureCacheBase::CopyFilterCoefficientArray& filter_coefficients)
|
||||
{
|
||||
// Resolve MSAA targets before copying.
|
||||
// FIXME: Instead of resolving EFB, it would be better to pick out a
|
||||
// single sample from each pixel. The game may break if it isn't
|
||||
// expecting the blurred edges around multisampled shapes.
|
||||
ID3D11ShaderResourceView* pEFB = params.depth ?
|
||||
FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() :
|
||||
FramebufferManager::GetResolvedEFBColorTexture()->GetSRV();
|
||||
|
||||
// Reset API
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
// Set up all the state for EFB encoding
|
||||
{
|
||||
const u32 words_per_row = bytes_per_row / sizeof(u32);
|
||||
|
||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(words_per_row), FLOAT(num_blocks_y));
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
|
||||
constexpr EFBRectangle fullSrcRect(0, 0, EFB_WIDTH, EFB_HEIGHT);
|
||||
TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(fullSrcRect);
|
||||
|
||||
D3D::context->OMSetRenderTargets(
|
||||
1,
|
||||
&static_cast<DXTexture*>(m_encoding_render_texture.get())->GetRawTexIdentifier()->GetRTV(),
|
||||
nullptr);
|
||||
|
||||
EFBEncodeParams encode_params;
|
||||
encode_params.SrcLeft = src_rect.left;
|
||||
encode_params.SrcTop = src_rect.top;
|
||||
encode_params.DestWidth = native_width;
|
||||
encode_params.ScaleFactor = scale_by_half ? 2 : 1;
|
||||
encode_params.y_scale = y_scale;
|
||||
encode_params.gamma_rcp = 1.0f / gamma;
|
||||
encode_params.clamp_top = clamp_top ? src_rect.top / float(EFB_HEIGHT) : 0.0f;
|
||||
encode_params.clamp_bottom = clamp_bottom ? src_rect.bottom / float(EFB_HEIGHT) : 1.0f;
|
||||
for (size_t i = 0; i < filter_coefficients.size(); i++)
|
||||
encode_params.filter_coefficients[i] = filter_coefficients[i];
|
||||
|
||||
D3D::context->UpdateSubresource(m_encode_params, 0, nullptr, &encode_params, 0, 0);
|
||||
D3D::stateman->SetPixelConstants(m_encode_params);
|
||||
|
||||
// We also linear filtering for both box filtering and downsampling higher resolutions to 1x
|
||||
// TODO: This only produces perfect downsampling for 2x IR, other resolutions will need more
|
||||
// complex down filtering to average all pixels and produce the correct result.
|
||||
// Also, box filtering won't be correct for anything other than 1x IR
|
||||
if (scale_by_half || g_renderer->GetEFBScale() != 1 || y_scale > 1.0f)
|
||||
D3D::SetLinearCopySampler();
|
||||
else
|
||||
D3D::SetPointCopySampler();
|
||||
|
||||
D3D::drawShadedTexQuad(pEFB, targetRect.AsRECT(), g_renderer->GetTargetWidth(),
|
||||
g_renderer->GetTargetHeight(), GetEncodingPixelShader(params),
|
||||
VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout());
|
||||
|
||||
// Copy to staging buffer
|
||||
MathUtil::Rectangle<int> copy_rect(0, 0, words_per_row, num_blocks_y);
|
||||
dst->CopyFromTexture(m_encoding_render_texture.get(), copy_rect, 0, 0, copy_rect);
|
||||
}
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
ID3D11PixelShader* PSTextureEncoder::GetEncodingPixelShader(const EFBCopyParams& params)
|
||||
{
|
||||
auto iter = m_encoding_shaders.find(params);
|
||||
if (iter != m_encoding_shaders.end())
|
||||
return iter->second;
|
||||
|
||||
D3DBlob* bytecode = nullptr;
|
||||
const char* shader = TextureConversionShaderTiled::GenerateEncodingShader(params, APIType::D3D);
|
||||
if (!D3D::CompilePixelShader(shader, &bytecode))
|
||||
{
|
||||
PanicAlert("Failed to compile texture encoding shader.");
|
||||
m_encoding_shaders[params] = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11PixelShader* newShader;
|
||||
HRESULT hr =
|
||||
D3D::device->CreatePixelShader(bytecode->Data(), bytecode->Size(), nullptr, &newShader);
|
||||
CHECK(SUCCEEDED(hr), "create efb encoder pixel shader");
|
||||
|
||||
m_encoding_shaders.emplace(params, newShader);
|
||||
return newShader;
|
||||
}
|
||||
} // namespace DX11
|
|
@ -1,53 +0,0 @@
|
|||
// Copyright 2011 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
#include "VideoCommon/TextureConversionShader.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
||||
class AbstractTexture;
|
||||
class AbstractStagingTexture;
|
||||
|
||||
struct ID3D11Texture2D;
|
||||
struct ID3D11RenderTargetView;
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11InputLayout;
|
||||
struct ID3D11VertexShader;
|
||||
struct ID3D11PixelShader;
|
||||
struct ID3D11ClassLinkage;
|
||||
struct ID3D11ClassInstance;
|
||||
struct ID3D11BlendState;
|
||||
struct ID3D11DepthStencilState;
|
||||
struct ID3D11RasterizerState;
|
||||
struct ID3D11SamplerState;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
class PSTextureEncoder final
|
||||
{
|
||||
public:
|
||||
PSTextureEncoder();
|
||||
~PSTextureEncoder();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
void Encode(AbstractStagingTexture* dst, const EFBCopyParams& params, u32 native_width,
|
||||
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const TextureCacheBase::CopyFilterCoefficientArray& filter_coefficients);
|
||||
|
||||
private:
|
||||
ID3D11PixelShader* GetEncodingPixelShader(const EFBCopyParams& params);
|
||||
|
||||
ID3D11Buffer* m_encode_params = nullptr;
|
||||
std::unique_ptr<AbstractTexture> m_encoding_render_texture;
|
||||
std::map<EFBCopyParams, ID3D11PixelShader*> m_encoding_shaders;
|
||||
};
|
||||
}
|
|
@ -1,315 +0,0 @@
|
|||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Host.h"
|
||||
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DShader.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/PixelShaderCache.h"
|
||||
|
||||
#include "VideoCommon/Debugger.h"
|
||||
#include "VideoCommon/PixelShaderGen.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
ID3D11PixelShader* s_ColorCopyProgram[2] = {nullptr};
|
||||
ID3D11PixelShader* s_ClearProgram = nullptr;
|
||||
ID3D11PixelShader* s_AnaglyphProgram = nullptr;
|
||||
ID3D11PixelShader* s_DepthResolveProgram = nullptr;
|
||||
ID3D11PixelShader* s_rgba6_to_rgb8[2] = {nullptr};
|
||||
ID3D11PixelShader* s_rgb8_to_rgba6[2] = {nullptr};
|
||||
|
||||
const char clear_program_code[] = {"void main(\n"
|
||||
"out float4 ocol0 : SV_Target,\n"
|
||||
"in float4 pos : SV_Position,\n"
|
||||
"in float4 incol0 : COLOR0){\n"
|
||||
"ocol0 = incol0;\n"
|
||||
"}\n"};
|
||||
|
||||
// TODO: Find some way to avoid having separate shaders for non-MSAA and MSAA...
|
||||
const char color_copy_program_code[] = {"sampler samp0 : register(s0);\n"
|
||||
"Texture2DArray Tex0 : register(t0);\n"
|
||||
"void main(\n"
|
||||
"out float4 ocol0 : SV_Target,\n"
|
||||
"in float4 pos : SV_Position,\n"
|
||||
"in float3 uv0 : TEXCOORD0){\n"
|
||||
"ocol0 = Tex0.Sample(samp0,uv0);\n"
|
||||
"}\n"};
|
||||
|
||||
// Anaglyph Red-Cyan shader based on Dubois algorithm
|
||||
// Constants taken from the paper:
|
||||
// "Conversion of a Stereo Pair to Anaglyph with
|
||||
// the Least-Squares Projection Method"
|
||||
// Eric Dubois, March 2009
|
||||
const char anaglyph_program_code[] = {"sampler samp0 : register(s0);\n"
|
||||
"Texture2DArray Tex0 : register(t0);\n"
|
||||
"void main(\n"
|
||||
"out float4 ocol0 : SV_Target,\n"
|
||||
"in float4 pos : SV_Position,\n"
|
||||
"in float3 uv0 : TEXCOORD0){\n"
|
||||
"float4 c0 = Tex0.Sample(samp0, float3(uv0.xy, 0.0));\n"
|
||||
"float4 c1 = Tex0.Sample(samp0, float3(uv0.xy, 1.0));\n"
|
||||
"float3x3 l = float3x3( 0.437, 0.449, 0.164,\n"
|
||||
" -0.062,-0.062,-0.024,\n"
|
||||
" -0.048,-0.050,-0.017);\n"
|
||||
"float3x3 r = float3x3(-0.011,-0.032,-0.007,\n"
|
||||
" 0.377, 0.761, 0.009,\n"
|
||||
" -0.026,-0.093, 1.234);\n"
|
||||
"ocol0 = float4(mul(l, c0.rgb) + mul(r, c1.rgb), c0.a);\n"
|
||||
"}\n"};
|
||||
|
||||
// TODO: Improve sampling algorithm!
|
||||
const char color_copy_program_code_msaa[] = {
|
||||
"#define SAMPLES %d\n"
|
||||
"sampler samp0 : register(s0);\n"
|
||||
"Texture2DMSArray<float4, SAMPLES> Tex0 : register(t0);\n"
|
||||
"void main(\n"
|
||||
"out float4 ocol0 : SV_Target,\n"
|
||||
"in float4 pos : SV_Position,\n"
|
||||
"in float3 uv0 : TEXCOORD0){\n"
|
||||
"int width, height, slices, samples;\n"
|
||||
"Tex0.GetDimensions(width, height, slices, samples);\n"
|
||||
"ocol0 = 0;\n"
|
||||
"for(int i = 0; i < SAMPLES; ++i)\n"
|
||||
" ocol0 += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n"
|
||||
"ocol0 /= SAMPLES;\n"
|
||||
"}\n"};
|
||||
|
||||
const char depth_resolve_program[] = {
|
||||
"#define SAMPLES %d\n"
|
||||
"Texture2DMSArray<float4, SAMPLES> Tex0 : register(t0);\n"
|
||||
"void main(\n"
|
||||
" out float ocol0 : SV_Target,\n"
|
||||
" in float4 pos : SV_Position,\n"
|
||||
" in float3 uv0 : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
" int width, height, slices, samples;\n"
|
||||
" Tex0.GetDimensions(width, height, slices, samples);\n"
|
||||
" ocol0 = Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), 0).x;\n"
|
||||
" for(int i = 1; i < SAMPLES; ++i)\n"
|
||||
" ocol0 = min(ocol0, Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i).x);\n"
|
||||
"}\n"};
|
||||
|
||||
const char reint_rgba6_to_rgb8[] = {"sampler samp0 : register(s0);\n"
|
||||
"Texture2DArray Tex0 : register(t0);\n"
|
||||
"void main(\n"
|
||||
" out float4 ocol0 : SV_Target,\n"
|
||||
" in float4 pos : SV_Position,\n"
|
||||
" in float3 uv0 : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
" int4 src6 = round(Tex0.Sample(samp0,uv0) * 63.f);\n"
|
||||
" int4 dst8;\n"
|
||||
" dst8.r = (src6.r << 2) | (src6.g >> 4);\n"
|
||||
" dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n"
|
||||
" dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n"
|
||||
" dst8.a = 255;\n"
|
||||
" ocol0 = (float4)dst8 / 255.f;\n"
|
||||
"}"};
|
||||
|
||||
const char reint_rgba6_to_rgb8_msaa[] = {
|
||||
"#define SAMPLES %d\n"
|
||||
"sampler samp0 : register(s0);\n"
|
||||
"Texture2DMSArray<float4, SAMPLES> Tex0 : register(t0);\n"
|
||||
"void main(\n"
|
||||
" out float4 ocol0 : SV_Target,\n"
|
||||
" in float4 pos : SV_Position,\n"
|
||||
" in float3 uv0 : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
" int width, height, slices, samples;\n"
|
||||
" Tex0.GetDimensions(width, height, slices, samples);\n"
|
||||
" float4 texcol = 0;\n"
|
||||
" for (int i = 0; i < SAMPLES; ++i)\n"
|
||||
" texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n"
|
||||
" texcol /= SAMPLES;\n"
|
||||
" int4 src6 = round(texcol * 63.f);\n"
|
||||
" int4 dst8;\n"
|
||||
" dst8.r = (src6.r << 2) | (src6.g >> 4);\n"
|
||||
" dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n"
|
||||
" dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n"
|
||||
" dst8.a = 255;\n"
|
||||
" ocol0 = (float4)dst8 / 255.f;\n"
|
||||
"}"};
|
||||
|
||||
const char reint_rgb8_to_rgba6[] = {"sampler samp0 : register(s0);\n"
|
||||
"Texture2DArray Tex0 : register(t0);\n"
|
||||
"void main(\n"
|
||||
" out float4 ocol0 : SV_Target,\n"
|
||||
" in float4 pos : SV_Position,\n"
|
||||
" in float3 uv0 : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
" int4 src8 = round(Tex0.Sample(samp0,uv0) * 255.f);\n"
|
||||
" int4 dst6;\n"
|
||||
" dst6.r = src8.r >> 2;\n"
|
||||
" dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n"
|
||||
" dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n"
|
||||
" dst6.a = src8.b & 0x3F;\n"
|
||||
" ocol0 = (float4)dst6 / 63.f;\n"
|
||||
"}\n"};
|
||||
|
||||
const char reint_rgb8_to_rgba6_msaa[] = {
|
||||
"#define SAMPLES %d\n"
|
||||
"sampler samp0 : register(s0);\n"
|
||||
"Texture2DMSArray<float4, SAMPLES> Tex0 : register(t0);\n"
|
||||
"void main(\n"
|
||||
" out float4 ocol0 : SV_Target,\n"
|
||||
" in float4 pos : SV_Position,\n"
|
||||
" in float3 uv0 : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
" int width, height, slices, samples;\n"
|
||||
" Tex0.GetDimensions(width, height, slices, samples);\n"
|
||||
" float4 texcol = 0;\n"
|
||||
" for (int i = 0; i < SAMPLES; ++i)\n"
|
||||
" texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n"
|
||||
" texcol /= SAMPLES;\n"
|
||||
" int4 src8 = round(texcol * 255.f);\n"
|
||||
" int4 dst6;\n"
|
||||
" dst6.r = src8.r >> 2;\n"
|
||||
" dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n"
|
||||
" dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n"
|
||||
" dst6.a = src8.b & 0x3F;\n"
|
||||
" ocol0 = (float4)dst6 / 63.f;\n"
|
||||
"}\n"};
|
||||
|
||||
ID3D11PixelShader* PixelShaderCache::ReinterpRGBA6ToRGB8(bool multisampled)
|
||||
{
|
||||
if (!multisampled || g_ActiveConfig.iMultisamples <= 1)
|
||||
{
|
||||
if (!s_rgba6_to_rgb8[0])
|
||||
{
|
||||
s_rgba6_to_rgb8[0] = D3D::CompileAndCreatePixelShader(reint_rgba6_to_rgb8);
|
||||
CHECK(s_rgba6_to_rgb8[0], "Create RGBA6 to RGB8 pixel shader");
|
||||
D3D::SetDebugObjectName(s_rgba6_to_rgb8[0], "RGBA6 to RGB8 pixel shader");
|
||||
}
|
||||
return s_rgba6_to_rgb8[0];
|
||||
}
|
||||
else if (!s_rgba6_to_rgb8[1])
|
||||
{
|
||||
// create MSAA shader for current AA mode
|
||||
std::string buf = StringFromFormat(reint_rgba6_to_rgb8_msaa, g_ActiveConfig.iMultisamples);
|
||||
s_rgba6_to_rgb8[1] = D3D::CompileAndCreatePixelShader(buf);
|
||||
|
||||
CHECK(s_rgba6_to_rgb8[1], "Create RGBA6 to RGB8 MSAA pixel shader");
|
||||
D3D::SetDebugObjectName(s_rgba6_to_rgb8[1], "RGBA6 to RGB8 MSAA pixel shader");
|
||||
}
|
||||
return s_rgba6_to_rgb8[1];
|
||||
}
|
||||
|
||||
ID3D11PixelShader* PixelShaderCache::ReinterpRGB8ToRGBA6(bool multisampled)
|
||||
{
|
||||
if (!multisampled || g_ActiveConfig.iMultisamples <= 1)
|
||||
{
|
||||
if (!s_rgb8_to_rgba6[0])
|
||||
{
|
||||
s_rgb8_to_rgba6[0] = D3D::CompileAndCreatePixelShader(reint_rgb8_to_rgba6);
|
||||
CHECK(s_rgb8_to_rgba6[0], "Create RGB8 to RGBA6 pixel shader");
|
||||
D3D::SetDebugObjectName(s_rgb8_to_rgba6[0], "RGB8 to RGBA6 pixel shader");
|
||||
}
|
||||
return s_rgb8_to_rgba6[0];
|
||||
}
|
||||
else if (!s_rgb8_to_rgba6[1])
|
||||
{
|
||||
// create MSAA shader for current AA mode
|
||||
std::string buf = StringFromFormat(reint_rgb8_to_rgba6_msaa, g_ActiveConfig.iMultisamples);
|
||||
s_rgb8_to_rgba6[1] = D3D::CompileAndCreatePixelShader(buf);
|
||||
|
||||
CHECK(s_rgb8_to_rgba6[1], "Create RGB8 to RGBA6 MSAA pixel shader");
|
||||
D3D::SetDebugObjectName(s_rgb8_to_rgba6[1], "RGB8 to RGBA6 MSAA pixel shader");
|
||||
}
|
||||
return s_rgb8_to_rgba6[1];
|
||||
}
|
||||
|
||||
ID3D11PixelShader* PixelShaderCache::GetColorCopyProgram(bool multisampled)
|
||||
{
|
||||
if (!multisampled || g_ActiveConfig.iMultisamples <= 1)
|
||||
{
|
||||
return s_ColorCopyProgram[0];
|
||||
}
|
||||
else if (s_ColorCopyProgram[1])
|
||||
{
|
||||
return s_ColorCopyProgram[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// create MSAA shader for current AA mode
|
||||
std::string buf = StringFromFormat(color_copy_program_code_msaa, g_ActiveConfig.iMultisamples);
|
||||
s_ColorCopyProgram[1] = D3D::CompileAndCreatePixelShader(buf);
|
||||
CHECK(s_ColorCopyProgram[1] != nullptr, "Create color copy MSAA pixel shader");
|
||||
D3D::SetDebugObjectName(s_ColorCopyProgram[1], "color copy MSAA pixel shader");
|
||||
return s_ColorCopyProgram[1];
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11PixelShader* PixelShaderCache::GetClearProgram()
|
||||
{
|
||||
return s_ClearProgram;
|
||||
}
|
||||
|
||||
ID3D11PixelShader* PixelShaderCache::GetAnaglyphProgram()
|
||||
{
|
||||
return s_AnaglyphProgram;
|
||||
}
|
||||
|
||||
ID3D11PixelShader* PixelShaderCache::GetDepthResolveProgram()
|
||||
{
|
||||
if (s_DepthResolveProgram != nullptr)
|
||||
return s_DepthResolveProgram;
|
||||
|
||||
// create MSAA shader for current AA mode
|
||||
std::string buf = StringFromFormat(depth_resolve_program, g_ActiveConfig.iMultisamples);
|
||||
s_DepthResolveProgram = D3D::CompileAndCreatePixelShader(buf);
|
||||
CHECK(s_DepthResolveProgram != nullptr, "Create depth matrix MSAA pixel shader");
|
||||
D3D::SetDebugObjectName(s_DepthResolveProgram, "depth resolve pixel shader");
|
||||
return s_DepthResolveProgram;
|
||||
}
|
||||
|
||||
void PixelShaderCache::Init()
|
||||
{
|
||||
// used when drawing clear quads
|
||||
s_ClearProgram = D3D::CompileAndCreatePixelShader(clear_program_code);
|
||||
CHECK(s_ClearProgram != nullptr, "Create clear pixel shader");
|
||||
D3D::SetDebugObjectName(s_ClearProgram, "clear pixel shader");
|
||||
|
||||
// used for anaglyph stereoscopy
|
||||
s_AnaglyphProgram = D3D::CompileAndCreatePixelShader(anaglyph_program_code);
|
||||
CHECK(s_AnaglyphProgram != nullptr, "Create anaglyph pixel shader");
|
||||
D3D::SetDebugObjectName(s_AnaglyphProgram, "anaglyph pixel shader");
|
||||
|
||||
// used when copying/resolving the color buffer
|
||||
s_ColorCopyProgram[0] = D3D::CompileAndCreatePixelShader(color_copy_program_code);
|
||||
CHECK(s_ColorCopyProgram[0] != nullptr, "Create color copy pixel shader");
|
||||
D3D::SetDebugObjectName(s_ColorCopyProgram[0], "color copy pixel shader");
|
||||
}
|
||||
|
||||
// Used in Swap() when AA mode has changed
|
||||
void PixelShaderCache::InvalidateMSAAShaders()
|
||||
{
|
||||
SAFE_RELEASE(s_ColorCopyProgram[1]);
|
||||
SAFE_RELEASE(s_rgb8_to_rgba6[1]);
|
||||
SAFE_RELEASE(s_rgba6_to_rgb8[1]);
|
||||
SAFE_RELEASE(s_DepthResolveProgram);
|
||||
}
|
||||
|
||||
void PixelShaderCache::Shutdown()
|
||||
{
|
||||
SAFE_RELEASE(s_ClearProgram);
|
||||
SAFE_RELEASE(s_AnaglyphProgram);
|
||||
SAFE_RELEASE(s_DepthResolveProgram);
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
SAFE_RELEASE(s_ColorCopyProgram[i]);
|
||||
SAFE_RELEASE(s_rgba6_to_rgb8[i]);
|
||||
SAFE_RELEASE(s_rgb8_to_rgba6[i]);
|
||||
}
|
||||
}
|
||||
} // DX11
|
|
@ -1,34 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <map>
|
||||
|
||||
#include "VideoCommon/AsyncShaderCompiler.h"
|
||||
#include "VideoCommon/PixelShaderGen.h"
|
||||
#include "VideoCommon/UberShaderPixel.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
class D3DBlob;
|
||||
|
||||
class PixelShaderCache
|
||||
{
|
||||
public:
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
static ID3D11PixelShader* GetColorCopyProgram(bool multisampled);
|
||||
static ID3D11PixelShader* GetClearProgram();
|
||||
static ID3D11PixelShader* GetAnaglyphProgram();
|
||||
static ID3D11PixelShader* GetDepthResolveProgram();
|
||||
static ID3D11PixelShader* ReinterpRGBA6ToRGB8(bool multisampled);
|
||||
static ID3D11PixelShader* ReinterpRGB8ToRGBA6(bool multisampled);
|
||||
|
||||
static void InvalidateMSAAShaders();
|
||||
};
|
||||
|
||||
} // namespace DX11
|
|
@ -23,33 +23,19 @@
|
|||
#include "VideoBackends/D3D/BoundingBox.h"
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/D3DUtil.h"
|
||||
#include "VideoBackends/D3D/DXPipeline.h"
|
||||
#include "VideoBackends/D3D/DXShader.h"
|
||||
#include "VideoBackends/D3D/DXTexture.h"
|
||||
#include "VideoBackends/D3D/FramebufferManager.h"
|
||||
#include "VideoBackends/D3D/GeometryShaderCache.h"
|
||||
#include "VideoBackends/D3D/PixelShaderCache.h"
|
||||
#include "VideoBackends/D3D/TextureCache.h"
|
||||
#include "VideoBackends/D3D/VertexShaderCache.h"
|
||||
|
||||
#include "VideoCommon/BPFunctions.h"
|
||||
#include "VideoCommon/OnScreenDisplay.h"
|
||||
#include "VideoCommon/PixelEngine.h"
|
||||
#include "VideoCommon/FramebufferManager.h"
|
||||
#include "VideoCommon/PostProcessing.h"
|
||||
#include "VideoCommon/RenderState.h"
|
||||
#include "VideoCommon/VideoBackendBase.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
#include "VideoCommon/XFMemory.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
// Reserve 512KB for vertices, and 64KB for uniforms.
|
||||
// This should be sufficient for our usages, and if more is required,
|
||||
// we split it into multiple draws.
|
||||
constexpr u32 UTILITY_VBO_SIZE = 512 * 1024;
|
||||
constexpr u32 UTILITY_UBO_SIZE = 64 * 1024;
|
||||
|
||||
// Nvidia stereo blitting struct defined in "nvstereo.h" from the Nvidia SDK
|
||||
typedef struct _Nv_Stereo_Image_Header
|
||||
{
|
||||
|
@ -67,118 +53,9 @@ Renderer::Renderer(int backbuffer_width, int backbuffer_height, float backbuffer
|
|||
AbstractTextureFormat::RGBA8)
|
||||
{
|
||||
m_last_fullscreen_state = D3D::GetFullscreenState();
|
||||
g_framebuffer_manager = std::make_unique<FramebufferManager>(m_target_width, m_target_height);
|
||||
SetupDeviceObjects();
|
||||
|
||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)m_target_width, (float)m_target_height);
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
FramebufferManager::BindEFBRenderTarget();
|
||||
m_current_framebuffer_width = m_target_width;
|
||||
m_current_framebuffer_height = m_target_height;
|
||||
}
|
||||
|
||||
Renderer::~Renderer()
|
||||
{
|
||||
TeardownDeviceObjects();
|
||||
}
|
||||
|
||||
void Renderer::SetupDeviceObjects()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
D3D11_DEPTH_STENCIL_DESC ddesc;
|
||||
ddesc.DepthEnable = FALSE;
|
||||
ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
|
||||
ddesc.DepthFunc = D3D11_COMPARISON_ALWAYS;
|
||||
ddesc.StencilEnable = FALSE;
|
||||
ddesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
|
||||
ddesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
|
||||
hr = D3D::device->CreateDepthStencilState(&ddesc, &m_clear_depth_states[0]);
|
||||
CHECK(hr == S_OK, "Create depth state for Renderer::ClearScreen");
|
||||
ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
|
||||
ddesc.DepthEnable = TRUE;
|
||||
hr = D3D::device->CreateDepthStencilState(&ddesc, &m_clear_depth_states[1]);
|
||||
CHECK(hr == S_OK, "Create depth state for Renderer::ClearScreen");
|
||||
ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
|
||||
hr = D3D::device->CreateDepthStencilState(&ddesc, &m_clear_depth_states[2]);
|
||||
CHECK(hr == S_OK, "Create depth state for Renderer::ClearScreen");
|
||||
D3D::SetDebugObjectName(m_clear_depth_states[0],
|
||||
"depth state for Renderer::ClearScreen (depth buffer disabled)");
|
||||
D3D::SetDebugObjectName(
|
||||
m_clear_depth_states[1],
|
||||
"depth state for Renderer::ClearScreen (depth buffer enabled, writing enabled)");
|
||||
D3D::SetDebugObjectName(
|
||||
m_clear_depth_states[2],
|
||||
"depth state for Renderer::ClearScreen (depth buffer enabled, writing disabled)");
|
||||
|
||||
D3D11_BLEND_DESC blenddesc;
|
||||
blenddesc.AlphaToCoverageEnable = FALSE;
|
||||
blenddesc.IndependentBlendEnable = FALSE;
|
||||
blenddesc.RenderTarget[0].BlendEnable = FALSE;
|
||||
blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||
blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
|
||||
blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
|
||||
blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
||||
blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
||||
blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
||||
blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||
hr = D3D::device->CreateBlendState(&blenddesc, &m_reset_blend_state);
|
||||
CHECK(hr == S_OK, "Create blend state for Renderer::ResetAPIState");
|
||||
D3D::SetDebugObjectName(m_reset_blend_state, "blend state for Renderer::ResetAPIState");
|
||||
|
||||
m_clear_blend_states[0] = m_reset_blend_state;
|
||||
m_reset_blend_state->AddRef();
|
||||
|
||||
blenddesc.RenderTarget[0].RenderTargetWriteMask =
|
||||
D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | D3D11_COLOR_WRITE_ENABLE_BLUE;
|
||||
hr = D3D::device->CreateBlendState(&blenddesc, &m_clear_blend_states[1]);
|
||||
CHECK(hr == S_OK, "Create blend state for Renderer::ClearScreen");
|
||||
|
||||
blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALPHA;
|
||||
hr = D3D::device->CreateBlendState(&blenddesc, &m_clear_blend_states[2]);
|
||||
CHECK(hr == S_OK, "Create blend state for Renderer::ClearScreen");
|
||||
|
||||
blenddesc.RenderTarget[0].RenderTargetWriteMask = 0;
|
||||
hr = D3D::device->CreateBlendState(&blenddesc, &m_clear_blend_states[3]);
|
||||
CHECK(hr == S_OK, "Create blend state for Renderer::ClearScreen");
|
||||
|
||||
ddesc.DepthEnable = FALSE;
|
||||
ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
|
||||
ddesc.DepthFunc = D3D11_COMPARISON_LESS;
|
||||
ddesc.StencilEnable = FALSE;
|
||||
ddesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
|
||||
ddesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
|
||||
hr = D3D::device->CreateDepthStencilState(&ddesc, &m_reset_depth_state);
|
||||
CHECK(hr == S_OK, "Create depth state for Renderer::ResetAPIState");
|
||||
D3D::SetDebugObjectName(m_reset_depth_state, "depth stencil state for Renderer::ResetAPIState");
|
||||
|
||||
D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false,
|
||||
0, 0.f, 0.f, false, false, false, false);
|
||||
hr = D3D::device->CreateRasterizerState(&rastdesc, &m_reset_rast_state);
|
||||
CHECK(hr == S_OK, "Create rasterizer state for Renderer::ResetAPIState");
|
||||
D3D::SetDebugObjectName(m_reset_rast_state, "rasterizer state for Renderer::ResetAPIState");
|
||||
|
||||
m_screenshot_texture = nullptr;
|
||||
}
|
||||
|
||||
// Kill off all device objects
|
||||
void Renderer::TeardownDeviceObjects()
|
||||
{
|
||||
g_framebuffer_manager.reset();
|
||||
|
||||
SAFE_RELEASE(m_clear_blend_states[0]);
|
||||
SAFE_RELEASE(m_clear_blend_states[1]);
|
||||
SAFE_RELEASE(m_clear_blend_states[2]);
|
||||
SAFE_RELEASE(m_clear_blend_states[3]);
|
||||
SAFE_RELEASE(m_clear_depth_states[0]);
|
||||
SAFE_RELEASE(m_clear_depth_states[1]);
|
||||
SAFE_RELEASE(m_clear_depth_states[2]);
|
||||
SAFE_RELEASE(m_reset_blend_state);
|
||||
SAFE_RELEASE(m_reset_depth_state);
|
||||
SAFE_RELEASE(m_reset_rast_state);
|
||||
SAFE_RELEASE(m_screenshot_texture);
|
||||
SAFE_RELEASE(m_3d_vision_texture);
|
||||
}
|
||||
Renderer::~Renderer() = default;
|
||||
|
||||
void Renderer::Create3DVisionTexture(int width, int height)
|
||||
{
|
||||
|
@ -200,9 +77,17 @@ void Renderer::Create3DVisionTexture(int width, int height)
|
|||
sys_data.SysMemPitch = pitch;
|
||||
sys_data.pSysMem = memory.get();
|
||||
|
||||
m_3d_vision_texture =
|
||||
D3DTexture2D::Create(width * 2, height + 1, D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, &sys_data);
|
||||
CD3D11_TEXTURE2D_DESC texture_desc(DXGI_FORMAT_R8G8B8A8_UNORM, width * 2, height + 1, 1, 1,
|
||||
D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, 0, 1, 0, 0);
|
||||
ID3D11Texture2D* texture;
|
||||
HRESULT hr = D3D::device->CreateTexture2D(&texture_desc, &sys_data, &texture);
|
||||
CHECK(SUCCEEDED(hr), "Create 3D Vision Texture");
|
||||
m_3d_vision_texture = std::make_unique<DXTexture>(TextureConfig(width * 2, height + 1, 1, 1, 1,
|
||||
AbstractTextureFormat::RGBA8,
|
||||
AbstractTextureFlag_RenderTarget),
|
||||
texture, nullptr, nullptr);
|
||||
m_3d_vision_framebuffer =
|
||||
DXFramebuffer::Create(static_cast<DXTexture*>(m_3d_vision_texture.get()), nullptr);
|
||||
}
|
||||
|
||||
bool Renderer::IsHeadless() const
|
||||
|
@ -212,7 +97,7 @@ bool Renderer::IsHeadless() const
|
|||
|
||||
std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config)
|
||||
{
|
||||
return std::make_unique<DXTexture>(config);
|
||||
return DXTexture::Create(config);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTextureType type,
|
||||
|
@ -221,12 +106,11 @@ std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTe
|
|||
return DXStagingTexture::Create(type, config);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
Renderer::CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment)
|
||||
std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment,
|
||||
AbstractTexture* depth_attachment)
|
||||
{
|
||||
return DXFramebuffer::Create(static_cast<const DXTexture*>(color_attachment),
|
||||
static_cast<const DXTexture*>(depth_attachment));
|
||||
return DXFramebuffer::Create(static_cast<DXTexture*>(color_attachment),
|
||||
static_cast<DXTexture*>(depth_attachment));
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
||||
|
@ -249,220 +133,44 @@ std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelin
|
|||
void Renderer::SetPipeline(const AbstractPipeline* pipeline)
|
||||
{
|
||||
const DXPipeline* dx_pipeline = static_cast<const DXPipeline*>(pipeline);
|
||||
if (!dx_pipeline)
|
||||
if (m_current_pipeline == dx_pipeline)
|
||||
return;
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
|
||||
{
|
||||
TargetRectangle result;
|
||||
result.left = EFBToScaledX(rc.left);
|
||||
result.top = EFBToScaledY(rc.top);
|
||||
result.right = EFBToScaledX(rc.right);
|
||||
result.bottom = EFBToScaledY(rc.bottom);
|
||||
return result;
|
||||
if (dx_pipeline)
|
||||
{
|
||||
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());
|
||||
}
|
||||
else
|
||||
{
|
||||
// These will be destroyed at pipeline destruction.
|
||||
D3D::stateman->SetInputLayout(nullptr);
|
||||
D3D::stateman->SetVertexShader(nullptr);
|
||||
D3D::stateman->SetGeometryShader(nullptr);
|
||||
D3D::stateman->SetPixelShader(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc)
|
||||
{
|
||||
const RECT rect = {rc.left, rc.top, rc.right, rc.bottom};
|
||||
// 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);
|
||||
}
|
||||
|
||||
// This function allows the CPU to directly access the EFB.
|
||||
// There are EFB peeks (which will read the color or depth of a pixel)
|
||||
// and EFB pokes (which will change the color or depth of a pixel).
|
||||
//
|
||||
// The behavior of EFB peeks can only be modified by:
|
||||
// - GX_PokeAlphaRead
|
||||
// The behavior of EFB pokes can be modified by:
|
||||
// - GX_PokeAlphaMode (TODO)
|
||||
// - GX_PokeAlphaUpdate (TODO)
|
||||
// - GX_PokeBlendMode (TODO)
|
||||
// - GX_PokeColorUpdate (TODO)
|
||||
// - GX_PokeDither (TODO)
|
||||
// - GX_PokeDstAlpha (TODO)
|
||||
// - GX_PokeZMode (TODO)
|
||||
u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
|
||||
{
|
||||
// Convert EFB dimensions to the ones of our render target
|
||||
EFBRectangle efbPixelRc;
|
||||
efbPixelRc.left = x;
|
||||
efbPixelRc.top = y;
|
||||
efbPixelRc.right = x + 1;
|
||||
efbPixelRc.bottom = y + 1;
|
||||
TargetRectangle targetPixelRc = Renderer::ConvertEFBRectangle(efbPixelRc);
|
||||
|
||||
// Take the mean of the resulting dimensions; TODO: Don't use the center pixel, compute the
|
||||
// average color instead
|
||||
D3D11_RECT RectToLock;
|
||||
if (type == EFBAccessType::PeekColor || type == EFBAccessType::PeekZ)
|
||||
{
|
||||
RectToLock.left = (targetPixelRc.left + targetPixelRc.right) / 2;
|
||||
RectToLock.top = (targetPixelRc.top + targetPixelRc.bottom) / 2;
|
||||
RectToLock.right = RectToLock.left + 1;
|
||||
RectToLock.bottom = RectToLock.top + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
RectToLock.left = targetPixelRc.left;
|
||||
RectToLock.right = targetPixelRc.right;
|
||||
RectToLock.top = targetPixelRc.top;
|
||||
RectToLock.bottom = targetPixelRc.bottom;
|
||||
}
|
||||
|
||||
// Reset any game specific settings.
|
||||
ResetAPIState();
|
||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, 1.f, 1.f);
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
D3D::SetPointCopySampler();
|
||||
|
||||
// Select copy and read textures depending on if we are doing a color or depth read (since they
|
||||
// are different formats).
|
||||
D3DTexture2D* source_tex;
|
||||
D3DTexture2D* read_tex;
|
||||
ID3D11Texture2D* staging_tex;
|
||||
if (type == EFBAccessType::PeekColor)
|
||||
{
|
||||
source_tex = FramebufferManager::GetEFBColorTexture();
|
||||
read_tex = FramebufferManager::GetEFBColorReadTexture();
|
||||
staging_tex = FramebufferManager::GetEFBColorStagingBuffer();
|
||||
}
|
||||
else
|
||||
{
|
||||
source_tex = FramebufferManager::GetEFBDepthTexture();
|
||||
read_tex = FramebufferManager::GetEFBDepthReadTexture();
|
||||
staging_tex = FramebufferManager::GetEFBDepthStagingBuffer();
|
||||
}
|
||||
|
||||
// Select pixel shader (we don't want to average depth samples, instead select the minimum).
|
||||
ID3D11PixelShader* copy_pixel_shader;
|
||||
if (type == EFBAccessType::PeekZ && g_ActiveConfig.iMultisamples > 1)
|
||||
copy_pixel_shader = PixelShaderCache::GetDepthResolveProgram();
|
||||
else
|
||||
copy_pixel_shader = PixelShaderCache::GetColorCopyProgram(true);
|
||||
|
||||
// Draw a quad to grab the texel we want to read.
|
||||
D3D::context->OMSetRenderTargets(1, &read_tex->GetRTV(), nullptr);
|
||||
D3D::drawShadedTexQuad(source_tex->GetSRV(), &RectToLock, Renderer::GetTargetWidth(),
|
||||
Renderer::GetTargetHeight(), copy_pixel_shader,
|
||||
VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout());
|
||||
|
||||
// Restore expected game state.
|
||||
RestoreAPIState();
|
||||
|
||||
// Copy the pixel from the renderable to cpu-readable buffer.
|
||||
D3D11_BOX box = CD3D11_BOX(0, 0, 0, 1, 1, 1);
|
||||
D3D::context->CopySubresourceRegion(staging_tex, 0, 0, 0, 0, read_tex->GetTex(), 0, &box);
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
CHECK(D3D::context->Map(staging_tex, 0, D3D11_MAP_READ, 0, &map) == S_OK,
|
||||
"Map staging buffer failed");
|
||||
|
||||
// Convert the framebuffer data to the format the game is expecting to receive.
|
||||
u32 ret;
|
||||
if (type == EFBAccessType::PeekColor)
|
||||
{
|
||||
u32 val;
|
||||
memcpy(&val, map.pData, sizeof(val));
|
||||
|
||||
// our buffers are RGBA, yet a BGRA value is expected
|
||||
val = ((val & 0xFF00FF00) | ((val >> 16) & 0xFF) | ((val << 16) & 0xFF0000));
|
||||
|
||||
// check what to do with the alpha channel (GX_PokeAlphaRead)
|
||||
PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode();
|
||||
|
||||
if (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24)
|
||||
{
|
||||
val = RGBA8ToRGBA6ToRGBA8(val);
|
||||
}
|
||||
else if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16)
|
||||
{
|
||||
val = RGBA8ToRGB565ToRGBA8(val);
|
||||
}
|
||||
if (bpmem.zcontrol.pixel_format != PEControl::RGBA6_Z24)
|
||||
{
|
||||
val |= 0xFF000000;
|
||||
}
|
||||
|
||||
if (alpha_read_mode.ReadMode == 2)
|
||||
ret = val; // GX_READ_NONE
|
||||
else if (alpha_read_mode.ReadMode == 1)
|
||||
ret = (val | 0xFF000000); // GX_READ_FF
|
||||
else /*if(alpha_read_mode.ReadMode == 0)*/
|
||||
ret = (val & 0x00FFFFFF); // GX_READ_00
|
||||
}
|
||||
else // type == EFBAccessType::PeekZ
|
||||
{
|
||||
float val;
|
||||
memcpy(&val, map.pData, sizeof(val));
|
||||
|
||||
// depth buffer is inverted in the d3d backend
|
||||
val = 1.0f - val;
|
||||
|
||||
if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16)
|
||||
{
|
||||
// if Z is in 16 bit format you must return a 16 bit integer
|
||||
ret = MathUtil::Clamp<u32>(static_cast<u32>(val * 65536.0f), 0, 0xFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = MathUtil::Clamp<u32>(static_cast<u32>(val * 16777216.0f), 0, 0xFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
D3D::context->Unmap(staging_tex, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points)
|
||||
{
|
||||
ResetAPIState();
|
||||
|
||||
if (type == EFBAccessType::PokeColor)
|
||||
{
|
||||
D3D11_VIEWPORT vp =
|
||||
CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight());
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
}
|
||||
else // if (type == EFBAccessType::PokeZ)
|
||||
{
|
||||
D3D::stateman->SetBlendState(m_clear_blend_states[3]);
|
||||
D3D::stateman->SetDepthState(m_clear_depth_states[1]);
|
||||
|
||||
D3D11_VIEWPORT vp =
|
||||
CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight());
|
||||
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
}
|
||||
|
||||
D3D::DrawEFBPokeQuads(type, points, num_points);
|
||||
|
||||
RestoreAPIState();
|
||||
}
|
||||
|
||||
void Renderer::SetViewport(float x, float y, float width, float height, float near_depth,
|
||||
float far_depth)
|
||||
{
|
||||
// In D3D, the viewport rectangle must fit within the render target.
|
||||
D3D11_VIEWPORT vp;
|
||||
vp.TopLeftX = MathUtil::Clamp(x, 0.0f, static_cast<float>(m_current_framebuffer_width - 1));
|
||||
vp.TopLeftY = MathUtil::Clamp(y, 0.0f, static_cast<float>(m_current_framebuffer_height - 1));
|
||||
vp.Width =
|
||||
MathUtil::Clamp(width, 1.0f, static_cast<float>(m_current_framebuffer_width) - vp.TopLeftX);
|
||||
vp.Height =
|
||||
MathUtil::Clamp(height, 1.0f, static_cast<float>(m_current_framebuffer_height) - vp.TopLeftY);
|
||||
vp.MinDepth = near_depth;
|
||||
vp.MaxDepth = far_depth;
|
||||
// TODO: Move to stateman
|
||||
const CD3D11_VIEWPORT vp(x, y, width, height, near_depth, far_depth);
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
}
|
||||
|
||||
|
@ -478,89 +186,19 @@ void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
|
|||
D3D::context->DrawIndexed(num_indices, base_index, base_vertex);
|
||||
}
|
||||
|
||||
void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
|
||||
u32 color, u32 z)
|
||||
void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groups_x, u32 groups_y,
|
||||
u32 groups_z)
|
||||
{
|
||||
ResetAPIState();
|
||||
|
||||
if (colorEnable && alphaEnable)
|
||||
D3D::stateman->SetBlendState(m_clear_blend_states[0]);
|
||||
else if (colorEnable)
|
||||
D3D::stateman->SetBlendState(m_clear_blend_states[1]);
|
||||
else if (alphaEnable)
|
||||
D3D::stateman->SetBlendState(m_clear_blend_states[2]);
|
||||
else
|
||||
D3D::stateman->SetBlendState(m_clear_blend_states[3]);
|
||||
|
||||
// TODO: Should we enable Z testing here?
|
||||
// if (!bpmem.zmode.testenable) D3D::stateman->PushDepthState(s_clear_depth_states[0]);
|
||||
// else
|
||||
if (zEnable)
|
||||
D3D::stateman->SetDepthState(m_clear_depth_states[1]);
|
||||
else /*if (!zEnable)*/
|
||||
D3D::stateman->SetDepthState(m_clear_depth_states[2]);
|
||||
|
||||
// Update the view port for clearing the picture
|
||||
TargetRectangle targetRc = Renderer::ConvertEFBRectangle(rc);
|
||||
D3D11_VIEWPORT vp =
|
||||
CD3D11_VIEWPORT((float)targetRc.left, (float)targetRc.top, (float)targetRc.GetWidth(),
|
||||
(float)targetRc.GetHeight(), 0.f, 1.f);
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
FramebufferManager::SetIntegerEFBRenderTarget(false);
|
||||
|
||||
// Color is passed in bgra mode so we need to convert it to rgba
|
||||
u32 rgbaColor = (color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000);
|
||||
D3D::drawClearQuad(rgbaColor, 1.0f - (z & 0xFFFFFF) / 16777216.0f);
|
||||
|
||||
RestoreAPIState();
|
||||
}
|
||||
|
||||
void Renderer::ReinterpretPixelData(unsigned int convtype)
|
||||
{
|
||||
// TODO: MSAA support..
|
||||
D3D11_RECT source = CD3D11_RECT(0, 0, GetTargetWidth(), GetTargetHeight());
|
||||
|
||||
ID3D11PixelShader* pixel_shader;
|
||||
if (convtype == 0)
|
||||
pixel_shader = PixelShaderCache::ReinterpRGB8ToRGBA6(true);
|
||||
else if (convtype == 2)
|
||||
pixel_shader = PixelShaderCache::ReinterpRGBA6ToRGB8(true);
|
||||
else
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Trying to reinterpret pixel data with unsupported conversion type %d",
|
||||
convtype);
|
||||
return;
|
||||
}
|
||||
|
||||
// convert data and set the target texture as our new EFB
|
||||
ResetAPIState();
|
||||
|
||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, static_cast<float>(GetTargetWidth()),
|
||||
static_cast<float>(GetTargetHeight()));
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
|
||||
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTempTexture()->GetRTV(),
|
||||
nullptr);
|
||||
D3D::SetPointCopySampler();
|
||||
D3D::drawShadedTexQuad(
|
||||
FramebufferManager::GetEFBColorTexture()->GetSRV(), &source, GetTargetWidth(),
|
||||
GetTargetHeight(), pixel_shader, VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader());
|
||||
|
||||
FramebufferManager::SwapReinterpretTexture();
|
||||
RestoreAPIState();
|
||||
D3D::stateman->SetComputeShader(static_cast<const DXShader*>(shader)->GetD3DComputeShader());
|
||||
D3D::stateman->SyncComputeBindings();
|
||||
D3D::context->Dispatch(groups_x, groups_y, groups_z);
|
||||
}
|
||||
|
||||
void Renderer::BindBackbuffer(const ClearColor& clear_color)
|
||||
{
|
||||
CheckForSurfaceChange();
|
||||
CheckForSurfaceResize();
|
||||
|
||||
D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr);
|
||||
D3D::context->ClearRenderTargetView(D3D::GetBackBuffer()->GetRTV(), clear_color.data());
|
||||
m_current_framebuffer = nullptr;
|
||||
m_current_framebuffer_width = m_backbuffer_width;
|
||||
m_current_framebuffer_height = m_backbuffer_height;
|
||||
SetAndClearFramebuffer(D3D::GetSwapChainFramebuffer(), clear_color);
|
||||
}
|
||||
|
||||
void Renderer::PresentBackbuffer()
|
||||
|
@ -570,14 +208,6 @@ void Renderer::PresentBackbuffer()
|
|||
|
||||
void Renderer::OnConfigChanged(u32 bits)
|
||||
{
|
||||
// Resize the back buffers NOW to avoid flickering
|
||||
if (bits & (CONFIG_CHANGE_BIT_TARGET_SIZE | CONFIG_CHANGE_BIT_MULTISAMPLES |
|
||||
CONFIG_CHANGE_BIT_STEREO_MODE))
|
||||
{
|
||||
PixelShaderCache::InvalidateMSAAShaders();
|
||||
g_framebuffer_manager.reset();
|
||||
g_framebuffer_manager = std::make_unique<FramebufferManager>(m_target_width, m_target_height);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::CheckForSurfaceChange()
|
||||
|
@ -585,8 +215,8 @@ void Renderer::CheckForSurfaceChange()
|
|||
if (!m_surface_changed.TestAndClear())
|
||||
return;
|
||||
|
||||
SAFE_RELEASE(m_screenshot_texture);
|
||||
SAFE_RELEASE(m_3d_vision_texture);
|
||||
m_3d_vision_framebuffer.reset();
|
||||
m_3d_vision_texture.reset();
|
||||
|
||||
D3D::Reset(reinterpret_cast<HWND>(m_new_surface_handle));
|
||||
m_new_surface_handle = nullptr;
|
||||
|
@ -601,8 +231,9 @@ void Renderer::CheckForSurfaceResize()
|
|||
if (!m_surface_resized.TestAndClear() && !exclusive_fullscreen_changed)
|
||||
return;
|
||||
|
||||
SAFE_RELEASE(m_screenshot_texture);
|
||||
SAFE_RELEASE(m_3d_vision_texture);
|
||||
m_3d_vision_framebuffer.reset();
|
||||
m_3d_vision_texture.reset();
|
||||
|
||||
m_last_fullscreen_state = fullscreen_state;
|
||||
if (D3D::swapchain)
|
||||
D3D::ResizeSwapChain();
|
||||
|
@ -625,43 +256,38 @@ void Renderer::UpdateBackbufferSize()
|
|||
}
|
||||
}
|
||||
|
||||
// ALWAYS call RestoreAPIState for each ResetAPIState call you're doing
|
||||
void Renderer::ResetAPIState()
|
||||
void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
|
||||
{
|
||||
D3D::stateman->SetBlendState(m_reset_blend_state);
|
||||
D3D::stateman->SetDepthState(m_reset_depth_state);
|
||||
D3D::stateman->SetRasterizerState(m_reset_rast_state);
|
||||
}
|
||||
if (m_current_framebuffer == framebuffer)
|
||||
return;
|
||||
|
||||
void Renderer::RestoreAPIState()
|
||||
{
|
||||
// Gets us back into a more game-like state.
|
||||
m_current_framebuffer = nullptr;
|
||||
m_current_framebuffer_width = m_target_width;
|
||||
m_current_framebuffer_height = m_target_height;
|
||||
FramebufferManager::BindEFBRenderTarget();
|
||||
BPFunctions::SetViewport();
|
||||
BPFunctions::SetScissor();
|
||||
}
|
||||
// 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();
|
||||
}
|
||||
|
||||
void Renderer::SetFramebuffer(const AbstractFramebuffer* framebuffer)
|
||||
{
|
||||
const DXFramebuffer* fb = static_cast<const DXFramebuffer*>(framebuffer);
|
||||
D3D::context->OMSetRenderTargets(fb->GetNumRTVs(), fb->GetRTVArray(), fb->GetDSV());
|
||||
D3D::stateman->SetFramebuffer(fb);
|
||||
m_current_framebuffer = fb;
|
||||
m_current_framebuffer_width = fb->GetWidth();
|
||||
m_current_framebuffer_height = fb->GetHeight();
|
||||
}
|
||||
|
||||
void Renderer::SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer)
|
||||
void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
|
||||
{
|
||||
SetFramebuffer(framebuffer);
|
||||
}
|
||||
|
||||
void Renderer::SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
|
||||
void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
|
||||
const ClearColor& color_value, float depth_value)
|
||||
{
|
||||
SetFramebuffer(framebuffer);
|
||||
D3D::stateman->Apply();
|
||||
|
||||
if (framebuffer->GetColorFormat() != AbstractTextureFormat::Undefined)
|
||||
{
|
||||
D3D::context->ClearRenderTargetView(
|
||||
|
@ -676,9 +302,8 @@ void Renderer::SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
|
|||
|
||||
void Renderer::SetTexture(u32 index, const AbstractTexture* texture)
|
||||
{
|
||||
D3D::stateman->SetTexture(
|
||||
index,
|
||||
texture ? static_cast<const DXTexture*>(texture)->GetRawTexIdentifier()->GetSRV() : nullptr);
|
||||
D3D::stateman->SetTexture(index, texture ? static_cast<const DXTexture*>(texture)->GetD3DSRV() :
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void Renderer::SetSamplerState(u32 index, const SamplerState& state)
|
||||
|
@ -686,15 +311,15 @@ void Renderer::SetSamplerState(u32 index, const SamplerState& state)
|
|||
D3D::stateman->SetSampler(index, m_state_cache.Get(state));
|
||||
}
|
||||
|
||||
void Renderer::UnbindTexture(const AbstractTexture* texture)
|
||||
void Renderer::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
|
||||
{
|
||||
D3D::stateman->UnsetTexture(
|
||||
static_cast<const DXTexture*>(texture)->GetRawTexIdentifier()->GetSRV());
|
||||
D3D::stateman->SetComputeUAV(texture ? static_cast<DXTexture*>(texture)->GetD3DUAV() : nullptr);
|
||||
}
|
||||
|
||||
void Renderer::SetInterlacingMode()
|
||||
void Renderer::UnbindTexture(const AbstractTexture* texture)
|
||||
{
|
||||
// TODO
|
||||
if (D3D::stateman->UnsetTexture(static_cast<const DXTexture*>(texture)->GetD3DSRV()) != 0)
|
||||
D3D::stateman->ApplyTextures();
|
||||
}
|
||||
|
||||
u16 Renderer::BBoxRead(int index)
|
||||
|
@ -736,93 +361,43 @@ void Renderer::BBoxWrite(int index, u16 _value)
|
|||
BBox::Set(index, value);
|
||||
}
|
||||
|
||||
void Renderer::Flush()
|
||||
{
|
||||
D3D::context->Flush();
|
||||
}
|
||||
|
||||
void Renderer::WaitForGPUIdle()
|
||||
{
|
||||
// There is no glFinish() equivalent in D3D.
|
||||
D3D::context->Flush();
|
||||
}
|
||||
|
||||
void Renderer::RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc)
|
||||
{
|
||||
const CD3D11_RECT source_rc(rc.left, rc.top, rc.right, rc.bottom);
|
||||
const TargetRectangle target_rc = GetTargetRectangle();
|
||||
if (g_ActiveConfig.stereo_mode != StereoMode::Nvidia3DVision)
|
||||
return ::Renderer::RenderXFBToScreen(texture, rc);
|
||||
|
||||
// activate linear filtering for the buffer copies
|
||||
D3D::SetLinearCopySampler();
|
||||
if (!m_3d_vision_texture)
|
||||
Create3DVisionTexture(m_backbuffer_width, m_backbuffer_height);
|
||||
|
||||
if (g_ActiveConfig.stereo_mode == StereoMode::SBS ||
|
||||
g_ActiveConfig.stereo_mode == StereoMode::TAB)
|
||||
{
|
||||
TargetRectangle left_rc, right_rc;
|
||||
std::tie(left_rc, right_rc) = ConvertStereoRectangle(target_rc);
|
||||
// Render to staging texture which is double the width of the backbuffer
|
||||
SetAndClearFramebuffer(m_3d_vision_framebuffer.get());
|
||||
|
||||
SetViewport(static_cast<float>(left_rc.left), static_cast<float>(left_rc.top),
|
||||
static_cast<float>(left_rc.GetWidth()), static_cast<float>(right_rc.GetHeight()),
|
||||
0.0f, 1.0f);
|
||||
D3D::drawShadedTexQuad(static_cast<const DXTexture*>(texture)->GetRawTexIdentifier()->GetSRV(),
|
||||
&source_rc, texture->GetWidth(), texture->GetHeight(),
|
||||
PixelShaderCache::GetColorCopyProgram(false),
|
||||
VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), nullptr, 0);
|
||||
const auto target_rc = GetTargetRectangle();
|
||||
m_post_processor->BlitFromTexture(target_rc, rc, texture, 0);
|
||||
m_post_processor->BlitFromTexture(
|
||||
MathUtil::Rectangle<int>(target_rc.left + m_backbuffer_width, target_rc.top,
|
||||
target_rc.right + m_backbuffer_width, target_rc.bottom),
|
||||
rc, texture, 1);
|
||||
|
||||
SetViewport(static_cast<float>(right_rc.left), static_cast<float>(right_rc.top),
|
||||
static_cast<float>(right_rc.GetWidth()), static_cast<float>(right_rc.GetHeight()),
|
||||
0.0f, 1.0f);
|
||||
D3D::drawShadedTexQuad(static_cast<const DXTexture*>(texture)->GetRawTexIdentifier()->GetSRV(),
|
||||
&source_rc, texture->GetWidth(), texture->GetHeight(),
|
||||
PixelShaderCache::GetColorCopyProgram(false),
|
||||
VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), nullptr, 1);
|
||||
}
|
||||
else if (g_ActiveConfig.stereo_mode == StereoMode::Nvidia3DVision)
|
||||
{
|
||||
if (!m_3d_vision_texture)
|
||||
Create3DVisionTexture(m_backbuffer_width, m_backbuffer_height);
|
||||
// Copy the left eye to the backbuffer, if Nvidia 3D Vision is enabled it should
|
||||
// recognize the signature and automatically include the right eye frame.
|
||||
const CD3D11_BOX box(0, 0, 0, m_backbuffer_width, m_backbuffer_height, 1);
|
||||
D3D::context->CopySubresourceRegion(D3D::GetSwapChainTexture()->GetD3DTexture(), 0, 0, 0, 0,
|
||||
m_3d_vision_texture->GetD3DTexture(), 0, &box);
|
||||
|
||||
const CD3D11_VIEWPORT left_vp(
|
||||
static_cast<float>(target_rc.left), static_cast<float>(target_rc.top),
|
||||
static_cast<float>(target_rc.GetWidth()), static_cast<float>(target_rc.GetHeight()));
|
||||
const CD3D11_VIEWPORT right_vp(
|
||||
static_cast<float>(target_rc.left + m_backbuffer_width), static_cast<float>(target_rc.top),
|
||||
static_cast<float>(target_rc.GetWidth()), static_cast<float>(target_rc.GetHeight()));
|
||||
|
||||
// Render to staging texture which is double the width of the backbuffer
|
||||
D3D::context->OMSetRenderTargets(1, &m_3d_vision_texture->GetRTV(), nullptr);
|
||||
|
||||
D3D::context->RSSetViewports(1, &left_vp);
|
||||
D3D::drawShadedTexQuad(static_cast<const DXTexture*>(texture)->GetRawTexIdentifier()->GetSRV(),
|
||||
&source_rc, texture->GetWidth(), texture->GetHeight(),
|
||||
PixelShaderCache::GetColorCopyProgram(false),
|
||||
VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), nullptr, 0);
|
||||
|
||||
D3D::context->RSSetViewports(1, &right_vp);
|
||||
D3D::drawShadedTexQuad(static_cast<const DXTexture*>(texture)->GetRawTexIdentifier()->GetSRV(),
|
||||
&source_rc, texture->GetWidth(), texture->GetHeight(),
|
||||
PixelShaderCache::GetColorCopyProgram(false),
|
||||
VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), nullptr, 1);
|
||||
|
||||
// Copy the left eye to the backbuffer, if Nvidia 3D Vision is enabled it should
|
||||
// recognize the signature and automatically include the right eye frame.
|
||||
const CD3D11_BOX box(0, 0, 0, m_backbuffer_width, m_backbuffer_height, 1);
|
||||
D3D::context->CopySubresourceRegion(D3D::GetBackBuffer()->GetTex(), 0, 0, 0, 0,
|
||||
m_3d_vision_texture->GetTex(), 0, &box);
|
||||
|
||||
// Restore render target to backbuffer
|
||||
D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetViewport(static_cast<float>(target_rc.left), static_cast<float>(target_rc.top),
|
||||
static_cast<float>(target_rc.GetWidth()), static_cast<float>(target_rc.GetHeight()),
|
||||
0.0f, 1.0f);
|
||||
|
||||
ID3D11PixelShader* pixelShader = (g_Config.stereo_mode == StereoMode::Anaglyph) ?
|
||||
PixelShaderCache::GetAnaglyphProgram() :
|
||||
PixelShaderCache::GetColorCopyProgram(false);
|
||||
ID3D11GeometryShader* geomShader = (g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer) ?
|
||||
GeometryShaderCache::GetCopyGeometryShader() :
|
||||
nullptr;
|
||||
D3D::drawShadedTexQuad(static_cast<const DXTexture*>(texture)->GetRawTexIdentifier()->GetSRV(),
|
||||
&source_rc, texture->GetWidth(), texture->GetHeight(), pixelShader,
|
||||
VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), geomShader);
|
||||
}
|
||||
// Restore render target to backbuffer
|
||||
SetFramebuffer(D3D::GetSwapChainFramebuffer());
|
||||
}
|
||||
|
||||
void Renderer::SetFullscreen(bool enable_fullscreen)
|
||||
|
|
|
@ -9,11 +9,10 @@
|
|||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
|
||||
enum class EFBAccessType;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
class D3DTexture2D;
|
||||
class DXTexture;
|
||||
class DXFramebuffer;
|
||||
|
||||
class Renderer : public ::Renderer
|
||||
{
|
||||
|
@ -32,53 +31,43 @@ public:
|
|||
size_t length) override;
|
||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||
size_t length) override;
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
|
||||
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config) override;
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment) override;
|
||||
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
|
||||
|
||||
void SetPipeline(const AbstractPipeline* pipeline) override;
|
||||
void SetFramebuffer(const AbstractFramebuffer* framebuffer) override;
|
||||
void SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer) override;
|
||||
void SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
|
||||
const ClearColor& color_value = {},
|
||||
void SetFramebuffer(AbstractFramebuffer* framebuffer) override;
|
||||
void SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) override;
|
||||
void SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value = {},
|
||||
float depth_value = 0.0f) override;
|
||||
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
|
||||
void SetTexture(u32 index, const AbstractTexture* texture) override;
|
||||
void SetSamplerState(u32 index, const SamplerState& state) override;
|
||||
void SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) override;
|
||||
void UnbindTexture(const AbstractTexture* texture) override;
|
||||
void SetInterlacingMode() override;
|
||||
void SetViewport(float x, float y, float width, float height, float near_depth,
|
||||
float far_depth) override;
|
||||
void Draw(u32 base_vertex, u32 num_vertices) override;
|
||||
void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override;
|
||||
void DispatchComputeShader(const AbstractShader* shader, u32 groups_x, u32 groups_y,
|
||||
u32 groups_z) override;
|
||||
void BindBackbuffer(const ClearColor& clear_color = {}) override;
|
||||
void PresentBackbuffer() override;
|
||||
void SetFullscreen(bool enable_fullscreen) override;
|
||||
bool IsFullscreen() const override;
|
||||
|
||||
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
|
||||
void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override;
|
||||
|
||||
u16 BBoxRead(int index) override;
|
||||
void BBoxWrite(int index, u16 value) override;
|
||||
|
||||
void ResetAPIState() override;
|
||||
void RestoreAPIState() override;
|
||||
|
||||
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
|
||||
void Flush() override;
|
||||
void WaitForGPUIdle() override;
|
||||
|
||||
void RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc) override;
|
||||
void OnConfigChanged(u32 bits) override;
|
||||
|
||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
|
||||
u32 color, u32 z) override;
|
||||
|
||||
void ReinterpretPixelData(unsigned int convtype) override;
|
||||
|
||||
private:
|
||||
void SetupDeviceObjects();
|
||||
void TeardownDeviceObjects();
|
||||
void Create3DVisionTexture(int width, int height);
|
||||
void CheckForSurfaceChange();
|
||||
void CheckForSurfaceResize();
|
||||
|
@ -86,15 +75,9 @@ private:
|
|||
|
||||
StateCache m_state_cache;
|
||||
|
||||
std::array<ID3D11BlendState*, 4> m_clear_blend_states{};
|
||||
std::array<ID3D11DepthStencilState*, 3> m_clear_depth_states{};
|
||||
ID3D11BlendState* m_reset_blend_state = nullptr;
|
||||
ID3D11DepthStencilState* m_reset_depth_state = nullptr;
|
||||
ID3D11RasterizerState* m_reset_rast_state = nullptr;
|
||||
|
||||
ID3D11Texture2D* m_screenshot_texture = nullptr;
|
||||
D3DTexture2D* m_3d_vision_texture = nullptr;
|
||||
std::unique_ptr<DXTexture> m_3d_vision_texture;
|
||||
std::unique_ptr<DXFramebuffer> m_3d_vision_framebuffer;
|
||||
|
||||
bool m_last_fullscreen_state = false;
|
||||
};
|
||||
}
|
||||
} // namespace DX11
|
||||
|
|
|
@ -1,318 +0,0 @@
|
|||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/D3D/TextureCache.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DShader.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/D3DTexture.h"
|
||||
#include "VideoBackends/D3D/D3DUtil.h"
|
||||
#include "VideoBackends/D3D/DXTexture.h"
|
||||
#include "VideoBackends/D3D/FramebufferManager.h"
|
||||
#include "VideoBackends/D3D/GeometryShaderCache.h"
|
||||
#include "VideoBackends/D3D/PSTextureEncoder.h"
|
||||
#include "VideoBackends/D3D/PixelShaderCache.h"
|
||||
#include "VideoBackends/D3D/VertexShaderCache.h"
|
||||
|
||||
#include "VideoCommon/ImageWrite.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoCommon/TextureConfig.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
static std::unique_ptr<PSTextureEncoder> g_encoder;
|
||||
|
||||
void TextureCache::CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams& params,
|
||||
u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
|
||||
const EFBRectangle& src_rect, bool scale_by_half, float y_scale,
|
||||
float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients)
|
||||
{
|
||||
g_encoder->Encode(dst, params, native_width, bytes_per_row, num_blocks_y, memory_stride, src_rect,
|
||||
scale_by_half, y_scale, gamma, clamp_top, clamp_bottom, filter_coefficients);
|
||||
}
|
||||
|
||||
const char palette_shader[] =
|
||||
R"HLSL(
|
||||
sampler samp0 : register(s0);
|
||||
Texture2DArray Tex0 : register(t0);
|
||||
Buffer<uint> Tex1 : register(t1);
|
||||
uniform float Multiply;
|
||||
|
||||
uint Convert3To8(uint v)
|
||||
{
|
||||
// Swizzle bits: 00000123 -> 12312312
|
||||
return (v << 5) | (v << 2) | (v >> 1);
|
||||
}
|
||||
|
||||
uint Convert4To8(uint v)
|
||||
{
|
||||
// Swizzle bits: 00001234 -> 12341234
|
||||
return (v << 4) | v;
|
||||
}
|
||||
|
||||
uint Convert5To8(uint v)
|
||||
{
|
||||
// Swizzle bits: 00012345 -> 12345123
|
||||
return (v << 3) | (v >> 2);
|
||||
}
|
||||
|
||||
uint Convert6To8(uint v)
|
||||
{
|
||||
// Swizzle bits: 00123456 -> 12345612
|
||||
return (v << 2) | (v >> 4);
|
||||
}
|
||||
|
||||
float4 DecodePixel_RGB5A3(uint val)
|
||||
{
|
||||
int r,g,b,a;
|
||||
if ((val&0x8000))
|
||||
{
|
||||
r=Convert5To8((val>>10) & 0x1f);
|
||||
g=Convert5To8((val>>5 ) & 0x1f);
|
||||
b=Convert5To8((val ) & 0x1f);
|
||||
a=0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
a=Convert3To8((val>>12) & 0x7);
|
||||
r=Convert4To8((val>>8 ) & 0xf);
|
||||
g=Convert4To8((val>>4 ) & 0xf);
|
||||
b=Convert4To8((val ) & 0xf);
|
||||
}
|
||||
return float4(r, g, b, a) / 255;
|
||||
}
|
||||
|
||||
float4 DecodePixel_RGB565(uint val)
|
||||
{
|
||||
int r, g, b, a;
|
||||
r = Convert5To8((val >> 11) & 0x1f);
|
||||
g = Convert6To8((val >> 5) & 0x3f);
|
||||
b = Convert5To8((val) & 0x1f);
|
||||
a = 0xFF;
|
||||
return float4(r, g, b, a) / 255;
|
||||
}
|
||||
|
||||
float4 DecodePixel_IA8(uint val)
|
||||
{
|
||||
int i = val & 0xFF;
|
||||
int a = val >> 8;
|
||||
return float4(i, i, i, a) / 255;
|
||||
}
|
||||
|
||||
void main(
|
||||
out float4 ocol0 : SV_Target,
|
||||
in float4 pos : SV_Position,
|
||||
in float3 uv0 : TEXCOORD0)
|
||||
{
|
||||
uint src = round(Tex0.Sample(samp0,uv0) * Multiply).r;
|
||||
src = Tex1.Load(src);
|
||||
src = ((src << 8) & 0xFF00) | (src >> 8);
|
||||
ocol0 = DECODE(src);
|
||||
}
|
||||
)HLSL";
|
||||
|
||||
void TextureCache::ConvertTexture(TCacheEntry* destination, TCacheEntry* source,
|
||||
const void* palette, TLUTFormat format)
|
||||
{
|
||||
DXTexture* source_texture = static_cast<DXTexture*>(source->texture.get());
|
||||
DXTexture* destination_texture = static_cast<DXTexture*>(destination->texture.get());
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
// stretch picture with increased internal resolution
|
||||
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, static_cast<float>(source->GetWidth()),
|
||||
static_cast<float>(source->GetHeight()));
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
|
||||
D3D11_BOX box{0, 0, 0, 512, 1, 1};
|
||||
D3D::context->UpdateSubresource(palette_buf, 0, &box, palette, 0, 0);
|
||||
|
||||
D3D::stateman->SetTexture(1, palette_buf_srv);
|
||||
|
||||
// TODO: Add support for C14X2 format. (Different multiplier, more palette entries.)
|
||||
float params[8] = {source->format == TextureFormat::I4 ? 15.f : 255.f};
|
||||
D3D::context->UpdateSubresource(uniform_buffer, 0, nullptr, ¶ms, 0, 0);
|
||||
D3D::stateman->SetPixelConstants(uniform_buffer);
|
||||
|
||||
const D3D11_RECT sourcerect = CD3D11_RECT(0, 0, source->GetWidth(), source->GetHeight());
|
||||
|
||||
D3D::SetPointCopySampler();
|
||||
|
||||
// Make sure we don't draw with the texture set as both a source and target.
|
||||
// (This can happen because we don't unbind textures when we free them.)
|
||||
D3D::stateman->UnsetTexture(destination_texture->GetRawTexIdentifier()->GetSRV());
|
||||
D3D::stateman->Apply();
|
||||
|
||||
D3D::context->OMSetRenderTargets(1, &destination_texture->GetRawTexIdentifier()->GetRTV(),
|
||||
nullptr);
|
||||
|
||||
// Create texture copy
|
||||
D3D::drawShadedTexQuad(
|
||||
source_texture->GetRawTexIdentifier()->GetSRV(), &sourcerect, source->GetWidth(),
|
||||
source->GetHeight(), palette_pixel_shader[static_cast<int>(format)],
|
||||
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(),
|
||||
GeometryShaderCache::GetCopyGeometryShader());
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
ID3D11PixelShader* GetConvertShader(const char* Type)
|
||||
{
|
||||
std::string shader = "#define DECODE DecodePixel_";
|
||||
shader.append(Type);
|
||||
shader.append("\n");
|
||||
shader.append(palette_shader);
|
||||
return D3D::CompileAndCreatePixelShader(shader);
|
||||
}
|
||||
|
||||
TextureCache::TextureCache()
|
||||
{
|
||||
// FIXME: Is it safe here?
|
||||
g_encoder = std::make_unique<PSTextureEncoder>();
|
||||
g_encoder->Init();
|
||||
|
||||
palette_buf = nullptr;
|
||||
palette_buf_srv = nullptr;
|
||||
uniform_buffer = nullptr;
|
||||
palette_pixel_shader[static_cast<int>(TLUTFormat::IA8)] = GetConvertShader("IA8");
|
||||
palette_pixel_shader[static_cast<int>(TLUTFormat::RGB565)] = GetConvertShader("RGB565");
|
||||
palette_pixel_shader[static_cast<int>(TLUTFormat::RGB5A3)] = GetConvertShader("RGB5A3");
|
||||
auto lutBd = CD3D11_BUFFER_DESC(sizeof(u16) * 256, D3D11_BIND_SHADER_RESOURCE);
|
||||
HRESULT hr = D3D::device->CreateBuffer(&lutBd, nullptr, &palette_buf);
|
||||
CHECK(SUCCEEDED(hr), "create palette decoder lut buffer");
|
||||
D3D::SetDebugObjectName(palette_buf, "texture decoder lut buffer");
|
||||
// TODO: C14X2 format.
|
||||
auto outlutUavDesc =
|
||||
CD3D11_SHADER_RESOURCE_VIEW_DESC(palette_buf, DXGI_FORMAT_R16_UINT, 0, 256, 0);
|
||||
hr = D3D::device->CreateShaderResourceView(palette_buf, &outlutUavDesc, &palette_buf_srv);
|
||||
CHECK(SUCCEEDED(hr), "create palette decoder lut srv");
|
||||
D3D::SetDebugObjectName(palette_buf_srv, "texture decoder lut srv");
|
||||
const D3D11_BUFFER_DESC cbdesc =
|
||||
CD3D11_BUFFER_DESC(sizeof(float) * 8, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT);
|
||||
hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &uniform_buffer);
|
||||
CHECK(SUCCEEDED(hr), "Create palette decoder constant buffer");
|
||||
D3D::SetDebugObjectName(uniform_buffer,
|
||||
"a constant buffer used in TextureCache::CopyRenderTargetToTexture");
|
||||
}
|
||||
|
||||
TextureCache::~TextureCache()
|
||||
{
|
||||
g_encoder->Shutdown();
|
||||
g_encoder.reset();
|
||||
|
||||
SAFE_RELEASE(palette_buf);
|
||||
SAFE_RELEASE(palette_buf_srv);
|
||||
SAFE_RELEASE(uniform_buffer);
|
||||
for (auto*& shader : palette_pixel_shader)
|
||||
SAFE_RELEASE(shader);
|
||||
for (auto& iter : m_efb_to_tex_pixel_shaders)
|
||||
SAFE_RELEASE(iter.second);
|
||||
}
|
||||
|
||||
void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
|
||||
const EFBRectangle& src_rect, bool scale_by_half,
|
||||
EFBCopyFormat dst_format, bool is_intensity, float gamma,
|
||||
bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients)
|
||||
{
|
||||
auto* destination_texture = static_cast<DXTexture*>(entry->texture.get());
|
||||
|
||||
bool multisampled = g_ActiveConfig.iMultisamples > 1;
|
||||
ID3D11ShaderResourceView* efb_tex_srv;
|
||||
if (multisampled)
|
||||
{
|
||||
efb_tex_srv = is_depth_copy ? FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() :
|
||||
FramebufferManager::GetResolvedEFBColorTexture()->GetSRV();
|
||||
}
|
||||
else
|
||||
{
|
||||
efb_tex_srv = is_depth_copy ? FramebufferManager::GetEFBDepthTexture()->GetSRV() :
|
||||
FramebufferManager::GetEFBColorTexture()->GetSRV();
|
||||
}
|
||||
|
||||
auto uid = TextureConversionShaderGen::GetShaderUid(dst_format, is_depth_copy, is_intensity,
|
||||
scale_by_half,
|
||||
NeedsCopyFilterInShader(filter_coefficients));
|
||||
ID3D11PixelShader* pixel_shader = GetEFBToTexPixelShader(uid);
|
||||
if (!pixel_shader)
|
||||
return;
|
||||
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
// stretch picture with increased internal resolution
|
||||
const D3D11_VIEWPORT vp =
|
||||
CD3D11_VIEWPORT(0.f, 0.f, static_cast<float>(destination_texture->GetConfig().width),
|
||||
static_cast<float>(destination_texture->GetConfig().height));
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
|
||||
const TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(src_rect);
|
||||
// TODO: try targetSource.asRECT();
|
||||
const D3D11_RECT sourcerect =
|
||||
CD3D11_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom);
|
||||
|
||||
// Use linear filtering if (bScaleByHalf), use point filtering otherwise
|
||||
if (scale_by_half)
|
||||
D3D::SetLinearCopySampler();
|
||||
else
|
||||
D3D::SetPointCopySampler();
|
||||
|
||||
struct PixelConstants
|
||||
{
|
||||
float filter_coefficients[3];
|
||||
float gamma_rcp;
|
||||
float clamp_top;
|
||||
float clamp_bottom;
|
||||
float pixel_height;
|
||||
u32 padding;
|
||||
};
|
||||
PixelConstants constants;
|
||||
for (size_t i = 0; i < filter_coefficients.size(); i++)
|
||||
constants.filter_coefficients[i] = filter_coefficients[i];
|
||||
constants.gamma_rcp = 1.0f / gamma;
|
||||
constants.clamp_top = clamp_top ? src_rect.top / float(EFB_HEIGHT) : 0.0f;
|
||||
constants.clamp_bottom = clamp_bottom ? src_rect.bottom / float(EFB_HEIGHT) : 1.0f;
|
||||
constants.pixel_height =
|
||||
g_ActiveConfig.bCopyEFBScaled ? 1.0f / g_renderer->GetTargetHeight() : 1.0f / EFB_HEIGHT;
|
||||
constants.padding = 0;
|
||||
D3D::context->UpdateSubresource(uniform_buffer, 0, nullptr, &constants, 0, 0);
|
||||
D3D::stateman->SetPixelConstants(uniform_buffer);
|
||||
|
||||
// Make sure we don't draw with the texture set as both a source and target.
|
||||
// (This can happen because we don't unbind textures when we free them.)
|
||||
D3D::stateman->UnsetTexture(destination_texture->GetRawTexIdentifier()->GetSRV());
|
||||
D3D::stateman->Apply();
|
||||
|
||||
D3D::context->OMSetRenderTargets(1, &destination_texture->GetRawTexIdentifier()->GetRTV(),
|
||||
nullptr);
|
||||
|
||||
// Create texture copy
|
||||
D3D::drawShadedTexQuad(
|
||||
efb_tex_srv, &sourcerect, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight(),
|
||||
pixel_shader, VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader());
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
ID3D11PixelShader*
|
||||
TextureCache::GetEFBToTexPixelShader(const TextureConversionShaderGen::TCShaderUid& uid)
|
||||
{
|
||||
auto iter = m_efb_to_tex_pixel_shaders.find(uid);
|
||||
if (iter != m_efb_to_tex_pixel_shaders.end())
|
||||
return iter->second;
|
||||
|
||||
ShaderCode code = TextureConversionShaderGen::GenerateShader(APIType::D3D, uid.GetUidData());
|
||||
ID3D11PixelShader* shader = D3D::CompileAndCreatePixelShader(code.GetBuffer());
|
||||
m_efb_to_tex_pixel_shaders.emplace(uid, shader);
|
||||
return shader;
|
||||
}
|
||||
} // namespace DX11
|
|
@ -1,49 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "VideoBackends/D3D/D3DTexture.h"
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
#include "VideoCommon/TextureConverterShaderGen.h"
|
||||
|
||||
class AbstractTexture;
|
||||
struct TextureConfig;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
class TextureCache : public TextureCacheBase
|
||||
{
|
||||
public:
|
||||
TextureCache();
|
||||
~TextureCache();
|
||||
|
||||
private:
|
||||
void ConvertTexture(TCacheEntry* destination, TCacheEntry* source, const void* palette,
|
||||
TLUTFormat format) override;
|
||||
|
||||
void CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams& params, u32 native_width,
|
||||
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override;
|
||||
|
||||
void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, EFBCopyFormat dst_format, bool is_intensity,
|
||||
float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override;
|
||||
|
||||
bool CompileShaders() override { return true; }
|
||||
void DeleteShaders() override {}
|
||||
ID3D11PixelShader* GetEFBToTexPixelShader(const TextureConversionShaderGen::TCShaderUid& uid);
|
||||
|
||||
ID3D11Buffer* palette_buf;
|
||||
ID3D11ShaderResourceView* palette_buf_srv;
|
||||
ID3D11Buffer* uniform_buffer;
|
||||
ID3D11PixelShader* palette_pixel_shader[3];
|
||||
|
||||
std::map<TextureConversionShaderGen::TCShaderUid, ID3D11PixelShader*> m_efb_to_tex_pixel_shaders;
|
||||
};
|
||||
}
|
|
@ -7,24 +7,19 @@
|
|||
#include <d3d11.h>
|
||||
|
||||
#include "Common/Align.h"
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
#include "VideoBackends/D3D/BoundingBox.h"
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/FramebufferManager.h"
|
||||
#include "VideoBackends/D3D/GeometryShaderCache.h"
|
||||
#include "VideoBackends/D3D/PixelShaderCache.h"
|
||||
#include "VideoBackends/D3D/Render.h"
|
||||
#include "VideoBackends/D3D/VertexShaderCache.h"
|
||||
|
||||
#include "VideoCommon/BoundingBox.h"
|
||||
#include "VideoCommon/Debugger.h"
|
||||
#include "VideoCommon/GeometryShaderManager.h"
|
||||
#include "VideoCommon/IndexGenerator.h"
|
||||
#include "VideoCommon/NativeVertexFormat.h"
|
||||
#include "VideoCommon/PixelShaderManager.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoCommon/Statistics.h"
|
||||
#include "VideoCommon/VertexLoaderManager.h"
|
||||
#include "VideoCommon/VertexShaderManager.h"
|
||||
|
@ -32,11 +27,6 @@
|
|||
|
||||
namespace DX11
|
||||
{
|
||||
// TODO: Find sensible values for these two
|
||||
const u32 MAX_IBUFFER_SIZE = VertexManager::MAXIBUFFERSIZE * sizeof(u16) * 8;
|
||||
const u32 MAX_VBUFFER_SIZE = VertexManager::MAXVBUFFERSIZE;
|
||||
const u32 MAX_BUFFER_SIZE = MAX_IBUFFER_SIZE + MAX_VBUFFER_SIZE;
|
||||
|
||||
static ID3D11Buffer* AllocateConstantBuffer(u32 size)
|
||||
{
|
||||
const u32 cbsize = Common::AlignUp(size, 16u); // must be a multiple of 16
|
||||
|
@ -59,71 +49,172 @@ static void UpdateConstantBuffer(ID3D11Buffer* const buffer, const void* data, u
|
|||
ADDSTAT(stats.thisFrame.bytesUniformStreamed, data_size);
|
||||
}
|
||||
|
||||
void VertexManager::CreateDeviceObjects()
|
||||
static ID3D11ShaderResourceView*
|
||||
CreateTexelBufferView(ID3D11Buffer* buffer, TexelBufferFormat format, DXGI_FORMAT srv_format)
|
||||
{
|
||||
D3D11_BUFFER_DESC bufdesc =
|
||||
CD3D11_BUFFER_DESC(MAX_BUFFER_SIZE, D3D11_BIND_INDEX_BUFFER | D3D11_BIND_VERTEX_BUFFER,
|
||||
D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
|
||||
ID3D11ShaderResourceView* srv;
|
||||
CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(buffer, srv_format, 0,
|
||||
VertexManager::TEXEL_STREAM_BUFFER_SIZE /
|
||||
VertexManager::GetTexelBufferElementSize(format));
|
||||
CHECK(SUCCEEDED(D3D::device->CreateShaderResourceView(buffer, &srv_desc, &srv)),
|
||||
"Create SRV for texel buffer");
|
||||
return srv;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_BUFFER_COUNT; i++)
|
||||
VertexManager::VertexManager() = default;
|
||||
|
||||
VertexManager::~VertexManager()
|
||||
{
|
||||
for (auto& srv_ptr : m_texel_buffer_views)
|
||||
SAFE_RELEASE(srv_ptr);
|
||||
SAFE_RELEASE(m_texel_buffer);
|
||||
SAFE_RELEASE(m_pixel_constant_buffer);
|
||||
SAFE_RELEASE(m_geometry_constant_buffer);
|
||||
SAFE_RELEASE(m_vertex_constant_buffer);
|
||||
for (auto& buffer : m_buffers)
|
||||
SAFE_RELEASE(buffer);
|
||||
}
|
||||
|
||||
bool VertexManager::Initialize()
|
||||
{
|
||||
if (!VertexManagerBase::Initialize())
|
||||
return false;
|
||||
|
||||
CD3D11_BUFFER_DESC bufdesc((VERTEX_STREAM_BUFFER_SIZE + INDEX_STREAM_BUFFER_SIZE) / BUFFER_COUNT,
|
||||
D3D11_BIND_INDEX_BUFFER | D3D11_BIND_VERTEX_BUFFER,
|
||||
D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
|
||||
|
||||
for (int i = 0; i < BUFFER_COUNT; i++)
|
||||
{
|
||||
m_buffers[i] = nullptr;
|
||||
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, nullptr, &m_buffers[i])),
|
||||
"Failed to create buffer.");
|
||||
D3D::SetDebugObjectName(m_buffers[i], "Buffer of VertexManager");
|
||||
}
|
||||
|
||||
m_buffer_cursor = MAX_BUFFER_SIZE;
|
||||
|
||||
m_vertex_constant_buffer = AllocateConstantBuffer(sizeof(VertexShaderConstants));
|
||||
m_geometry_constant_buffer = AllocateConstantBuffer(sizeof(GeometryShaderConstants));
|
||||
m_pixel_constant_buffer = AllocateConstantBuffer(sizeof(PixelShaderConstants));
|
||||
}
|
||||
if (!m_vertex_constant_buffer || !m_geometry_constant_buffer || !m_pixel_constant_buffer)
|
||||
return false;
|
||||
|
||||
void VertexManager::DestroyDeviceObjects()
|
||||
{
|
||||
SAFE_RELEASE(m_pixel_constant_buffer);
|
||||
SAFE_RELEASE(m_geometry_constant_buffer);
|
||||
SAFE_RELEASE(m_vertex_constant_buffer);
|
||||
for (int i = 0; i < MAX_BUFFER_COUNT; i++)
|
||||
CD3D11_BUFFER_DESC texel_buf_desc(TEXEL_STREAM_BUFFER_SIZE, D3D11_BIND_SHADER_RESOURCE,
|
||||
D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
|
||||
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&texel_buf_desc, nullptr, &m_texel_buffer)),
|
||||
"Creating texel buffer failed");
|
||||
if (!m_texel_buffer)
|
||||
return false;
|
||||
|
||||
static constexpr std::array<std::pair<TexelBufferFormat, DXGI_FORMAT>, NUM_TEXEL_BUFFER_FORMATS>
|
||||
format_mapping = {{
|
||||
{TEXEL_BUFFER_FORMAT_R8_UINT, DXGI_FORMAT_R8_UINT},
|
||||
{TEXEL_BUFFER_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT},
|
||||
{TEXEL_BUFFER_FORMAT_RGBA8_UINT, DXGI_FORMAT_R8G8B8A8_UNORM},
|
||||
{TEXEL_BUFFER_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32_UINT},
|
||||
}};
|
||||
for (const auto& it : format_mapping)
|
||||
{
|
||||
SAFE_RELEASE(m_buffers[i]);
|
||||
m_texel_buffer_views[it.first] = CreateTexelBufferView(m_texel_buffer, it.first, it.second);
|
||||
if (!m_texel_buffer_views[it.first])
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
VertexManager::VertexManager()
|
||||
{
|
||||
m_staging_vertex_buffer.resize(MAXVBUFFERSIZE);
|
||||
|
||||
m_cur_buffer_pointer = m_base_buffer_pointer = &m_staging_vertex_buffer[0];
|
||||
m_end_buffer_pointer = m_base_buffer_pointer + m_staging_vertex_buffer.size();
|
||||
|
||||
m_staging_index_buffer.resize(MAXIBUFFERSIZE);
|
||||
|
||||
CreateDeviceObjects();
|
||||
}
|
||||
|
||||
VertexManager::~VertexManager()
|
||||
{
|
||||
DestroyDeviceObjects();
|
||||
return true;
|
||||
}
|
||||
|
||||
void VertexManager::UploadUtilityUniforms(const void* uniforms, u32 uniforms_size)
|
||||
{
|
||||
// Just use the one buffer for all three.
|
||||
InvalidateConstants();
|
||||
UpdateConstantBuffer(m_vertex_constant_buffer, uniforms, uniforms_size);
|
||||
D3D::stateman->SetVertexConstants(m_vertex_constant_buffer);
|
||||
D3D::stateman->SetGeometryConstants(m_vertex_constant_buffer);
|
||||
D3D::stateman->SetPixelConstants(m_vertex_constant_buffer);
|
||||
VertexShaderManager::dirty = true;
|
||||
GeometryShaderManager::dirty = true;
|
||||
PixelShaderManager::dirty = true;
|
||||
}
|
||||
|
||||
void VertexManager::ResetBuffer(u32 vertex_stride, bool cull_all)
|
||||
bool VertexManager::MapTexelBuffer(u32 required_size, D3D11_MAPPED_SUBRESOURCE& sr)
|
||||
{
|
||||
if ((m_texel_buffer_offset + required_size) > TEXEL_STREAM_BUFFER_SIZE)
|
||||
{
|
||||
// Restart buffer.
|
||||
HRESULT hr = D3D::context->Map(m_texel_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &sr);
|
||||
CHECK(SUCCEEDED(hr), "Map texel buffer");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
m_texel_buffer_offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't overwrite the earlier-used space.
|
||||
HRESULT hr = D3D::context->Map(m_texel_buffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &sr);
|
||||
CHECK(SUCCEEDED(hr), "Map texel buffer");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format,
|
||||
u32* out_offset)
|
||||
{
|
||||
if (data_size > TEXEL_STREAM_BUFFER_SIZE)
|
||||
return false;
|
||||
|
||||
const u32 elem_size = GetTexelBufferElementSize(format);
|
||||
m_texel_buffer_offset = Common::AlignUp(m_texel_buffer_offset, elem_size);
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE sr;
|
||||
if (!MapTexelBuffer(data_size, sr))
|
||||
return false;
|
||||
|
||||
*out_offset = m_texel_buffer_offset / elem_size;
|
||||
std::memcpy(static_cast<u8*>(sr.pData) + m_texel_buffer_offset, data, data_size);
|
||||
ADDSTAT(stats.thisFrame.bytesUniformStreamed, data_size);
|
||||
m_texel_buffer_offset += data_size;
|
||||
|
||||
D3D::context->Unmap(m_texel_buffer, 0);
|
||||
D3D::stateman->SetTexture(0, m_texel_buffer_views[static_cast<size_t>(format)]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format,
|
||||
u32* out_offset, const void* palette_data, u32 palette_size,
|
||||
TexelBufferFormat palette_format, u32* out_palette_offset)
|
||||
{
|
||||
const u32 elem_size = GetTexelBufferElementSize(format);
|
||||
const u32 palette_elem_size = GetTexelBufferElementSize(palette_format);
|
||||
const u32 reserve_size = data_size + palette_size + palette_elem_size;
|
||||
if (reserve_size > TEXEL_STREAM_BUFFER_SIZE)
|
||||
return false;
|
||||
|
||||
m_texel_buffer_offset = Common::AlignUp(m_texel_buffer_offset, elem_size);
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE sr;
|
||||
if (!MapTexelBuffer(reserve_size, sr))
|
||||
return false;
|
||||
|
||||
const u32 palette_byte_offset = Common::AlignUp(data_size, palette_elem_size);
|
||||
std::memcpy(static_cast<u8*>(sr.pData) + m_texel_buffer_offset, data, data_size);
|
||||
std::memcpy(static_cast<u8*>(sr.pData) + m_texel_buffer_offset + palette_byte_offset,
|
||||
palette_data, palette_size);
|
||||
ADDSTAT(stats.thisFrame.bytesUniformStreamed, palette_byte_offset + palette_size);
|
||||
*out_offset = m_texel_buffer_offset / elem_size;
|
||||
*out_palette_offset = (m_texel_buffer_offset + palette_byte_offset) / palette_elem_size;
|
||||
m_texel_buffer_offset += palette_byte_offset + palette_size;
|
||||
|
||||
D3D::context->Unmap(m_texel_buffer, 0);
|
||||
D3D::stateman->SetTexture(0, m_texel_buffer_views[static_cast<size_t>(format)]);
|
||||
D3D::stateman->SetTexture(1, m_texel_buffer_views[static_cast<size_t>(palette_format)]);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VertexManager::ResetBuffer(u32 vertex_stride)
|
||||
{
|
||||
m_base_buffer_pointer = m_cpu_vertex_buffer.data();
|
||||
m_cur_buffer_pointer = m_base_buffer_pointer;
|
||||
IndexGenerator::Start(m_staging_index_buffer.data());
|
||||
m_end_buffer_pointer = m_base_buffer_pointer + m_cpu_vertex_buffer.size();
|
||||
IndexGenerator::Start(m_cpu_index_buffer.data());
|
||||
}
|
||||
|
||||
void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices,
|
||||
|
@ -143,10 +234,10 @@ void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_in
|
|||
}
|
||||
|
||||
D3D11_MAP MapType = D3D11_MAP_WRITE_NO_OVERWRITE;
|
||||
if (cursor + totalBufferSize >= MAX_BUFFER_SIZE)
|
||||
if (cursor + totalBufferSize >= BUFFER_SIZE)
|
||||
{
|
||||
// Wrap around
|
||||
m_current_buffer = (m_current_buffer + 1) % MAX_BUFFER_COUNT;
|
||||
m_current_buffer = (m_current_buffer + 1) % BUFFER_COUNT;
|
||||
cursor = 0;
|
||||
MapType = D3D11_MAP_WRITE_DISCARD;
|
||||
}
|
||||
|
@ -159,8 +250,7 @@ void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_in
|
|||
if (vertexBufferSize > 0)
|
||||
std::memcpy(mappedData + cursor, m_base_buffer_pointer, vertexBufferSize);
|
||||
if (indexBufferSize > 0)
|
||||
std::memcpy(mappedData + cursor + vertexBufferSize, m_staging_index_buffer.data(),
|
||||
indexBufferSize);
|
||||
std::memcpy(mappedData + cursor + vertexBufferSize, m_cpu_index_buffer.data(), indexBufferSize);
|
||||
D3D::context->Unmap(m_buffers[m_current_buffer], 0);
|
||||
|
||||
m_buffer_cursor = cursor + totalBufferSize;
|
||||
|
@ -172,7 +262,7 @@ void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_in
|
|||
D3D::stateman->SetIndexBuffer(m_buffers[m_current_buffer]);
|
||||
}
|
||||
|
||||
void VertexManager::UploadConstants()
|
||||
void VertexManager::UploadUniforms()
|
||||
{
|
||||
if (VertexShaderManager::dirty)
|
||||
{
|
||||
|
@ -199,20 +289,4 @@ void VertexManager::UploadConstants()
|
|||
D3D::stateman->SetVertexConstants(m_vertex_constant_buffer);
|
||||
D3D::stateman->SetGeometryConstants(m_geometry_constant_buffer);
|
||||
}
|
||||
|
||||
void VertexManager::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex)
|
||||
{
|
||||
FramebufferManager::SetIntegerEFBRenderTarget(
|
||||
m_current_pipeline_config.blending_state.logicopenable);
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsBBox && BoundingBox::active)
|
||||
{
|
||||
D3D::context->OMSetRenderTargetsAndUnorderedAccessViews(
|
||||
D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, 2, 1, &BBox::GetUAV(),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
D3D::stateman->Apply();
|
||||
D3D::context->DrawIndexed(num_indices, base_index, base_vertex);
|
||||
}
|
||||
} // namespace DX11
|
||||
|
|
|
@ -18,13 +18,12 @@ struct ID3D11Buffer;
|
|||
|
||||
namespace DX11
|
||||
{
|
||||
class D3DBlob;
|
||||
class D3DVertexFormat : public NativeVertexFormat
|
||||
{
|
||||
public:
|
||||
D3DVertexFormat(const PortableVertexDeclaration& vtx_decl);
|
||||
~D3DVertexFormat();
|
||||
ID3D11InputLayout* GetInputLayout(D3DBlob* vs_bytecode);
|
||||
ID3D11InputLayout* GetInputLayout(const void* vs_bytecode, size_t vs_bytecode_size);
|
||||
|
||||
private:
|
||||
std::array<D3D11_INPUT_ELEMENT_DESC, 32> m_elems{};
|
||||
|
@ -39,35 +38,39 @@ public:
|
|||
VertexManager();
|
||||
~VertexManager();
|
||||
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
|
||||
bool Initialize();
|
||||
|
||||
void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) override;
|
||||
bool UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format,
|
||||
u32* out_offset) override;
|
||||
bool UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format, u32* out_offset,
|
||||
const void* palette_data, u32 palette_size,
|
||||
TexelBufferFormat palette_format, u32* out_palette_offset) override;
|
||||
|
||||
protected:
|
||||
void CreateDeviceObjects() override;
|
||||
void DestroyDeviceObjects() override;
|
||||
void ResetBuffer(u32 vertex_stride, bool cull_all) override;
|
||||
void ResetBuffer(u32 vertex_stride) override;
|
||||
void CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, u32* out_base_vertex,
|
||||
u32* out_base_index) override;
|
||||
void UploadConstants() override;
|
||||
void DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) override;
|
||||
void UploadUniforms() override;
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
MAX_BUFFER_COUNT = 2
|
||||
};
|
||||
ID3D11Buffer* m_buffers[MAX_BUFFER_COUNT] = {};
|
||||
static constexpr u32 BUFFER_COUNT = 2;
|
||||
static constexpr u32 BUFFER_SIZE =
|
||||
(VERTEX_STREAM_BUFFER_SIZE + INDEX_STREAM_BUFFER_SIZE) / BUFFER_COUNT;
|
||||
|
||||
bool MapTexelBuffer(u32 required_size, D3D11_MAPPED_SUBRESOURCE& sr);
|
||||
|
||||
ID3D11Buffer* m_buffers[BUFFER_COUNT] = {};
|
||||
u32 m_current_buffer = 0;
|
||||
u32 m_buffer_cursor = 0;
|
||||
|
||||
std::vector<u8> m_staging_vertex_buffer;
|
||||
std::vector<u16> m_staging_index_buffer;
|
||||
|
||||
ID3D11Buffer* m_vertex_constant_buffer = nullptr;
|
||||
ID3D11Buffer* m_geometry_constant_buffer = nullptr;
|
||||
ID3D11Buffer* m_pixel_constant_buffer = nullptr;
|
||||
|
||||
ID3D11Buffer* m_texel_buffer = nullptr;
|
||||
std::array<ID3D11ShaderResourceView*, NUM_TEXEL_BUFFER_FORMATS> m_texel_buffer_views;
|
||||
u32 m_texel_buffer_offset = 0;
|
||||
};
|
||||
|
||||
} // namespace DX11
|
||||
|
|
|
@ -1,136 +0,0 @@
|
|||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Host.h"
|
||||
|
||||
#include "VideoBackends/D3D/D3DShader.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/VertexManager.h"
|
||||
#include "VideoBackends/D3D/VertexShaderCache.h"
|
||||
|
||||
#include "VideoCommon/Debugger.h"
|
||||
#include "VideoCommon/Statistics.h"
|
||||
#include "VideoCommon/UberShaderVertex.h"
|
||||
#include "VideoCommon/VertexLoaderManager.h"
|
||||
#include "VideoCommon/VertexShaderGen.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
static ID3D11VertexShader* SimpleVertexShader = nullptr;
|
||||
static ID3D11VertexShader* ClearVertexShader = nullptr;
|
||||
static ID3D11InputLayout* SimpleLayout = nullptr;
|
||||
static ID3D11InputLayout* ClearLayout = nullptr;
|
||||
|
||||
ID3D11VertexShader* VertexShaderCache::GetSimpleVertexShader()
|
||||
{
|
||||
return SimpleVertexShader;
|
||||
}
|
||||
ID3D11VertexShader* VertexShaderCache::GetClearVertexShader()
|
||||
{
|
||||
return ClearVertexShader;
|
||||
}
|
||||
ID3D11InputLayout* VertexShaderCache::GetSimpleInputLayout()
|
||||
{
|
||||
return SimpleLayout;
|
||||
}
|
||||
ID3D11InputLayout* VertexShaderCache::GetClearInputLayout()
|
||||
{
|
||||
return ClearLayout;
|
||||
}
|
||||
|
||||
// this class will load the precompiled shaders into our cache
|
||||
template <typename UidType>
|
||||
class VertexShaderCacheInserter : public LinearDiskCacheReader<UidType, u8>
|
||||
{
|
||||
public:
|
||||
void Read(const UidType& key, const u8* value, u32 value_size)
|
||||
{
|
||||
D3DBlob* blob = new D3DBlob(value_size, value);
|
||||
VertexShaderCache::InsertByteCode(key, blob);
|
||||
blob->Release();
|
||||
}
|
||||
};
|
||||
|
||||
const char simple_shader_code[] = {
|
||||
"struct VSOUTPUT\n"
|
||||
"{\n"
|
||||
"float4 vPosition : POSITION;\n"
|
||||
"float3 vTexCoord : TEXCOORD0;\n"
|
||||
"};\n"
|
||||
"VSOUTPUT main(float4 inPosition : POSITION,float3 inTEX0 : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
"VSOUTPUT OUT;\n"
|
||||
"OUT.vPosition = inPosition;\n"
|
||||
"OUT.vTexCoord = inTEX0;\n"
|
||||
"return OUT;\n"
|
||||
"}\n"};
|
||||
|
||||
const char clear_shader_code[] = {
|
||||
"struct VSOUTPUT\n"
|
||||
"{\n"
|
||||
"float4 vPosition : POSITION;\n"
|
||||
"float4 vColor0 : COLOR0;\n"
|
||||
"};\n"
|
||||
"VSOUTPUT main(float4 inPosition : POSITION,float4 inColor0: COLOR0)\n"
|
||||
"{\n"
|
||||
"VSOUTPUT OUT;\n"
|
||||
"OUT.vPosition = inPosition;\n"
|
||||
"OUT.vColor0 = inColor0;\n"
|
||||
"return OUT;\n"
|
||||
"}\n"};
|
||||
|
||||
void VertexShaderCache::Init()
|
||||
{
|
||||
const D3D11_INPUT_ELEMENT_DESC simpleelems[2] = {
|
||||
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
{"TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
|
||||
};
|
||||
const D3D11_INPUT_ELEMENT_DESC clearelems[2] = {
|
||||
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
};
|
||||
|
||||
D3DBlob* blob;
|
||||
D3D::CompileVertexShader(simple_shader_code, &blob);
|
||||
D3D::device->CreateInputLayout(simpleelems, 2, blob->Data(), blob->Size(), &SimpleLayout);
|
||||
SimpleVertexShader = D3D::CreateVertexShaderFromByteCode(blob);
|
||||
if (SimpleLayout == nullptr || SimpleVertexShader == nullptr)
|
||||
PanicAlert("Failed to create simple vertex shader or input layout at %s %d\n", __FILE__,
|
||||
__LINE__);
|
||||
blob->Release();
|
||||
D3D::SetDebugObjectName(SimpleVertexShader, "simple vertex shader");
|
||||
D3D::SetDebugObjectName(SimpleLayout, "simple input layout");
|
||||
|
||||
D3D::CompileVertexShader(clear_shader_code, &blob);
|
||||
D3D::device->CreateInputLayout(clearelems, 2, blob->Data(), blob->Size(), &ClearLayout);
|
||||
ClearVertexShader = D3D::CreateVertexShaderFromByteCode(blob);
|
||||
if (ClearLayout == nullptr || ClearVertexShader == nullptr)
|
||||
PanicAlert("Failed to create clear vertex shader or input layout at %s %d\n", __FILE__,
|
||||
__LINE__);
|
||||
blob->Release();
|
||||
D3D::SetDebugObjectName(ClearVertexShader, "clear vertex shader");
|
||||
D3D::SetDebugObjectName(ClearLayout, "clear input layout");
|
||||
|
||||
SETSTAT(stats.numVertexShadersCreated, 0);
|
||||
SETSTAT(stats.numVertexShadersAlive, 0);
|
||||
}
|
||||
|
||||
void VertexShaderCache::Shutdown()
|
||||
{
|
||||
SAFE_RELEASE(SimpleVertexShader);
|
||||
SAFE_RELEASE(ClearVertexShader);
|
||||
|
||||
SAFE_RELEASE(SimpleLayout);
|
||||
SAFE_RELEASE(ClearLayout);
|
||||
}
|
||||
} // namespace DX11
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DBlob.h"
|
||||
|
||||
#include "VideoCommon/AsyncShaderCompiler.h"
|
||||
#include "VideoCommon/UberShaderVertex.h"
|
||||
#include "VideoCommon/VertexShaderGen.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
class D3DVertexFormat;
|
||||
|
||||
class VertexShaderCache
|
||||
{
|
||||
public:
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
static ID3D11VertexShader* GetSimpleVertexShader();
|
||||
static ID3D11VertexShader* GetClearVertexShader();
|
||||
static ID3D11InputLayout* GetSimpleInputLayout();
|
||||
static ID3D11InputLayout* GetClearInputLayout();
|
||||
};
|
||||
|
||||
} // namespace DX11
|
|
@ -12,17 +12,14 @@
|
|||
|
||||
#include "VideoBackends/D3D/BoundingBox.h"
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DUtil.h"
|
||||
#include "VideoBackends/D3D/GeometryShaderCache.h"
|
||||
#include "VideoBackends/D3D/PerfQuery.h"
|
||||
#include "VideoBackends/D3D/PixelShaderCache.h"
|
||||
#include "VideoBackends/D3D/Render.h"
|
||||
#include "VideoBackends/D3D/TextureCache.h"
|
||||
#include "VideoBackends/D3D/VertexManager.h"
|
||||
#include "VideoBackends/D3D/VertexShaderCache.h"
|
||||
#include "VideoBackends/D3D/VideoBackend.h"
|
||||
|
||||
#include "VideoCommon/FramebufferManager.h"
|
||||
#include "VideoCommon/ShaderCache.h"
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
|
@ -51,6 +48,7 @@ void VideoBackend::InitBackendInfo()
|
|||
|
||||
g_Config.backend_info.api_type = APIType::D3D;
|
||||
g_Config.backend_info.MaxTextureSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
g_Config.backend_info.bUsesLowerLeftOrigin = false;
|
||||
g_Config.backend_info.bSupportsExclusiveFullscreen = true;
|
||||
g_Config.backend_info.bSupportsDualSourceBlend = true;
|
||||
g_Config.backend_info.bSupportsPrimitiveRestart = true;
|
||||
|
@ -58,16 +56,17 @@ void VideoBackend::InitBackendInfo()
|
|||
g_Config.backend_info.bSupportsGeometryShaders = true;
|
||||
g_Config.backend_info.bSupportsComputeShaders = false;
|
||||
g_Config.backend_info.bSupports3DVision = true;
|
||||
g_Config.backend_info.bSupportsPostProcessing = false;
|
||||
g_Config.backend_info.bSupportsPostProcessing = true;
|
||||
g_Config.backend_info.bSupportsPaletteConversion = true;
|
||||
g_Config.backend_info.bSupportsClipControl = true;
|
||||
g_Config.backend_info.bSupportsDepthClamp = true;
|
||||
g_Config.backend_info.bSupportsReversedDepthRange = false;
|
||||
g_Config.backend_info.bSupportsLogicOp = true;
|
||||
g_Config.backend_info.bSupportsMultithreading = false;
|
||||
g_Config.backend_info.bSupportsGPUTextureDecoding = false;
|
||||
g_Config.backend_info.bSupportsGPUTextureDecoding = true;
|
||||
g_Config.backend_info.bSupportsST3CTextures = false;
|
||||
g_Config.backend_info.bSupportsCopyToVram = true;
|
||||
g_Config.backend_info.bSupportsLargePoints = false;
|
||||
g_Config.backend_info.bSupportsBitfield = false;
|
||||
g_Config.backend_info.bSupportsDynamicSamplerIndexing = false;
|
||||
g_Config.backend_info.bSupportsBPTCTextures = false;
|
||||
|
@ -149,21 +148,20 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
|
|||
// internal interfaces
|
||||
g_renderer =
|
||||
std::make_unique<Renderer>(backbuffer_width, backbuffer_height, wsi.render_surface_scale);
|
||||
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
|
||||
g_texture_cache = std::make_unique<TextureCache>();
|
||||
g_vertex_manager = std::make_unique<VertexManager>();
|
||||
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
|
||||
g_framebuffer_manager = std::make_unique<FramebufferManager>();
|
||||
g_texture_cache = std::make_unique<TextureCacheBase>();
|
||||
g_perf_query = std::make_unique<PerfQuery>();
|
||||
|
||||
VertexShaderCache::Init();
|
||||
PixelShaderCache::Init();
|
||||
GeometryShaderCache::Init();
|
||||
|
||||
if (!g_renderer->Initialize() || !g_shader_cache->Initialize())
|
||||
if (!g_renderer->Initialize() || !g_vertex_manager->Initialize() ||
|
||||
!g_shader_cache->Initialize() || !g_framebuffer_manager->Initialize() ||
|
||||
!g_texture_cache->Initialize())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
D3D::InitUtils();
|
||||
BBox::Init();
|
||||
|
||||
g_shader_cache->InitializeShaderCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -172,16 +170,13 @@ void VideoBackend::Shutdown()
|
|||
g_shader_cache->Shutdown();
|
||||
g_renderer->Shutdown();
|
||||
|
||||
D3D::ShutdownUtils();
|
||||
PixelShaderCache::Shutdown();
|
||||
VertexShaderCache::Shutdown();
|
||||
GeometryShaderCache::Shutdown();
|
||||
BBox::Shutdown();
|
||||
|
||||
g_perf_query.reset();
|
||||
g_vertex_manager.reset();
|
||||
g_texture_cache.reset();
|
||||
g_framebuffer_manager.reset();
|
||||
g_shader_cache.reset();
|
||||
g_vertex_manager.reset();
|
||||
g_renderer.reset();
|
||||
|
||||
ShutdownShared();
|
||||
|
|
|
@ -13,7 +13,9 @@
|
|||
#include "VideoBackends/Null/VertexManager.h"
|
||||
#include "VideoBackends/Null/VideoBackend.h"
|
||||
|
||||
#include "VideoCommon/FramebufferManagerBase.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
#include "VideoCommon/FramebufferManager.h"
|
||||
#include "VideoCommon/VideoBackendBase.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
@ -61,10 +63,21 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
|
|||
g_renderer = std::make_unique<Renderer>();
|
||||
g_vertex_manager = std::make_unique<VertexManager>();
|
||||
g_perf_query = std::make_unique<PerfQuery>();
|
||||
g_framebuffer_manager = std::make_unique<FramebufferManagerBase>();
|
||||
g_framebuffer_manager = std::make_unique<FramebufferManager>();
|
||||
g_texture_cache = std::make_unique<TextureCache>();
|
||||
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
|
||||
return g_renderer->Initialize() && g_shader_cache->Initialize();
|
||||
|
||||
if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() ||
|
||||
!g_renderer->Initialize() || !g_framebuffer_manager->Initialize() ||
|
||||
!g_texture_cache->Initialize())
|
||||
{
|
||||
PanicAlert("Failed to initialize renderer classes");
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
g_shader_cache->InitializeShaderCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoBackend::Shutdown()
|
||||
|
|
|
@ -16,11 +16,6 @@ void NullTexture::CopyRectangleFromTexture(const AbstractTexture* src,
|
|||
u32 dst_layer, u32 dst_level)
|
||||
{
|
||||
}
|
||||
void NullTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
const MathUtil::Rectangle<int>& srcrect,
|
||||
const MathUtil::Rectangle<int>& dstrect)
|
||||
{
|
||||
}
|
||||
void NullTexture::ResolveFromTexture(const AbstractTexture* src,
|
||||
const MathUtil::Rectangle<int>& rect, u32 layer, u32 level)
|
||||
{
|
||||
|
@ -70,15 +65,18 @@ void NullStagingTexture::Flush()
|
|||
m_needs_flush = false;
|
||||
}
|
||||
|
||||
NullFramebuffer::NullFramebuffer(AbstractTextureFormat color_format,
|
||||
NullFramebuffer::NullFramebuffer(AbstractTexture* color_attachment,
|
||||
AbstractTexture* depth_attachment,
|
||||
AbstractTextureFormat color_format,
|
||||
AbstractTextureFormat depth_format, u32 width, u32 height,
|
||||
u32 layers, u32 samples)
|
||||
: AbstractFramebuffer(color_format, depth_format, width, height, layers, samples)
|
||||
: AbstractFramebuffer(color_attachment, depth_attachment, color_format, depth_format, width,
|
||||
height, layers, samples)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<NullFramebuffer> NullFramebuffer::Create(const NullTexture* color_attachment,
|
||||
const NullTexture* depth_attachment)
|
||||
std::unique_ptr<NullFramebuffer> NullFramebuffer::Create(NullTexture* color_attachment,
|
||||
NullTexture* depth_attachment)
|
||||
{
|
||||
if (!ValidateConfig(color_attachment, depth_attachment))
|
||||
return nullptr;
|
||||
|
@ -93,8 +91,8 @@ std::unique_ptr<NullFramebuffer> NullFramebuffer::Create(const NullTexture* colo
|
|||
const u32 layers = either_attachment->GetLayers();
|
||||
const u32 samples = either_attachment->GetSamples();
|
||||
|
||||
return std::make_unique<NullFramebuffer>(color_format, depth_format, width, height, layers,
|
||||
samples);
|
||||
return std::make_unique<NullFramebuffer>(color_attachment, depth_attachment, color_format,
|
||||
depth_format, width, height, layers, samples);
|
||||
}
|
||||
|
||||
} // namespace Null
|
||||
|
|
|
@ -25,9 +25,6 @@ public:
|
|||
const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
|
||||
u32 src_level, const MathUtil::Rectangle<int>& dst_rect,
|
||||
u32 dst_layer, u32 dst_level) override;
|
||||
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
const MathUtil::Rectangle<int>& srcrect,
|
||||
const MathUtil::Rectangle<int>& dstrect) override;
|
||||
void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
|
||||
u32 layer, u32 level) override;
|
||||
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
|
@ -58,12 +55,13 @@ private:
|
|||
class NullFramebuffer final : public AbstractFramebuffer
|
||||
{
|
||||
public:
|
||||
explicit NullFramebuffer(AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
|
||||
explicit NullFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
||||
AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
|
||||
u32 width, u32 height, u32 layers, u32 samples);
|
||||
~NullFramebuffer() override = default;
|
||||
|
||||
static std::unique_ptr<NullFramebuffer> Create(const NullTexture* color_attachment,
|
||||
const NullTexture* depth_attachment);
|
||||
static std::unique_ptr<NullFramebuffer> Create(NullTexture* color_attachment,
|
||||
NullTexture* depth_attachment);
|
||||
};
|
||||
|
||||
} // namespace Null
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "VideoCommon/AbstractPipeline.h"
|
||||
#include "VideoCommon/AbstractShader.h"
|
||||
#include "VideoCommon/NativeVertexFormat.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace Null
|
||||
|
@ -74,22 +75,16 @@ std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelin
|
|||
return std::make_unique<NullPipeline>();
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
Renderer::CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment)
|
||||
std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment,
|
||||
AbstractTexture* depth_attachment)
|
||||
{
|
||||
return NullFramebuffer::Create(static_cast<const NullTexture*>(color_attachment),
|
||||
static_cast<const NullTexture*>(depth_attachment));
|
||||
return NullFramebuffer::Create(static_cast<NullTexture*>(color_attachment),
|
||||
static_cast<NullTexture*>(depth_attachment));
|
||||
}
|
||||
|
||||
TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
{
|
||||
TargetRectangle result;
|
||||
result.left = rc.left;
|
||||
result.top = rc.top;
|
||||
result.right = rc.right;
|
||||
result.bottom = rc.bottom;
|
||||
return result;
|
||||
return std::make_unique<NativeVertexFormat>(vtx_decl);
|
||||
}
|
||||
|
||||
} // namespace Null
|
||||
|
|
|
@ -20,26 +20,26 @@ public:
|
|||
std::unique_ptr<AbstractStagingTexture>
|
||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment) override;
|
||||
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
|
||||
|
||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, const char* source,
|
||||
size_t length) override;
|
||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||
size_t length) override;
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
|
||||
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config) override;
|
||||
|
||||
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override { return 0; }
|
||||
void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {}
|
||||
u16 BBoxRead(int index) override { return 0; }
|
||||
void BBoxWrite(int index, u16 value) override {}
|
||||
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
|
||||
|
||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
|
||||
u32 color, u32 z) override
|
||||
{
|
||||
}
|
||||
|
||||
void ReinterpretPixelData(unsigned int convtype) override {}
|
||||
void ReinterpretPixelData(EFBReinterpretType convtype) override {}
|
||||
};
|
||||
}
|
||||
} // namespace Null
|
||||
|
|
|
@ -18,26 +18,21 @@ class TextureCache : public TextureCacheBase
|
|||
public:
|
||||
TextureCache() {}
|
||||
~TextureCache() {}
|
||||
bool CompileShaders() override { return true; }
|
||||
void DeleteShaders() override {}
|
||||
void ConvertTexture(TCacheEntry* entry, TCacheEntry* unconverted, const void* palette,
|
||||
TLUTFormat format) override
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
void CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams& params, u32 native_width,
|
||||
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override
|
||||
const EFBCopyFilterCoefficients& filter_coefficients) override
|
||||
{
|
||||
}
|
||||
|
||||
void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, EFBCopyFormat dst_format, bool is_intensity,
|
||||
float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override
|
||||
const EFBCopyFilterCoefficients& filter_coefficients) override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // Null name space
|
||||
} // namespace Null
|
||||
|
|
|
@ -3,52 +3,16 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/Null/VertexManager.h"
|
||||
#include "VideoBackends/Null/Render.h"
|
||||
|
||||
#include "VideoCommon/IndexGenerator.h"
|
||||
#include "VideoCommon/NativeVertexFormat.h"
|
||||
#include "VideoCommon/VertexLoaderManager.h"
|
||||
|
||||
namespace Null
|
||||
{
|
||||
class NullNativeVertexFormat : public NativeVertexFormat
|
||||
{
|
||||
public:
|
||||
NullNativeVertexFormat(const PortableVertexDeclaration& vtx_decl_) { vtx_decl = vtx_decl_; }
|
||||
};
|
||||
VertexManager::VertexManager() = default;
|
||||
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
{
|
||||
return std::make_unique<NullNativeVertexFormat>(vtx_decl);
|
||||
}
|
||||
|
||||
void VertexManager::UploadUtilityUniforms(const void* uniforms, u32 uniforms_size)
|
||||
{
|
||||
}
|
||||
|
||||
VertexManager::VertexManager() : m_local_v_buffer(MAXVBUFFERSIZE), m_local_i_buffer(MAXIBUFFERSIZE)
|
||||
{
|
||||
}
|
||||
|
||||
VertexManager::~VertexManager()
|
||||
{
|
||||
}
|
||||
|
||||
void VertexManager::ResetBuffer(u32 vertex_stride, bool cull_all)
|
||||
{
|
||||
m_cur_buffer_pointer = m_base_buffer_pointer = m_local_v_buffer.data();
|
||||
m_end_buffer_pointer = m_cur_buffer_pointer + m_local_v_buffer.size();
|
||||
IndexGenerator::Start(&m_local_i_buffer[0]);
|
||||
}
|
||||
|
||||
void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices,
|
||||
u32* out_base_vertex, u32* out_base_index)
|
||||
{
|
||||
}
|
||||
|
||||
void VertexManager::UploadConstants()
|
||||
{
|
||||
}
|
||||
VertexManager::~VertexManager() = default;
|
||||
|
||||
void VertexManager::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex)
|
||||
{
|
||||
|
|
|
@ -17,20 +17,7 @@ public:
|
|||
VertexManager();
|
||||
~VertexManager();
|
||||
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
|
||||
|
||||
void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) override;
|
||||
|
||||
protected:
|
||||
void ResetBuffer(u32 vertex_stride, bool cull_all) override;
|
||||
void CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, u32* out_base_vertex,
|
||||
u32* out_base_index) override;
|
||||
void UploadConstants() override;
|
||||
void DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) override;
|
||||
|
||||
private:
|
||||
std::vector<u8> m_local_v_buffer;
|
||||
std::vector<u16> m_local_i_buffer;
|
||||
};
|
||||
}
|
||||
} // namespace Null
|
||||
|
|
|
@ -2,175 +2,77 @@
|
|||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
|
||||
#include "Common/GL/GLUtil.h"
|
||||
|
||||
#include "VideoBackends/OGL/BoundingBox.h"
|
||||
#include "VideoBackends/OGL/FramebufferManager.h"
|
||||
#include "VideoBackends/OGL/Render.h"
|
||||
|
||||
#include "VideoCommon/DriverDetails.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
static GLuint s_bbox_buffer_id;
|
||||
static GLuint s_pbo;
|
||||
|
||||
static std::array<int, 4> s_stencil_bounds;
|
||||
static bool s_stencil_updated;
|
||||
static bool s_stencil_cleared;
|
||||
|
||||
static int s_target_width;
|
||||
static int s_target_height;
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
void BoundingBox::SetTargetSizeChanged(int target_width, int target_height)
|
||||
void BoundingBox::Init()
|
||||
{
|
||||
if (g_ActiveConfig.BBoxUseFragmentShaderImplementation())
|
||||
if (!g_ActiveConfig.backend_info.bSupportsBBox)
|
||||
return;
|
||||
|
||||
s_target_width = target_width;
|
||||
s_target_height = target_height;
|
||||
s_stencil_updated = false;
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, s_pbo);
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, s_target_width * s_target_height, nullptr, GL_STREAM_READ);
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
}
|
||||
|
||||
void BoundingBox::Init(int target_width, int target_height)
|
||||
{
|
||||
if (g_ActiveConfig.BBoxUseFragmentShaderImplementation())
|
||||
{
|
||||
int initial_values[4] = {0, 0, 0, 0};
|
||||
glGenBuffers(1, &s_bbox_buffer_id);
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id);
|
||||
glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * sizeof(s32), initial_values, GL_DYNAMIC_DRAW);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, s_bbox_buffer_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
s_stencil_bounds = {{0, 0, 0, 0}};
|
||||
glGenBuffers(1, &s_pbo);
|
||||
SetTargetSizeChanged(target_width, target_height);
|
||||
}
|
||||
int initial_values[4] = {0, 0, 0, 0};
|
||||
glGenBuffers(1, &s_bbox_buffer_id);
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id);
|
||||
glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * sizeof(s32), initial_values, GL_DYNAMIC_DRAW);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, s_bbox_buffer_id);
|
||||
}
|
||||
|
||||
void BoundingBox::Shutdown()
|
||||
{
|
||||
if (g_ActiveConfig.BBoxUseFragmentShaderImplementation())
|
||||
{
|
||||
glDeleteBuffers(1, &s_bbox_buffer_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDeleteBuffers(1, &s_pbo);
|
||||
}
|
||||
if (!g_ActiveConfig.backend_info.bSupportsBBox)
|
||||
return;
|
||||
|
||||
glDeleteBuffers(1, &s_bbox_buffer_id);
|
||||
}
|
||||
|
||||
void BoundingBox::Set(int index, int value)
|
||||
{
|
||||
if (g_ActiveConfig.BBoxUseFragmentShaderImplementation())
|
||||
{
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id);
|
||||
glBufferSubData(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int), &value);
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
s_stencil_bounds[index] = value;
|
||||
if (!g_ActiveConfig.backend_info.bSupportsBBox)
|
||||
return;
|
||||
|
||||
if (!s_stencil_cleared)
|
||||
{
|
||||
// Assumes that the EFB framebuffer is currently bound
|
||||
glClearStencil(0);
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
s_stencil_updated = false;
|
||||
s_stencil_cleared = true;
|
||||
}
|
||||
}
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id);
|
||||
glBufferSubData(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int), &value);
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
||||
}
|
||||
|
||||
int BoundingBox::Get(int index)
|
||||
{
|
||||
if (g_ActiveConfig.BBoxUseFragmentShaderImplementation())
|
||||
if (!g_ActiveConfig.backend_info.bSupportsBBox)
|
||||
return 0;
|
||||
|
||||
int data = 0;
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id);
|
||||
if (!DriverDetails::HasBug(DriverDetails::BUG_SLOW_GETBUFFERSUBDATA) &&
|
||||
!static_cast<Renderer*>(g_renderer.get())->IsGLES())
|
||||
{
|
||||
int data = 0;
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id);
|
||||
if (!DriverDetails::HasBug(DriverDetails::BUG_SLOW_GETBUFFERSUBDATA) &&
|
||||
!static_cast<Renderer*>(g_renderer.get())->IsGLES())
|
||||
{
|
||||
// Using glMapBufferRange to read back the contents of the SSBO is extremely slow
|
||||
// on nVidia drivers. This is more noticeable at higher internal resolutions.
|
||||
// Using glGetBufferSubData instead does not seem to exhibit this slowdown.
|
||||
glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int), &data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Using glMapBufferRange is faster on AMD cards by a measurable margin.
|
||||
void* ptr = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int),
|
||||
GL_MAP_READ_BIT);
|
||||
if (ptr)
|
||||
{
|
||||
memcpy(&data, ptr, sizeof(int));
|
||||
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
|
||||
}
|
||||
}
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
||||
return data;
|
||||
// Using glMapBufferRange to read back the contents of the SSBO is extremely slow
|
||||
// on nVidia drivers. This is more noticeable at higher internal resolutions.
|
||||
// Using glGetBufferSubData instead does not seem to exhibit this slowdown.
|
||||
glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int), &data);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s_stencil_updated)
|
||||
// Using glMapBufferRange is faster on AMD cards by a measurable margin.
|
||||
void* ptr = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int),
|
||||
GL_MAP_READ_BIT);
|
||||
if (ptr)
|
||||
{
|
||||
s_stencil_updated = false;
|
||||
|
||||
FramebufferManager::ResolveEFBStencilTexture();
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetResolvedFramebuffer());
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, s_pbo);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels(0, 0, s_target_width, s_target_height, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, 0);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetEFBFramebuffer());
|
||||
|
||||
// Eke every bit of performance out of the compiler that we can
|
||||
std::array<int, 4> bounds = s_stencil_bounds;
|
||||
|
||||
u8* data = static_cast<u8*>(glMapBufferRange(
|
||||
GL_PIXEL_PACK_BUFFER, 0, s_target_height * s_target_width, GL_MAP_READ_BIT));
|
||||
|
||||
for (int row = 0; row < s_target_height; row++)
|
||||
{
|
||||
for (int col = 0; col < s_target_width; col++)
|
||||
{
|
||||
if (data[row * s_target_width + col] == 0)
|
||||
continue;
|
||||
bounds[0] = std::min(bounds[0], col);
|
||||
bounds[1] = std::max(bounds[1], col);
|
||||
bounds[2] = std::min(bounds[2], row);
|
||||
bounds[3] = std::max(bounds[3], row);
|
||||
}
|
||||
}
|
||||
|
||||
s_stencil_bounds = bounds;
|
||||
|
||||
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
memcpy(&data, ptr, sizeof(int));
|
||||
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
|
||||
}
|
||||
|
||||
return s_stencil_bounds[index];
|
||||
}
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
||||
return data;
|
||||
}
|
||||
|
||||
void BoundingBox::StencilWasUpdated()
|
||||
{
|
||||
s_stencil_updated = true;
|
||||
s_stencil_cleared = false;
|
||||
}
|
||||
|
||||
bool BoundingBox::NeedsStencilBuffer()
|
||||
{
|
||||
return g_ActiveConfig.bBBoxEnable && !g_ActiveConfig.BBoxUseFragmentShaderImplementation();
|
||||
}
|
||||
};
|
||||
}; // namespace OGL
|
||||
|
|
|
@ -9,19 +9,10 @@ namespace OGL
|
|||
class BoundingBox
|
||||
{
|
||||
public:
|
||||
static void Init(int target_width, int target_height);
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
static void SetTargetSizeChanged(int target_width, int target_height);
|
||||
|
||||
// When SSBO isn't available, the bounding box is calculated directly from the
|
||||
// stencil buffer.
|
||||
static bool NeedsStencilBuffer();
|
||||
// When the stencil buffer is changed, this function needs to be called to
|
||||
// invalidate the cached bounding box data.
|
||||
static void StencilWasUpdated();
|
||||
|
||||
static void Set(int index, int value);
|
||||
static int Get(int index);
|
||||
};
|
||||
};
|
||||
}; // namespace OGL
|
||||
|
|
|
@ -1,19 +1,15 @@
|
|||
add_library(videoogl
|
||||
BoundingBox.cpp
|
||||
FramebufferManager.cpp
|
||||
main.cpp
|
||||
NativeVertexFormat.cpp
|
||||
OGLPipeline.cpp
|
||||
OGLShader.cpp
|
||||
OGLTexture.cpp
|
||||
PerfQuery.cpp
|
||||
PostProcessing.cpp
|
||||
ProgramShaderCache.cpp
|
||||
Render.cpp
|
||||
SamplerCache.cpp
|
||||
StreamBuffer.cpp
|
||||
TextureCache.cpp
|
||||
TextureConverter.cpp
|
||||
VertexManager.cpp
|
||||
)
|
||||
|
||||
|
|
|
@ -1,634 +0,0 @@
|
|||
// Copyright 2009 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/OGL/FramebufferManager.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/Common.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
#include "Core/HW/Memmap.h"
|
||||
|
||||
#include "VideoBackends/OGL/Render.h"
|
||||
#include "VideoBackends/OGL/SamplerCache.h"
|
||||
#include "VideoBackends/OGL/TextureConverter.h"
|
||||
#include "VideoBackends/OGL/VertexManager.h"
|
||||
|
||||
#include "VideoCommon/OnScreenDisplay.h"
|
||||
#include "VideoCommon/VertexShaderGen.h"
|
||||
#include "VideoCommon/VideoBackendBase.h"
|
||||
|
||||
constexpr const char* GLSL_REINTERPRET_PIXELFMT_VS = R"GLSL(
|
||||
flat out int layer;
|
||||
void main(void) {
|
||||
layer = 0;
|
||||
vec2 rawpos = vec2(gl_VertexID & 1, gl_VertexID & 2);
|
||||
gl_Position = vec4(rawpos* 2.0 - 1.0, 0.0, 1.0);
|
||||
})GLSL";
|
||||
|
||||
constexpr const char* GLSL_SHADER_FS = R"GLSL(
|
||||
#define MULTILAYER %d
|
||||
#define MSAA %d
|
||||
|
||||
#if MSAA
|
||||
|
||||
#if MULTILAYER
|
||||
SAMPLER_BINDING(9) uniform sampler2DMSArray samp9;
|
||||
#else
|
||||
SAMPLER_BINDING(9) uniform sampler2DMS samp9;
|
||||
#endif
|
||||
|
||||
#else
|
||||
SAMPLER_BINDING(9) uniform sampler2DArray samp9;
|
||||
#endif
|
||||
|
||||
vec4 sampleEFB(ivec3 pos) {
|
||||
#if MSAA
|
||||
|
||||
#if MULTILAYER
|
||||
return texelFetch(samp9, pos, gl_SampleID);
|
||||
#else
|
||||
return texelFetch(samp9, pos.xy, gl_SampleID);
|
||||
#endif
|
||||
|
||||
#else
|
||||
return texelFetch(samp9, pos, 0);
|
||||
#endif
|
||||
})GLSL";
|
||||
|
||||
constexpr const char* GLSL_SAMPLE_EFB_FS = R"GLSL(
|
||||
#define MULTILAYER %d
|
||||
|
||||
#if MULTILAYER
|
||||
SAMPLER_BINDING(9) uniform sampler2DMSArray samp9;
|
||||
#else
|
||||
SAMPLER_BINDING(9) uniform sampler2DMS samp9;
|
||||
#endif
|
||||
vec4 sampleEFB(ivec3 pos) {
|
||||
vec4 color = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
for (int i = 0; i < %d; i++)
|
||||
#if MULTILAYER
|
||||
color += texelFetch(samp9, pos, i);
|
||||
#else
|
||||
color += texelFetch(samp9, pos.xy, i);
|
||||
#endif
|
||||
|
||||
return color / %d;
|
||||
})GLSL";
|
||||
|
||||
constexpr const char* GLSL_RGBA6_TO_RGB8_FS = R"GLSL(
|
||||
flat in int layer;
|
||||
out vec4 ocol0;
|
||||
void main() {
|
||||
ivec4 src6 = ivec4(round(sampleEFB(ivec3(gl_FragCoord.xy, layer)) * 63.f));
|
||||
ivec4 dst8;
|
||||
|
||||
dst8.r = (src6.r << 2) | (src6.g >> 4);
|
||||
dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);
|
||||
dst8.b = ((src6.b & 0x3) << 6) | src6.a;
|
||||
dst8.a = 255;
|
||||
|
||||
ocol0 = float4(dst8) / 255.f;
|
||||
})GLSL";
|
||||
|
||||
constexpr const char* GLSL_RGB8_TO_RGBA6_FS = R"GLSL(
|
||||
flat in int layer;
|
||||
out vec4 ocol0;
|
||||
void main() {
|
||||
ivec4 src8 = ivec4(round(sampleEFB(ivec3(gl_FragCoord.xy, layer)) * 255.f));
|
||||
ivec4 dst6;
|
||||
|
||||
dst6.r = src8.r >> 2;
|
||||
dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);
|
||||
dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);
|
||||
dst6.a = src8.b & 0x3F;
|
||||
ocol0 = float4(dst6) / 63.f;
|
||||
})GLSL";
|
||||
|
||||
constexpr const char* GLSL_GS = R"GLSL(
|
||||
layout(triangles) in;
|
||||
layout(triangle_strip, max_vertices = %d) out;
|
||||
flat out int layer;
|
||||
void main() {
|
||||
for (int j = 0; j < %d; ++j) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
layer = j;
|
||||
gl_Layer = j;
|
||||
gl_Position = gl_in[i].gl_Position;
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
})GLSL";
|
||||
|
||||
constexpr const char* GLSL_EFB_POKE_VERTEX_VS = R"GLSL(
|
||||
in vec2 rawpos;
|
||||
in vec4 rawcolor0; // color
|
||||
in int rawcolor1; // depth
|
||||
out vec4 v_c;
|
||||
out float v_z;
|
||||
void main(void) {
|
||||
gl_Position = vec4(((rawpos + 0.5) / vec2(640.0, 528.0) * 2.0 - 1.0) * vec2(1.0, -1.0), 0.0, 1.0);
|
||||
gl_PointSize = %d.0 / 640.0;
|
||||
|
||||
v_c = rawcolor0.bgra;
|
||||
v_z = float(rawcolor1 & 0xFFFFFF) / 16777216.0;
|
||||
})GLSL";
|
||||
|
||||
constexpr const char* GLSL_EFB_POKE_PIXEL_FS = R"GLSL(
|
||||
in vec4 %s_c;
|
||||
in float %s_z;
|
||||
out vec4 ocol0;
|
||||
void main(void) {
|
||||
ocol0 = %s_c;
|
||||
gl_FragDepth = %s_z;
|
||||
})GLSL";
|
||||
|
||||
constexpr const char* GLSL_EFB_POKE_GEOMETRY_GS = R"GLSL(
|
||||
layout(points) in;
|
||||
layout(points, max_vertices = %d) out;
|
||||
in vec4 v_c[1];
|
||||
in float v_z[1];
|
||||
out vec4 g_c;
|
||||
out float g_z;
|
||||
void main() {
|
||||
for (int j = 0; j < %d; ++j) {
|
||||
gl_Layer = j;
|
||||
gl_Position = gl_in[0].gl_Position;
|
||||
gl_PointSize = %d.0 / 640.0;
|
||||
g_c = v_c[0];
|
||||
g_z = v_z[0];
|
||||
|
||||
EmitVertex();
|
||||
EndPrimitive();
|
||||
}
|
||||
})GLSL";
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
int FramebufferManager::m_targetWidth;
|
||||
int FramebufferManager::m_targetHeight;
|
||||
int FramebufferManager::m_msaaSamples;
|
||||
bool FramebufferManager::m_enable_stencil_buffer;
|
||||
|
||||
GLenum FramebufferManager::m_textureType;
|
||||
std::vector<GLuint> FramebufferManager::m_efbFramebuffer;
|
||||
GLuint FramebufferManager::m_efbColor;
|
||||
GLuint FramebufferManager::m_efbDepth;
|
||||
GLuint FramebufferManager::m_efbColorSwap; // for hot swap when reinterpreting EFB pixel formats
|
||||
|
||||
// Only used in MSAA mode.
|
||||
std::vector<GLuint> FramebufferManager::m_resolvedFramebuffer;
|
||||
GLuint FramebufferManager::m_resolvedColorTexture;
|
||||
GLuint FramebufferManager::m_resolvedDepthTexture;
|
||||
|
||||
// reinterpret pixel format
|
||||
SHADER FramebufferManager::m_pixel_format_shaders[2];
|
||||
|
||||
// EFB pokes
|
||||
GLuint FramebufferManager::m_EfbPokes_VBO;
|
||||
GLuint FramebufferManager::m_EfbPokes_VAO;
|
||||
SHADER FramebufferManager::m_EfbPokes;
|
||||
|
||||
GLuint FramebufferManager::CreateTexture(GLenum texture_type, GLenum internal_format,
|
||||
GLenum pixel_format, GLenum data_type)
|
||||
{
|
||||
GLuint texture;
|
||||
glActiveTexture(GL_TEXTURE9);
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(texture_type, texture);
|
||||
if (texture_type == GL_TEXTURE_2D_ARRAY)
|
||||
{
|
||||
glTexParameteri(texture_type, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage3D(texture_type, 0, internal_format, m_targetWidth, m_targetHeight, m_EFBLayers, 0,
|
||||
pixel_format, data_type, nullptr);
|
||||
}
|
||||
else if (texture_type == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
|
||||
{
|
||||
if (g_ogl_config.bSupports3DTextureStorageMultisample)
|
||||
glTexStorage3DMultisample(texture_type, m_msaaSamples, internal_format, m_targetWidth,
|
||||
m_targetHeight, m_EFBLayers, false);
|
||||
else
|
||||
glTexImage3DMultisample(texture_type, m_msaaSamples, internal_format, m_targetWidth,
|
||||
m_targetHeight, m_EFBLayers, false);
|
||||
}
|
||||
else if (texture_type == GL_TEXTURE_2D_MULTISAMPLE)
|
||||
{
|
||||
if (g_ogl_config.bSupports2DTextureStorageMultisample)
|
||||
glTexStorage2DMultisample(texture_type, m_msaaSamples, internal_format, m_targetWidth,
|
||||
m_targetHeight, false);
|
||||
else
|
||||
glTexImage2DMultisample(texture_type, m_msaaSamples, internal_format, m_targetWidth,
|
||||
m_targetHeight, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("Unhandled texture type %d", texture_type);
|
||||
}
|
||||
glBindTexture(texture_type, 0);
|
||||
return texture;
|
||||
}
|
||||
|
||||
void FramebufferManager::BindLayeredTexture(GLuint texture, const std::vector<GLuint>& framebuffers,
|
||||
GLenum attachment, GLenum texture_type)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffers[0]);
|
||||
FramebufferTexture(GL_FRAMEBUFFER, attachment, texture_type, texture, 0);
|
||||
// Bind all the other layers as separate FBOs for blitting.
|
||||
for (unsigned int i = 1; i < m_EFBLayers; i++)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffers[i]);
|
||||
glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, texture, 0, i);
|
||||
}
|
||||
}
|
||||
|
||||
bool FramebufferManager::HasStencilBuffer()
|
||||
{
|
||||
return m_enable_stencil_buffer;
|
||||
}
|
||||
|
||||
FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int msaaSamples,
|
||||
bool enable_stencil_buffer)
|
||||
{
|
||||
m_efbColor = 0;
|
||||
m_efbDepth = 0;
|
||||
m_efbColorSwap = 0;
|
||||
m_resolvedColorTexture = 0;
|
||||
m_resolvedDepthTexture = 0;
|
||||
|
||||
m_targetWidth = targetWidth;
|
||||
m_targetHeight = targetHeight;
|
||||
m_msaaSamples = msaaSamples;
|
||||
m_enable_stencil_buffer = enable_stencil_buffer;
|
||||
|
||||
// The EFB can be set to different pixel formats by the game through the
|
||||
// BPMEM_ZCOMPARE register (which should probably have a different name).
|
||||
// They are:
|
||||
// - 24-bit RGB (8-bit components) with 24-bit Z
|
||||
// - 24-bit RGBA (6-bit components) with 24-bit Z
|
||||
// - Multisampled 16-bit RGB (5-6-5 format) with 16-bit Z
|
||||
// We only use one EFB format here: 32-bit ARGB with 24-bit Z.
|
||||
// Multisampling depends on user settings.
|
||||
// The distinction becomes important for certain operations, i.e. the
|
||||
// alpha channel should be ignored if the EFB does not have one.
|
||||
|
||||
glActiveTexture(GL_TEXTURE9);
|
||||
|
||||
m_EFBLayers = (g_ActiveConfig.stereo_mode != StereoMode::Off) ? 2 : 1;
|
||||
m_efbFramebuffer.resize(m_EFBLayers);
|
||||
m_resolvedFramebuffer.resize(m_EFBLayers);
|
||||
|
||||
GLenum depth_internal_format = GL_DEPTH_COMPONENT32F;
|
||||
GLenum depth_pixel_format = GL_DEPTH_COMPONENT;
|
||||
GLenum depth_data_type = GL_FLOAT;
|
||||
if (m_enable_stencil_buffer)
|
||||
{
|
||||
depth_internal_format = GL_DEPTH32F_STENCIL8;
|
||||
depth_pixel_format = GL_DEPTH_STENCIL;
|
||||
depth_data_type = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
|
||||
}
|
||||
|
||||
const bool multilayer = m_EFBLayers > 1;
|
||||
|
||||
if (m_msaaSamples <= 1)
|
||||
{
|
||||
m_textureType = GL_TEXTURE_2D_ARRAY;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only use a layered multisample texture if needed. Some drivers
|
||||
// slow down significantly with single-layered multisample textures.
|
||||
m_textureType = multilayer ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_MULTISAMPLE;
|
||||
|
||||
// Although we are able to access the multisampled texture directly, we don't do it
|
||||
// everywhere. The old way is to "resolve" this multisampled texture by copying it into a
|
||||
// non-sampled texture. This would lead to an unneeded copy of the EFB, so we are going to
|
||||
// avoid it. But as this job isn't done right now, we do need that texture for resolving:
|
||||
GLenum resolvedType = GL_TEXTURE_2D_ARRAY;
|
||||
|
||||
m_resolvedColorTexture = CreateTexture(resolvedType, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
|
||||
m_resolvedDepthTexture =
|
||||
CreateTexture(resolvedType, depth_internal_format, depth_pixel_format, depth_data_type);
|
||||
|
||||
// Bind resolved textures to resolved framebuffer.
|
||||
glGenFramebuffers(m_EFBLayers, m_resolvedFramebuffer.data());
|
||||
BindLayeredTexture(m_resolvedColorTexture, m_resolvedFramebuffer, GL_COLOR_ATTACHMENT0,
|
||||
resolvedType);
|
||||
BindLayeredTexture(m_resolvedDepthTexture, m_resolvedFramebuffer, GL_DEPTH_ATTACHMENT,
|
||||
resolvedType);
|
||||
if (m_enable_stencil_buffer)
|
||||
BindLayeredTexture(m_resolvedDepthTexture, m_resolvedFramebuffer, GL_STENCIL_ATTACHMENT,
|
||||
resolvedType);
|
||||
}
|
||||
|
||||
m_efbColor = CreateTexture(m_textureType, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
|
||||
m_efbDepth =
|
||||
CreateTexture(m_textureType, depth_internal_format, depth_pixel_format, depth_data_type);
|
||||
m_efbColorSwap = CreateTexture(m_textureType, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
|
||||
|
||||
// Bind target textures to EFB framebuffer.
|
||||
glGenFramebuffers(m_EFBLayers, m_efbFramebuffer.data());
|
||||
BindLayeredTexture(m_efbColor, m_efbFramebuffer, GL_COLOR_ATTACHMENT0, m_textureType);
|
||||
BindLayeredTexture(m_efbDepth, m_efbFramebuffer, GL_DEPTH_ATTACHMENT, m_textureType);
|
||||
if (m_enable_stencil_buffer)
|
||||
BindLayeredTexture(m_efbDepth, m_efbFramebuffer, GL_STENCIL_ATTACHMENT, m_textureType);
|
||||
|
||||
// EFB framebuffer is currently bound, make sure to clear it before use.
|
||||
glViewport(0, 0, m_targetWidth, m_targetHeight);
|
||||
glScissor(0, 0, m_targetWidth, m_targetHeight);
|
||||
glClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
glClearDepthf(1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
if (m_enable_stencil_buffer)
|
||||
{
|
||||
glClearStencil(0);
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
}
|
||||
|
||||
// reinterpret pixel format
|
||||
std::string vs = GLSL_REINTERPRET_PIXELFMT_VS;
|
||||
|
||||
// The way to sample the EFB is based on the on the current configuration.
|
||||
// As we use the same sampling way for both interpreting shaders, the sampling
|
||||
// shader are generated first:
|
||||
std::string sampler;
|
||||
|
||||
if (m_msaaSamples <= 1)
|
||||
{
|
||||
// non-msaa, so just fetch the pixel
|
||||
sampler = StringFromFormat(GLSL_SHADER_FS, multilayer, false);
|
||||
}
|
||||
else if (g_ActiveConfig.backend_info.bSupportsSSAA)
|
||||
{
|
||||
// msaa + sample shading available, so just fetch the sample
|
||||
// This will lead to sample shading, but it's the only way to not loose
|
||||
// the values of each sample.
|
||||
sampler = StringFromFormat(GLSL_SHADER_FS, multilayer, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// msaa without sample shading: calculate the mean value of the pixel
|
||||
sampler = StringFromFormat(GLSL_SAMPLE_EFB_FS, multilayer, m_msaaSamples, m_msaaSamples);
|
||||
}
|
||||
|
||||
std::string ps_rgba6_to_rgb8 = sampler + GLSL_RGBA6_TO_RGB8_FS;
|
||||
|
||||
std::string ps_rgb8_to_rgba6 = sampler + GLSL_RGB8_TO_RGBA6_FS;
|
||||
|
||||
std::string gs = StringFromFormat(GLSL_GS, m_EFBLayers * 3, m_EFBLayers);
|
||||
|
||||
ProgramShaderCache::CompileShader(m_pixel_format_shaders[0], vs, ps_rgb8_to_rgba6,
|
||||
multilayer ? gs : "");
|
||||
ProgramShaderCache::CompileShader(m_pixel_format_shaders[1], vs, ps_rgba6_to_rgb8,
|
||||
multilayer ? gs : "");
|
||||
|
||||
const auto prefix = multilayer ? "g" : "v";
|
||||
|
||||
ProgramShaderCache::CompileShader(
|
||||
m_EfbPokes, StringFromFormat(GLSL_EFB_POKE_VERTEX_VS, m_targetWidth),
|
||||
|
||||
StringFromFormat(GLSL_EFB_POKE_PIXEL_FS, prefix, prefix, prefix, prefix),
|
||||
|
||||
multilayer ?
|
||||
StringFromFormat(GLSL_EFB_POKE_GEOMETRY_GS, m_EFBLayers, m_EFBLayers, m_targetWidth) :
|
||||
"");
|
||||
glGenBuffers(1, &m_EfbPokes_VBO);
|
||||
glGenVertexArrays(1, &m_EfbPokes_VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_EfbPokes_VBO);
|
||||
glBindVertexArray(m_EfbPokes_VAO);
|
||||
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_UNSIGNED_SHORT, 0, sizeof(EfbPokeData),
|
||||
(void*)offsetof(EfbPokeData, x));
|
||||
glEnableVertexAttribArray(SHADER_COLOR0_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_COLOR0_ATTRIB, 4, GL_UNSIGNED_BYTE, 1, sizeof(EfbPokeData),
|
||||
(void*)offsetof(EfbPokeData, data));
|
||||
glEnableVertexAttribArray(SHADER_COLOR1_ATTRIB);
|
||||
glVertexAttribIPointer(SHADER_COLOR1_ATTRIB, 1, GL_INT, sizeof(EfbPokeData),
|
||||
(void*)offsetof(EfbPokeData, data));
|
||||
glBindBuffer(GL_ARRAY_BUFFER,
|
||||
static_cast<VertexManager*>(g_vertex_manager.get())->GetVertexBufferHandle());
|
||||
|
||||
if (!static_cast<Renderer*>(g_renderer.get())->IsGLES())
|
||||
glEnable(GL_PROGRAM_POINT_SIZE);
|
||||
}
|
||||
|
||||
FramebufferManager::~FramebufferManager()
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
GLuint glObj[3];
|
||||
|
||||
// Note: OpenGL deletion functions silently ignore parameters of "0".
|
||||
|
||||
glDeleteFramebuffers(m_EFBLayers, m_efbFramebuffer.data());
|
||||
glDeleteFramebuffers(m_EFBLayers, m_resolvedFramebuffer.data());
|
||||
|
||||
// Required, as these are static class members
|
||||
m_efbFramebuffer.clear();
|
||||
m_resolvedFramebuffer.clear();
|
||||
|
||||
glObj[0] = m_resolvedColorTexture;
|
||||
glObj[1] = m_resolvedDepthTexture;
|
||||
glDeleteTextures(2, glObj);
|
||||
m_resolvedColorTexture = 0;
|
||||
m_resolvedDepthTexture = 0;
|
||||
|
||||
glObj[0] = m_efbColor;
|
||||
glObj[1] = m_efbDepth;
|
||||
glObj[2] = m_efbColorSwap;
|
||||
glDeleteTextures(3, glObj);
|
||||
m_efbColor = 0;
|
||||
m_efbDepth = 0;
|
||||
m_efbColorSwap = 0;
|
||||
|
||||
// reinterpret pixel format
|
||||
m_pixel_format_shaders[0].Destroy();
|
||||
m_pixel_format_shaders[1].Destroy();
|
||||
|
||||
// EFB pokes
|
||||
glDeleteBuffers(1, &m_EfbPokes_VBO);
|
||||
glDeleteVertexArrays(1, &m_EfbPokes_VAO);
|
||||
m_EfbPokes_VBO = 0;
|
||||
m_EfbPokes_VAO = 0;
|
||||
m_EfbPokes.Destroy();
|
||||
}
|
||||
|
||||
GLuint FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc)
|
||||
{
|
||||
if (m_msaaSamples <= 1)
|
||||
{
|
||||
return m_efbColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Transfer the EFB to a resolved texture. EXT_framebuffer_blit is
|
||||
// required.
|
||||
|
||||
TargetRectangle targetRc = g_renderer->ConvertEFBRectangle(sourceRc);
|
||||
targetRc.ClampUL(0, 0, m_targetWidth, m_targetHeight);
|
||||
|
||||
// Resolve.
|
||||
for (unsigned int i = 0; i < m_EFBLayers; i++)
|
||||
{
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer[i]);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer[i]);
|
||||
glBlitFramebuffer(targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, targetRc.left,
|
||||
targetRc.top, targetRc.right, targetRc.bottom, GL_COLOR_BUFFER_BIT,
|
||||
GL_NEAREST);
|
||||
}
|
||||
|
||||
// Return to EFB.
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[0]);
|
||||
|
||||
return m_resolvedColorTexture;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint FramebufferManager::GetEFBDepthTexture(const EFBRectangle& sourceRc)
|
||||
{
|
||||
if (m_msaaSamples <= 1)
|
||||
{
|
||||
return m_efbDepth;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Transfer the EFB to a resolved texture.
|
||||
|
||||
TargetRectangle targetRc = g_renderer->ConvertEFBRectangle(sourceRc);
|
||||
targetRc.ClampUL(0, 0, m_targetWidth, m_targetHeight);
|
||||
|
||||
// Resolve.
|
||||
for (unsigned int i = 0; i < m_EFBLayers; i++)
|
||||
{
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer[i]);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer[i]);
|
||||
glBlitFramebuffer(targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, targetRc.left,
|
||||
targetRc.top, targetRc.right, targetRc.bottom, GL_DEPTH_BUFFER_BIT,
|
||||
GL_NEAREST);
|
||||
}
|
||||
|
||||
// Return to EFB.
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[0]);
|
||||
|
||||
return m_resolvedDepthTexture;
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManager::ResolveEFBStencilTexture()
|
||||
{
|
||||
if (m_msaaSamples <= 1)
|
||||
return;
|
||||
|
||||
// Resolve.
|
||||
for (unsigned int i = 0; i < m_EFBLayers; i++)
|
||||
{
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer[i]);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer[i]);
|
||||
glBlitFramebuffer(0, 0, m_targetWidth, m_targetHeight, 0, 0, m_targetWidth, m_targetHeight,
|
||||
GL_STENCIL_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
|
||||
// Return to EFB.
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[0]);
|
||||
}
|
||||
|
||||
GLuint FramebufferManager::GetResolvedFramebuffer()
|
||||
{
|
||||
if (m_msaaSamples <= 1)
|
||||
return m_efbFramebuffer[0];
|
||||
return m_resolvedFramebuffer[0];
|
||||
}
|
||||
|
||||
void FramebufferManager::SetFramebuffer(GLuint fb)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb != 0 ? fb : GetEFBFramebuffer());
|
||||
}
|
||||
|
||||
void FramebufferManager::FramebufferTexture(GLenum target, GLenum attachment, GLenum textarget,
|
||||
GLuint texture, GLint level)
|
||||
{
|
||||
if (textarget == GL_TEXTURE_2D_ARRAY || textarget == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
|
||||
{
|
||||
if (m_EFBLayers > 1)
|
||||
glFramebufferTexture(target, attachment, texture, level);
|
||||
else
|
||||
glFramebufferTextureLayer(target, attachment, texture, level, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
glFramebufferTexture2D(target, attachment, textarget, texture, level);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply AA if enabled
|
||||
GLuint FramebufferManager::ResolveAndGetRenderTarget(const EFBRectangle& source_rect)
|
||||
{
|
||||
return GetEFBColorTexture(source_rect);
|
||||
}
|
||||
|
||||
GLuint FramebufferManager::ResolveAndGetDepthTarget(const EFBRectangle& source_rect)
|
||||
{
|
||||
return GetEFBDepthTexture(source_rect);
|
||||
}
|
||||
|
||||
void FramebufferManager::ReinterpretPixelData(unsigned int convtype)
|
||||
{
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
GLuint src_texture = 0;
|
||||
|
||||
// We aren't allowed to render and sample the same texture in one draw call,
|
||||
// so we have to create a new texture and overwrite it completely.
|
||||
// To not allocate one big texture every time, we've allocated two on
|
||||
// initialization and just swap them here:
|
||||
src_texture = m_efbColor;
|
||||
m_efbColor = m_efbColorSwap;
|
||||
m_efbColorSwap = src_texture;
|
||||
FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_textureType, m_efbColor, 0);
|
||||
|
||||
glViewport(0, 0, m_targetWidth, m_targetHeight);
|
||||
glActiveTexture(GL_TEXTURE9);
|
||||
glBindTexture(m_textureType, src_texture);
|
||||
g_sampler_cache->BindNearestSampler(9);
|
||||
|
||||
m_pixel_format_shaders[convtype ? 1 : 0].Bind();
|
||||
ProgramShaderCache::BindVertexFormat(nullptr);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
glBindTexture(m_textureType, 0);
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
void FramebufferManager::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points)
|
||||
{
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
if (type == EFBAccessType::PokeZ)
|
||||
{
|
||||
glDepthMask(GL_TRUE);
|
||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
}
|
||||
|
||||
glBindVertexArray(m_EfbPokes_VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_EfbPokes_VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(EfbPokeData) * num_points, points, GL_STREAM_DRAW);
|
||||
m_EfbPokes.Bind();
|
||||
glViewport(0, 0, m_targetWidth, m_targetHeight);
|
||||
glDrawArrays(GL_POINTS, 0, (GLsizei)num_points);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER,
|
||||
static_cast<VertexManager*>(g_vertex_manager.get())->GetVertexBufferHandle());
|
||||
g_renderer->RestoreAPIState();
|
||||
|
||||
// TODO: Could just update the EFB cache with the new value
|
||||
ClearEFBCache();
|
||||
}
|
||||
|
||||
} // namespace OGL
|
|
@ -1,127 +0,0 @@
|
|||
// Copyright 2009 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GL/GLUtil.h"
|
||||
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||
#include "VideoBackends/OGL/Render.h"
|
||||
#include "VideoCommon/FramebufferManagerBase.h"
|
||||
|
||||
// On the GameCube, the game sends a request for the graphics processor to
|
||||
// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM
|
||||
// called the XFB (External Framebuffer). The size and location of the XFB is
|
||||
// decided at the time of the copy, and the format is always YUYV. The video
|
||||
// interface is given a pointer to the XFB, which will be decoded and
|
||||
// displayed on the TV.
|
||||
//
|
||||
// There are two ways for Dolphin to emulate this:
|
||||
//
|
||||
// Real XFB mode:
|
||||
//
|
||||
// Dolphin will behave like the GameCube and encode the EFB to
|
||||
// a portion of GameCube RAM. The emulated video interface will decode the data
|
||||
// for output to the screen.
|
||||
//
|
||||
// Advantages: Behaves exactly like the GameCube.
|
||||
// Disadvantages: Resolution will be limited.
|
||||
//
|
||||
// Virtual XFB mode:
|
||||
//
|
||||
// When a request is made to copy the EFB to an XFB, Dolphin
|
||||
// will remember the RAM location and size of the XFB in a Virtual XFB list.
|
||||
// The video interface will look up the XFB in the list and use the enhanced
|
||||
// data stored there, if available.
|
||||
//
|
||||
// Advantages: Enables high resolution graphics, better than real hardware.
|
||||
// Disadvantages: If the GameCube CPU writes directly to the XFB (which is
|
||||
// possible but uncommon), the Virtual XFB will not capture this information.
|
||||
|
||||
// There may be multiple XFBs in GameCube RAM. This is the maximum number to
|
||||
// virtualize.
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
class FramebufferManager : public FramebufferManagerBase
|
||||
{
|
||||
public:
|
||||
FramebufferManager(int targetWidth, int targetHeight, int msaaSamples,
|
||||
bool enable_stencil_buffer);
|
||||
~FramebufferManager();
|
||||
|
||||
// To get the EFB in texture form, these functions may have to transfer
|
||||
// the EFB to a resolved texture first.
|
||||
static GLuint GetEFBColorTexture(const EFBRectangle& sourceRc);
|
||||
static GLuint GetEFBDepthTexture(const EFBRectangle& sourceRc);
|
||||
static void ResolveEFBStencilTexture();
|
||||
|
||||
static GLuint GetEFBFramebuffer(unsigned int layer = 0)
|
||||
{
|
||||
return (layer < m_EFBLayers) ? m_efbFramebuffer[layer] : m_efbFramebuffer.back();
|
||||
}
|
||||
// Resolved framebuffer is only used in MSAA mode.
|
||||
static GLuint GetResolvedFramebuffer();
|
||||
static void SetFramebuffer(GLuint fb);
|
||||
static void FramebufferTexture(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
|
||||
GLint level);
|
||||
|
||||
// If in MSAA mode, this will perform a resolve of the specified rectangle, and return the resolve
|
||||
// target as a texture ID.
|
||||
// Thus, this call may be expensive. Don't repeat it unnecessarily.
|
||||
// If not in MSAA mode, will just return the render target texture ID.
|
||||
// After calling this, before you render anything else, you MUST bind the framebuffer you want to
|
||||
// draw to.
|
||||
static GLuint ResolveAndGetRenderTarget(const EFBRectangle& rect);
|
||||
|
||||
// Same as above but for the depth Target.
|
||||
// After calling this, before you render anything else, you MUST bind the framebuffer you want to
|
||||
// draw to.
|
||||
static GLuint ResolveAndGetDepthTarget(const EFBRectangle& rect);
|
||||
|
||||
// Convert EFB content on pixel format change.
|
||||
// convtype=0 -> rgb8->rgba6, convtype=2 -> rgba6->rgb8
|
||||
static void ReinterpretPixelData(unsigned int convtype);
|
||||
|
||||
static void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points);
|
||||
static bool HasStencilBuffer();
|
||||
|
||||
private:
|
||||
GLuint CreateTexture(GLenum texture_type, GLenum internal_format, GLenum pixel_format,
|
||||
GLenum data_type);
|
||||
void BindLayeredTexture(GLuint texture, const std::vector<GLuint>& framebuffers,
|
||||
GLenum attachment, GLenum texture_type);
|
||||
|
||||
static int m_targetWidth;
|
||||
static int m_targetHeight;
|
||||
static int m_msaaSamples;
|
||||
|
||||
static GLenum m_textureType;
|
||||
static std::vector<GLuint> m_efbFramebuffer;
|
||||
static GLuint m_efbColor;
|
||||
static GLuint m_efbDepth;
|
||||
static GLuint
|
||||
m_efbColorSwap; // will be hot swapped with m_efbColor when reinterpreting EFB pixel formats
|
||||
|
||||
static bool m_enable_stencil_buffer;
|
||||
|
||||
// Only used in MSAA mode, TODO: try to avoid them
|
||||
static std::vector<GLuint> m_resolvedFramebuffer;
|
||||
static GLuint m_resolvedColorTexture;
|
||||
static GLuint m_resolvedDepthTexture;
|
||||
|
||||
// For pixel format draw
|
||||
static SHADER m_pixel_format_shaders[2];
|
||||
|
||||
// For EFB pokes
|
||||
static GLuint m_EfbPokes_VBO;
|
||||
static GLuint m_EfbPokes_VAO;
|
||||
static SHADER m_EfbPokes;
|
||||
};
|
||||
|
||||
} // namespace OGL
|
|
@ -7,6 +7,7 @@
|
|||
#include "Common/MsgHandler.h"
|
||||
|
||||
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||
#include "VideoBackends/OGL/Render.h"
|
||||
#include "VideoBackends/OGL/VertexManager.h"
|
||||
|
||||
#include "VideoCommon/NativeVertexFormat.h"
|
||||
|
@ -18,7 +19,7 @@
|
|||
namespace OGL
|
||||
{
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
{
|
||||
return std::make_unique<GLVertexFormat>(vtx_decl);
|
||||
}
|
||||
|
@ -44,10 +45,10 @@ static void SetPointer(u32 attrib, u32 stride, const AttributeFormat& format)
|
|||
(u8*)nullptr + format.offset);
|
||||
}
|
||||
|
||||
GLVertexFormat::GLVertexFormat(const PortableVertexDeclaration& _vtx_decl)
|
||||
GLVertexFormat::GLVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
: NativeVertexFormat(vtx_decl)
|
||||
{
|
||||
this->vtx_decl = _vtx_decl;
|
||||
u32 vertex_stride = _vtx_decl.stride;
|
||||
u32 vertex_stride = vtx_decl.stride;
|
||||
|
||||
// We will not allow vertex components causing uneven strides.
|
||||
if (vertex_stride & 3)
|
||||
|
@ -63,22 +64,22 @@ GLVertexFormat::GLVertexFormat(const PortableVertexDeclaration& _vtx_decl)
|
|||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vm->GetIndexBufferHandle());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vm->GetVertexBufferHandle());
|
||||
|
||||
SetPointer(SHADER_POSITION_ATTRIB, vertex_stride, _vtx_decl.position);
|
||||
SetPointer(SHADER_POSITION_ATTRIB, vertex_stride, vtx_decl.position);
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
SetPointer(SHADER_NORM0_ATTRIB + i, vertex_stride, _vtx_decl.normals[i]);
|
||||
SetPointer(SHADER_NORM0_ATTRIB + i, vertex_stride, vtx_decl.normals[i]);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
SetPointer(SHADER_COLOR0_ATTRIB + i, vertex_stride, _vtx_decl.colors[i]);
|
||||
SetPointer(SHADER_COLOR0_ATTRIB + i, vertex_stride, vtx_decl.colors[i]);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
SetPointer(SHADER_TEXTURE0_ATTRIB + i, vertex_stride, _vtx_decl.texcoords[i]);
|
||||
SetPointer(SHADER_TEXTURE0_ATTRIB + i, vertex_stride, vtx_decl.texcoords[i]);
|
||||
|
||||
SetPointer(SHADER_POSMTX_ATTRIB, vertex_stride, _vtx_decl.posmtx);
|
||||
SetPointer(SHADER_POSMTX_ATTRIB, vertex_stride, vtx_decl.posmtx);
|
||||
}
|
||||
|
||||
GLVertexFormat::~GLVertexFormat()
|
||||
{
|
||||
glDeleteVertexArrays(1, &VAO);
|
||||
}
|
||||
}
|
||||
} // namespace OGL
|
||||
|
|
|
@ -40,17 +40,13 @@
|
|||
<ClCompile Include="OGLShader.cpp" />
|
||||
<ClCompile Include="OGLTexture.cpp" />
|
||||
<ClCompile Include="BoundingBox.cpp" />
|
||||
<ClCompile Include="FramebufferManager.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="NativeVertexFormat.cpp" />
|
||||
<ClCompile Include="PerfQuery.cpp" />
|
||||
<ClCompile Include="PostProcessing.cpp" />
|
||||
<ClCompile Include="ProgramShaderCache.cpp" />
|
||||
<ClCompile Include="Render.cpp" />
|
||||
<ClCompile Include="SamplerCache.cpp" />
|
||||
<ClCompile Include="StreamBuffer.cpp" />
|
||||
<ClCompile Include="TextureCache.cpp" />
|
||||
<ClCompile Include="TextureConverter.cpp" />
|
||||
<ClCompile Include="VertexManager.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -58,16 +54,12 @@
|
|||
<ClInclude Include="OGLShader.h" />
|
||||
<ClInclude Include="OGLTexture.h" />
|
||||
<ClInclude Include="BoundingBox.h" />
|
||||
<ClInclude Include="FramebufferManager.h" />
|
||||
<ClInclude Include="GPUTimer.h" />
|
||||
<ClInclude Include="PerfQuery.h" />
|
||||
<ClInclude Include="PostProcessing.h" />
|
||||
<ClInclude Include="ProgramShaderCache.h" />
|
||||
<ClInclude Include="Render.h" />
|
||||
<ClInclude Include="SamplerCache.h" />
|
||||
<ClInclude Include="StreamBuffer.h" />
|
||||
<ClInclude Include="TextureCache.h" />
|
||||
<ClInclude Include="TextureConverter.h" />
|
||||
<ClInclude Include="VertexManager.h" />
|
||||
<ClInclude Include="VideoBackend.h" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -18,21 +18,12 @@
|
|||
<ClCompile Include="VertexManager.cpp">
|
||||
<Filter>Decoder</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TextureConverter.cpp">
|
||||
<Filter>GLUtil</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="BoundingBox.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FramebufferManager.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PerfQuery.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PostProcessing.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ProgramShaderCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
|
@ -42,9 +33,6 @@
|
|||
<ClCompile Include="StreamBuffer.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TextureCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="SamplerCache.cpp" />
|
||||
<ClCompile Include="OGLTexture.cpp">
|
||||
|
@ -61,21 +49,12 @@
|
|||
<ClInclude Include="VertexManager.h">
|
||||
<Filter>Decoder</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TextureConverter.h">
|
||||
<Filter>GLUtil</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BoundingBox.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FramebufferManager.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PerfQuery.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PostProcessing.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ProgramShaderCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
|
@ -85,9 +64,6 @@
|
|||
<ClInclude Include="StreamBuffer.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TextureCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SamplerCache.h" />
|
||||
<ClInclude Include="VideoBackend.h" />
|
||||
<ClInclude Include="GPUTimer.h">
|
||||
|
|
|
@ -24,23 +24,24 @@ static GLenum GetGLShaderTypeForStage(ShaderStage stage)
|
|||
}
|
||||
}
|
||||
|
||||
OGLShader::OGLShader(ShaderStage stage, GLenum gl_type, GLuint shader_id)
|
||||
: AbstractShader(stage), m_type(gl_type), m_id(shader_id)
|
||||
OGLShader::OGLShader(ShaderStage stage, GLenum gl_type, GLuint gl_id)
|
||||
: AbstractShader(stage), m_id(ProgramShaderCache::GenerateShaderID()), m_type(gl_type),
|
||||
m_gl_id(gl_id)
|
||||
{
|
||||
}
|
||||
|
||||
OGLShader::OGLShader(GLuint compute_program_id)
|
||||
: AbstractShader(ShaderStage::Compute), m_type(GL_COMPUTE_SHADER),
|
||||
m_compute_program_id(compute_program_id)
|
||||
OGLShader::OGLShader(GLuint gl_compute_program_id)
|
||||
: AbstractShader(ShaderStage::Compute), m_id(ProgramShaderCache::GenerateShaderID()),
|
||||
m_type(GL_COMPUTE_SHADER), m_gl_compute_program_id(gl_compute_program_id)
|
||||
{
|
||||
}
|
||||
|
||||
OGLShader::~OGLShader()
|
||||
{
|
||||
if (m_stage != ShaderStage::Compute)
|
||||
glDeleteShader(m_id);
|
||||
glDeleteShader(m_gl_id);
|
||||
else
|
||||
glDeleteProgram(m_compute_program_id);
|
||||
glDeleteProgram(m_gl_compute_program_id);
|
||||
}
|
||||
|
||||
bool OGLShader::HasBinary() const
|
||||
|
|
|
@ -16,13 +16,14 @@ namespace OGL
|
|||
class OGLShader final : public AbstractShader
|
||||
{
|
||||
public:
|
||||
explicit OGLShader(ShaderStage stage, GLenum gl_type, GLuint shader_id);
|
||||
explicit OGLShader(GLuint compute_program_id);
|
||||
explicit OGLShader(ShaderStage stage, GLenum gl_type, GLuint gl_id);
|
||||
explicit OGLShader(GLuint gl_compute_program_id);
|
||||
~OGLShader() override;
|
||||
|
||||
u64 GetID() const { return m_id; }
|
||||
GLenum GetGLShaderType() const { return m_type; }
|
||||
GLuint GetGLShaderID() const { return m_id; }
|
||||
GLuint GetGLComputeProgramID() const { return m_compute_program_id; }
|
||||
GLuint GetGLShaderID() const { return m_gl_id; }
|
||||
GLuint GetGLComputeProgramID() const { return m_gl_compute_program_id; }
|
||||
bool HasBinary() const override;
|
||||
BinaryData GetBinary() const override;
|
||||
|
||||
|
@ -30,9 +31,10 @@ public:
|
|||
size_t length);
|
||||
|
||||
private:
|
||||
u64 m_id;
|
||||
GLenum m_type;
|
||||
GLuint m_id = 0;
|
||||
GLuint m_compute_program_id = 0;
|
||||
GLuint m_gl_id = 0;
|
||||
GLuint m_gl_compute_program_id = 0;
|
||||
};
|
||||
|
||||
} // namespace OGL
|
||||
|
|
|
@ -6,13 +6,8 @@
|
|||
#include "Common/CommonTypes.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
#include "VideoBackends/OGL/FramebufferManager.h"
|
||||
#include "VideoBackends/OGL/OGLTexture.h"
|
||||
#include "VideoBackends/OGL/SamplerCache.h"
|
||||
#include "VideoBackends/OGL/TextureCache.h"
|
||||
|
||||
#include "VideoCommon/ImageWrite.h"
|
||||
#include "VideoCommon/TextureConfig.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
@ -115,10 +110,9 @@ OGLTexture::OGLTexture(const TextureConfig& tex_config) : AbstractTexture(tex_co
|
|||
DEBUG_ASSERT_MSG(VIDEO, !tex_config.IsMultisampled() || tex_config.levels == 1,
|
||||
"OpenGL does not support multisampled textures with mip levels");
|
||||
|
||||
GLenum target =
|
||||
tex_config.IsMultisampled() ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY;
|
||||
const GLenum target = GetGLTarget();
|
||||
glGenTextures(1, &m_texId);
|
||||
glActiveTexture(GL_TEXTURE9);
|
||||
glActiveTexture(GL_MUTABLE_TEXTURE_INDEX);
|
||||
glBindTexture(target, m_texId);
|
||||
|
||||
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, m_config.levels - 1);
|
||||
|
@ -139,7 +133,7 @@ OGLTexture::OGLTexture(const TextureConfig& tex_config) : AbstractTexture(tex_co
|
|||
m_config.layers);
|
||||
}
|
||||
|
||||
if (m_config.rendertarget)
|
||||
if (m_config.IsRenderTarget())
|
||||
{
|
||||
// We can't render to compressed formats.
|
||||
ASSERT(!IsCompressedFormat(m_config.format));
|
||||
|
@ -147,40 +141,19 @@ OGLTexture::OGLTexture(const TextureConfig& tex_config) : AbstractTexture(tex_co
|
|||
{
|
||||
for (u32 level = 0; level < m_config.levels; level++)
|
||||
{
|
||||
glTexImage3D(target, level, GL_RGBA, std::max(m_config.width >> level, 1u),
|
||||
std::max(m_config.height >> level, 1u), m_config.layers, 0, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexImage3D(target, level, gl_internal_format, std::max(m_config.width >> level, 1u),
|
||||
std::max(m_config.height >> level, 1u), m_config.layers, 0,
|
||||
GetGLFormatForTextureFormat(m_config.format),
|
||||
GetGLTypeForTextureFormat(m_config.format), nullptr);
|
||||
}
|
||||
}
|
||||
glGenFramebuffers(1, &m_framebuffer);
|
||||
FramebufferManager::SetFramebuffer(m_framebuffer);
|
||||
FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, m_texId,
|
||||
0);
|
||||
|
||||
// We broke the framebuffer binding here, and need to restore it, as the CreateTexture
|
||||
// method is in the base renderer class and can be called by VideoCommon.
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
}
|
||||
}
|
||||
|
||||
OGLTexture::~OGLTexture()
|
||||
{
|
||||
g_renderer->UnbindTexture(this);
|
||||
if (m_texId)
|
||||
glDeleteTextures(1, &m_texId);
|
||||
|
||||
if (m_framebuffer)
|
||||
glDeleteFramebuffers(1, &m_framebuffer);
|
||||
}
|
||||
|
||||
GLuint OGLTexture::GetRawTexIdentifier() const
|
||||
{
|
||||
return m_texId;
|
||||
}
|
||||
|
||||
GLuint OGLTexture::GetFramebuffer() const
|
||||
{
|
||||
return m_framebuffer;
|
||||
Renderer::GetInstance()->UnbindTexture(this);
|
||||
glDeleteTextures(1, &m_texId);
|
||||
}
|
||||
|
||||
void OGLTexture::CopyRectangleFromTexture(const AbstractTexture* src,
|
||||
|
@ -188,19 +161,18 @@ void OGLTexture::CopyRectangleFromTexture(const AbstractTexture* src,
|
|||
u32 src_level, const MathUtil::Rectangle<int>& dst_rect,
|
||||
u32 dst_layer, u32 dst_level)
|
||||
{
|
||||
const OGLTexture* srcentry = static_cast<const OGLTexture*>(src);
|
||||
const OGLTexture* src_gltex = static_cast<const OGLTexture*>(src);
|
||||
ASSERT(src_rect.GetWidth() == dst_rect.GetWidth() &&
|
||||
src_rect.GetHeight() == dst_rect.GetHeight());
|
||||
if (g_ogl_config.bSupportsCopySubImage)
|
||||
{
|
||||
glCopyImageSubData(srcentry->m_texId, GL_TEXTURE_2D_ARRAY, src_level, src_rect.left,
|
||||
src_rect.top, src_layer, m_texId, GL_TEXTURE_2D_ARRAY, dst_level,
|
||||
dst_rect.left, dst_rect.top, dst_layer, dst_rect.GetWidth(),
|
||||
dst_rect.GetHeight(), 1);
|
||||
glCopyImageSubData(src_gltex->m_texId, src_gltex->GetGLTarget(), src_level, src_rect.left,
|
||||
src_rect.top, src_layer, m_texId, GetGLTarget(), dst_level, dst_rect.left,
|
||||
dst_rect.top, dst_layer, dst_rect.GetWidth(), dst_rect.GetHeight(), 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
BlitFramebuffer(const_cast<OGLTexture*>(srcentry), src_rect, src_layer, src_level, dst_rect,
|
||||
BlitFramebuffer(const_cast<OGLTexture*>(src_gltex), src_rect, src_layer, src_level, dst_rect,
|
||||
dst_layer, dst_level);
|
||||
}
|
||||
}
|
||||
|
@ -210,28 +182,12 @@ void OGLTexture::BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle
|
|||
const MathUtil::Rectangle<int>& dst_rect, u32 dst_layer,
|
||||
u32 dst_level)
|
||||
{
|
||||
// If it isn't a single leveled/layered texture, we need to update the framebuffer.
|
||||
bool update_src_framebuffer =
|
||||
srcentry->m_framebuffer == 0 || srcentry->m_config.layers != 0 || src_level != 0;
|
||||
bool update_dst_framebuffer = m_framebuffer == 0 || m_config.layers != 0 || dst_level != 0;
|
||||
if (!m_framebuffer)
|
||||
glGenFramebuffers(1, &m_framebuffer);
|
||||
if (!srcentry->m_framebuffer)
|
||||
glGenFramebuffers(1, &const_cast<OGLTexture*>(srcentry)->m_framebuffer);
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcentry->m_framebuffer);
|
||||
if (update_src_framebuffer)
|
||||
{
|
||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcentry->m_texId,
|
||||
src_level, src_layer);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_framebuffer);
|
||||
if (update_dst_framebuffer)
|
||||
{
|
||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level,
|
||||
dst_layer);
|
||||
}
|
||||
Renderer::GetInstance()->BindSharedReadFramebuffer();
|
||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcentry->m_texId, src_level,
|
||||
src_layer);
|
||||
Renderer::GetInstance()->BindSharedDrawFramebuffer();
|
||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level,
|
||||
dst_layer);
|
||||
|
||||
// glBlitFramebuffer is still affected by the scissor test, which is enabled by default.
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
@ -239,50 +195,10 @@ void OGLTexture::BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle
|
|||
glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left,
|
||||
dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
if (update_src_framebuffer)
|
||||
{
|
||||
FramebufferManager::FramebufferTexture(
|
||||
GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
srcentry->m_config.IsMultisampled() ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY,
|
||||
srcentry->m_texId, 0);
|
||||
}
|
||||
if (update_dst_framebuffer)
|
||||
{
|
||||
FramebufferManager::FramebufferTexture(
|
||||
GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
m_config.IsMultisampled() ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY, m_texId,
|
||||
0);
|
||||
}
|
||||
|
||||
// The default state for the scissor test is enabled. We don't need to do a full state
|
||||
// restore, as the framebuffer and scissor test are the only things we changed.
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
}
|
||||
|
||||
void OGLTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
const MathUtil::Rectangle<int>& srcrect,
|
||||
const MathUtil::Rectangle<int>& dstrect)
|
||||
{
|
||||
const OGLTexture* srcentry = static_cast<const OGLTexture*>(source);
|
||||
if (!m_framebuffer)
|
||||
{
|
||||
glGenFramebuffers(1, &m_framebuffer);
|
||||
FramebufferManager::SetFramebuffer(m_framebuffer);
|
||||
FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D_ARRAY, m_texId, 0);
|
||||
}
|
||||
g_renderer->ResetAPIState();
|
||||
FramebufferManager::SetFramebuffer(m_framebuffer);
|
||||
glActiveTexture(GL_TEXTURE9);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, srcentry->m_texId);
|
||||
g_sampler_cache->BindLinearSampler(9);
|
||||
glViewport(dstrect.left, dstrect.top, dstrect.GetWidth(), dstrect.GetHeight());
|
||||
TextureCache::GetInstance()->GetColorCopyProgram().Bind();
|
||||
glUniform4f(TextureCache::GetInstance()->GetColorCopyPositionUniform(), float(srcrect.left),
|
||||
float(srcrect.top), float(srcrect.GetWidth()), float(srcrect.GetHeight()));
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
g_renderer->RestoreAPIState();
|
||||
Renderer::GetInstance()->RestoreFramebufferBinding();
|
||||
}
|
||||
|
||||
void OGLTexture::ResolveFromTexture(const AbstractTexture* src,
|
||||
|
@ -307,8 +223,9 @@ void OGLTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8
|
|||
std::max(1u, m_config.width >> level), std::max(1u, m_config.height >> level), width,
|
||||
height);
|
||||
|
||||
glActiveTexture(GL_TEXTURE9);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texId);
|
||||
const GLenum target = GetGLTarget();
|
||||
glActiveTexture(GL_MUTABLE_TEXTURE_INDEX);
|
||||
glBindTexture(target, m_texId);
|
||||
|
||||
if (row_length != width)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
|
||||
|
@ -318,12 +235,12 @@ void OGLTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8
|
|||
{
|
||||
if (g_ogl_config.bSupportsTextureStorage)
|
||||
{
|
||||
glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, 0, width, height, 1,
|
||||
gl_internal_format, static_cast<GLsizei>(buffer_size), buffer);
|
||||
glCompressedTexSubImage3D(target, level, 0, 0, 0, width, height, 1, gl_internal_format,
|
||||
static_cast<GLsizei>(buffer_size), buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, level, gl_internal_format, width, height, 1, 0,
|
||||
glCompressedTexImage3D(target, level, gl_internal_format, width, height, 1, 0,
|
||||
static_cast<GLsizei>(buffer_size), buffer);
|
||||
}
|
||||
}
|
||||
|
@ -333,13 +250,12 @@ void OGLTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8
|
|||
GLenum gl_type = GetGLTypeForTextureFormat(m_config.format);
|
||||
if (g_ogl_config.bSupportsTextureStorage)
|
||||
{
|
||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, 0, width, height, 1, gl_format, gl_type,
|
||||
buffer);
|
||||
glTexSubImage3D(target, level, 0, 0, 0, width, height, 1, gl_format, gl_type, buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexImage3D(GL_TEXTURE_2D_ARRAY, level, gl_internal_format, width, height, 1, 0, gl_format,
|
||||
gl_type, buffer);
|
||||
glTexImage3D(target, level, gl_internal_format, width, height, 1, 0, gl_format, gl_type,
|
||||
buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -347,6 +263,11 @@ void OGLTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8
|
|||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
}
|
||||
|
||||
GLenum OGLTexture::GetGLFormatForImageTexture() const
|
||||
{
|
||||
return GetGLInternalFormatForTextureFormat(m_config.format, true);
|
||||
}
|
||||
|
||||
OGLStagingTexture::OGLStagingTexture(StagingTextureType type, const TextureConfig& config,
|
||||
GLenum target, GLuint buffer_name, size_t buffer_size,
|
||||
char* map_ptr, size_t map_stride)
|
||||
|
@ -405,8 +326,7 @@ std::unique_ptr<OGLStagingTexture> OGLStagingTexture::Create(StagingTextureType
|
|||
}
|
||||
|
||||
glBufferStorage(target, buffer_size, nullptr, buffer_flags);
|
||||
buffer_ptr =
|
||||
reinterpret_cast<char*>(glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, buffer_size, map_flags));
|
||||
buffer_ptr = reinterpret_cast<char*>(glMapBufferRange(target, 0, buffer_size, map_flags));
|
||||
ASSERT(buffer_ptr != nullptr);
|
||||
}
|
||||
else
|
||||
|
@ -426,7 +346,7 @@ void OGLStagingTexture::CopyFromTexture(const AbstractTexture* src,
|
|||
const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
|
||||
u32 src_level, const MathUtil::Rectangle<int>& dst_rect)
|
||||
{
|
||||
ASSERT(m_type == StagingTextureType::Readback);
|
||||
ASSERT(m_type == StagingTextureType::Readback || m_type == StagingTextureType::Mutable);
|
||||
ASSERT(src_rect.GetWidth() == dst_rect.GetWidth() &&
|
||||
src_rect.GetHeight() == dst_rect.GetHeight());
|
||||
ASSERT(src_rect.left >= 0 && static_cast<u32>(src_rect.right) <= src->GetConfig().width &&
|
||||
|
@ -443,40 +363,37 @@ void OGLStagingTexture::CopyFromTexture(const AbstractTexture* src,
|
|||
glPixelStorei(GL_PACK_ROW_LENGTH, m_config.width);
|
||||
|
||||
const OGLTexture* gltex = static_cast<const OGLTexture*>(src);
|
||||
size_t dst_offset = dst_rect.top * m_config.GetStride() + dst_rect.left * m_texel_size;
|
||||
const size_t dst_offset = dst_rect.top * m_config.GetStride() + dst_rect.left * m_texel_size;
|
||||
|
||||
// If we don't have a FBO associated with this texture, we need to use a slow path.
|
||||
if (gltex->GetFramebuffer() != 0 && src_layer == 0 && src_level == 0)
|
||||
// Prefer glGetTextureSubImage(), when available.
|
||||
if (g_ogl_config.bSupportsTextureSubImage)
|
||||
{
|
||||
// This texture has a framebuffer, so we can use glReadPixels().
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, gltex->GetFramebuffer());
|
||||
glReadPixels(src_rect.left, src_rect.top, src_rect.GetWidth(), src_rect.GetHeight(),
|
||||
GetGLFormatForTextureFormat(m_config.format),
|
||||
GetGLTypeForTextureFormat(m_config.format), reinterpret_cast<void*>(dst_offset));
|
||||
|
||||
// Reset both read/draw framebuffers.
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferManager::GetEFBFramebuffer());
|
||||
glGetTextureSubImage(
|
||||
gltex->GetGLTextureId(), src_level, src_rect.left, src_rect.top, src_layer,
|
||||
src_rect.GetWidth(), src_rect.GetHeight(), 1, GetGLFormatForTextureFormat(src->GetFormat()),
|
||||
GetGLTypeForTextureFormat(src->GetFormat()),
|
||||
static_cast<GLsizei>(m_buffer_size - dst_offset), reinterpret_cast<void*>(dst_offset));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_ogl_config.bSupportsTextureSubImage)
|
||||
// Mutate the shared framebuffer.
|
||||
Renderer::GetInstance()->BindSharedReadFramebuffer();
|
||||
if (AbstractTexture::IsDepthFormat(gltex->GetFormat()))
|
||||
{
|
||||
glGetTextureSubImage(
|
||||
gltex->GetRawTexIdentifier(), src_level, src_rect.left, src_rect.top, src_layer,
|
||||
src_rect.GetWidth(), src_rect.GetHeight(), 1,
|
||||
GetGLFormatForTextureFormat(m_config.format), GetGLTypeForTextureFormat(m_config.format),
|
||||
static_cast<GLsizei>(m_buffer_size - dst_offset), reinterpret_cast<void*>(dst_offset));
|
||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0, 0, 0);
|
||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, gltex->GetGLTextureId(),
|
||||
src_level, src_layer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Investigate whether it's faster to use glReadPixels() with a framebuffer, since we're
|
||||
// copying the whole texture, which may waste bandwidth. So we're trading CPU work in creating
|
||||
// the framebuffer for GPU work in copying potentially redundant texels.
|
||||
glActiveTexture(GL_TEXTURE9);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, gltex->GetRawTexIdentifier());
|
||||
glGetTexImage(GL_TEXTURE_2D_ARRAY, src_level, GetGLFormatForTextureFormat(m_config.format),
|
||||
GetGLTypeForTextureFormat(m_config.format), nullptr);
|
||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gltex->GetGLTextureId(),
|
||||
src_level, src_layer);
|
||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 0, 0, 0);
|
||||
}
|
||||
glReadPixels(src_rect.left, src_rect.top, src_rect.GetWidth(), src_rect.GetHeight(),
|
||||
GetGLFormatForTextureFormat(src->GetFormat()),
|
||||
GetGLTypeForTextureFormat(src->GetFormat()), reinterpret_cast<void*>(dst_offset));
|
||||
Renderer::GetInstance()->RestoreFramebufferBinding();
|
||||
}
|
||||
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
||||
|
@ -501,7 +418,7 @@ void OGLStagingTexture::CopyToTexture(const MathUtil::Rectangle<int>& src_rect,
|
|||
const MathUtil::Rectangle<int>& dst_rect, u32 dst_layer,
|
||||
u32 dst_level)
|
||||
{
|
||||
ASSERT(m_type == StagingTextureType::Upload);
|
||||
ASSERT(m_type == StagingTextureType::Upload || m_type == StagingTextureType::Mutable);
|
||||
ASSERT(src_rect.GetWidth() == dst_rect.GetWidth() &&
|
||||
src_rect.GetHeight() == dst_rect.GetHeight());
|
||||
ASSERT(src_rect.left >= 0 && static_cast<u32>(src_rect.right) <= m_config.width &&
|
||||
|
@ -509,8 +426,9 @@ void OGLStagingTexture::CopyToTexture(const MathUtil::Rectangle<int>& src_rect,
|
|||
ASSERT(dst_rect.left >= 0 && static_cast<u32>(dst_rect.right) <= dst->GetConfig().width &&
|
||||
dst_rect.top >= 0 && static_cast<u32>(dst_rect.bottom) <= dst->GetConfig().height);
|
||||
|
||||
size_t src_offset = src_rect.top * m_config.GetStride() + src_rect.left * m_texel_size;
|
||||
size_t copy_size = src_rect.GetHeight() * m_config.GetStride();
|
||||
const OGLTexture* gltex = static_cast<const OGLTexture*>(dst);
|
||||
const size_t src_offset = src_rect.top * m_config.GetStride() + src_rect.left * m_texel_size;
|
||||
const size_t copy_size = src_rect.GetHeight() * m_config.GetStride();
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_buffer_name);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, m_config.width);
|
||||
|
@ -533,12 +451,12 @@ void OGLStagingTexture::CopyToTexture(const MathUtil::Rectangle<int>& src_rect,
|
|||
}
|
||||
|
||||
// Copy from the staging buffer to the texture object.
|
||||
glActiveTexture(GL_TEXTURE9);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, static_cast<const OGLTexture*>(dst)->GetRawTexIdentifier());
|
||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, dst_rect.left, dst_rect.top, dst_layer,
|
||||
dst_rect.GetWidth(), dst_rect.GetHeight(), 1,
|
||||
GetGLFormatForTextureFormat(m_config.format),
|
||||
GetGLTypeForTextureFormat(m_config.format), reinterpret_cast<void*>(src_offset));
|
||||
const GLenum target = gltex->GetGLTarget();
|
||||
glActiveTexture(GL_MUTABLE_TEXTURE_INDEX);
|
||||
glBindTexture(target, gltex->GetGLTextureId());
|
||||
glTexSubImage3D(target, 0, dst_rect.left, dst_rect.top, dst_layer, dst_rect.GetWidth(),
|
||||
dst_rect.GetHeight(), 1, GetGLFormatForTextureFormat(dst->GetFormat()),
|
||||
GetGLTypeForTextureFormat(dst->GetFormat()), reinterpret_cast<void*>(src_offset));
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
|
||||
|
@ -602,10 +520,13 @@ void OGLStagingTexture::Unmap()
|
|||
m_map_pointer = nullptr;
|
||||
}
|
||||
|
||||
OGLFramebuffer::OGLFramebuffer(AbstractTextureFormat color_format,
|
||||
OGLFramebuffer::OGLFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
||||
AbstractTextureFormat color_format,
|
||||
AbstractTextureFormat depth_format, u32 width, u32 height,
|
||||
u32 layers, u32 samples, GLuint fbo)
|
||||
: AbstractFramebuffer(color_format, depth_format, width, height, layers, samples), m_fbo(fbo)
|
||||
: AbstractFramebuffer(color_attachment, depth_attachment, color_format, depth_format, width,
|
||||
height, layers, samples),
|
||||
m_fbo(fbo)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -614,8 +535,8 @@ OGLFramebuffer::~OGLFramebuffer()
|
|||
glDeleteFramebuffers(1, &m_fbo);
|
||||
}
|
||||
|
||||
std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(const OGLTexture* color_attachment,
|
||||
const OGLTexture* depth_attachment)
|
||||
std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(OGLTexture* color_attachment,
|
||||
OGLTexture* depth_attachment)
|
||||
{
|
||||
if (!ValidateConfig(color_attachment, depth_attachment))
|
||||
return nullptr;
|
||||
|
@ -638,13 +559,13 @@ std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(const OGLTexture* color_a
|
|||
{
|
||||
if (color_attachment->GetConfig().layers > 1)
|
||||
{
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
color_attachment->GetRawTexIdentifier(), 0);
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, color_attachment->GetGLTextureId(),
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
color_attachment->GetRawTexIdentifier(), 0, 0);
|
||||
color_attachment->GetGLTextureId(), 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -655,19 +576,26 @@ std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(const OGLTexture* color_a
|
|||
GL_DEPTH_ATTACHMENT;
|
||||
if (depth_attachment->GetConfig().layers > 1)
|
||||
{
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, attachment, depth_attachment->GetRawTexIdentifier(), 0);
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, attachment, depth_attachment->GetGLTextureId(), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, depth_attachment->GetRawTexIdentifier(),
|
||||
0, 0);
|
||||
glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, depth_attachment->GetGLTextureId(), 0,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
return std::make_unique<OGLFramebuffer>(color_format, depth_format, width, height, layers,
|
||||
samples, fbo);
|
||||
Renderer::GetInstance()->RestoreFramebufferBinding();
|
||||
|
||||
return std::make_unique<OGLFramebuffer>(color_attachment, depth_attachment, color_format,
|
||||
depth_format, width, height, layers, samples, fbo);
|
||||
}
|
||||
|
||||
void OGLFramebuffer::UpdateDimensions(u32 width, u32 height)
|
||||
{
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
}
|
||||
|
||||
} // namespace OGL
|
||||
|
|
|
@ -25,16 +25,17 @@ public:
|
|||
const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
|
||||
u32 src_level, const MathUtil::Rectangle<int>& dst_rect,
|
||||
u32 dst_layer, u32 dst_level) override;
|
||||
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
const MathUtil::Rectangle<int>& srcrect,
|
||||
const MathUtil::Rectangle<int>& dstrect) override;
|
||||
void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
|
||||
u32 layer, u32 level) override;
|
||||
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
size_t buffer_size) override;
|
||||
|
||||
GLuint GetRawTexIdentifier() const;
|
||||
GLuint GetFramebuffer() const;
|
||||
GLuint GetGLTextureId() const { return m_texId; }
|
||||
GLenum GetGLTarget() const
|
||||
{
|
||||
return IsMultisampled() ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY;
|
||||
}
|
||||
GLenum GetGLFormatForImageTexture() const;
|
||||
|
||||
private:
|
||||
void BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle<int>& src_rect,
|
||||
|
@ -42,7 +43,6 @@ private:
|
|||
u32 dst_layer, u32 dst_level);
|
||||
|
||||
GLuint m_texId;
|
||||
GLuint m_framebuffer = 0;
|
||||
};
|
||||
|
||||
class OGLStagingTexture final : public AbstractStagingTexture
|
||||
|
@ -79,13 +79,18 @@ private:
|
|||
class OGLFramebuffer final : public AbstractFramebuffer
|
||||
{
|
||||
public:
|
||||
OGLFramebuffer(AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
|
||||
OGLFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
||||
AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
|
||||
u32 height, u32 layers, u32 samples, GLuint fbo);
|
||||
~OGLFramebuffer() override;
|
||||
|
||||
static std::unique_ptr<OGLFramebuffer> Create(OGLTexture* color_attachment,
|
||||
OGLTexture* depth_attachment);
|
||||
|
||||
GLuint GetFBO() const { return m_fbo; }
|
||||
static std::unique_ptr<OGLFramebuffer> Create(const OGLTexture* color_attachment,
|
||||
const OGLTexture* depth_attachment);
|
||||
|
||||
// Used for updating the dimensions of the system/window framebuffer.
|
||||
void UpdateDimensions(u32 width, u32 height);
|
||||
|
||||
protected:
|
||||
GLuint m_fbo;
|
||||
|
|
|
@ -1,273 +0,0 @@
|
|||
// Copyright 2009 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/OGL/PostProcessing.h"
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/Config/GraphicsSettings.h"
|
||||
|
||||
#include "VideoBackends/OGL/FramebufferManager.h"
|
||||
#include "VideoBackends/OGL/OGLTexture.h"
|
||||
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||
#include "VideoBackends/OGL/SamplerCache.h"
|
||||
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
static const char s_vertex_shader[] = "out vec2 uv0;\n"
|
||||
"uniform vec4 src_rect;\n"
|
||||
"void main(void) {\n"
|
||||
" vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n"
|
||||
" gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n"
|
||||
" uv0 = vec2(mix(src_rect.xy, src_rect.zw, rawpos));\n"
|
||||
"}\n";
|
||||
|
||||
OpenGLPostProcessing::OpenGLPostProcessing() : m_initialized(false)
|
||||
{
|
||||
CreateHeader();
|
||||
}
|
||||
|
||||
OpenGLPostProcessing::~OpenGLPostProcessing()
|
||||
{
|
||||
m_shader.Destroy();
|
||||
}
|
||||
|
||||
void OpenGLPostProcessing::BlitFromTexture(TargetRectangle src, TargetRectangle dst,
|
||||
int src_texture, int src_width, int src_height,
|
||||
int layer)
|
||||
{
|
||||
ApplyShader();
|
||||
|
||||
glViewport(dst.left, dst.bottom, dst.GetWidth(), dst.GetHeight());
|
||||
|
||||
ProgramShaderCache::BindVertexFormat(nullptr);
|
||||
|
||||
m_shader.Bind();
|
||||
|
||||
glUniform4f(m_uniform_resolution, (float)src_width, (float)src_height, 1.0f / (float)src_width,
|
||||
1.0f / (float)src_height);
|
||||
glUniform4f(m_uniform_src_rect, src.left / (float)src_width, src.top / (float)src_height,
|
||||
src.right / (float)src_width, src.bottom / (float)src_height);
|
||||
glUniform1ui(m_uniform_time, (GLuint)m_timer.GetTimeElapsed());
|
||||
glUniform1i(m_uniform_layer, layer);
|
||||
|
||||
if (m_config.IsDirty())
|
||||
{
|
||||
for (auto& it : m_config.GetOptions())
|
||||
{
|
||||
if (it.second.m_dirty)
|
||||
{
|
||||
switch (it.second.m_type)
|
||||
{
|
||||
case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL:
|
||||
glUniform1i(m_uniform_bindings[it.first], it.second.m_bool_value);
|
||||
break;
|
||||
case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER:
|
||||
switch (it.second.m_integer_values.size())
|
||||
{
|
||||
case 1:
|
||||
glUniform1i(m_uniform_bindings[it.first], it.second.m_integer_values[0]);
|
||||
break;
|
||||
case 2:
|
||||
glUniform2i(m_uniform_bindings[it.first], it.second.m_integer_values[0],
|
||||
it.second.m_integer_values[1]);
|
||||
break;
|
||||
case 3:
|
||||
glUniform3i(m_uniform_bindings[it.first], it.second.m_integer_values[0],
|
||||
it.second.m_integer_values[1], it.second.m_integer_values[2]);
|
||||
break;
|
||||
case 4:
|
||||
glUniform4i(m_uniform_bindings[it.first], it.second.m_integer_values[0],
|
||||
it.second.m_integer_values[1], it.second.m_integer_values[2],
|
||||
it.second.m_integer_values[3]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_FLOAT:
|
||||
switch (it.second.m_float_values.size())
|
||||
{
|
||||
case 1:
|
||||
glUniform1f(m_uniform_bindings[it.first], it.second.m_float_values[0]);
|
||||
break;
|
||||
case 2:
|
||||
glUniform2f(m_uniform_bindings[it.first], it.second.m_float_values[0],
|
||||
it.second.m_float_values[1]);
|
||||
break;
|
||||
case 3:
|
||||
glUniform3f(m_uniform_bindings[it.first], it.second.m_float_values[0],
|
||||
it.second.m_float_values[1], it.second.m_float_values[2]);
|
||||
break;
|
||||
case 4:
|
||||
glUniform4f(m_uniform_bindings[it.first], it.second.m_float_values[0],
|
||||
it.second.m_float_values[1], it.second.m_float_values[2],
|
||||
it.second.m_float_values[3]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
it.second.m_dirty = false;
|
||||
}
|
||||
}
|
||||
m_config.SetDirty(false);
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE9);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, src_texture);
|
||||
g_sampler_cache->BindLinearSampler(9);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
void OpenGLPostProcessing::ApplyShader()
|
||||
{
|
||||
// shader didn't changed
|
||||
if (m_initialized && m_config.GetShader() == g_ActiveConfig.sPostProcessingShader)
|
||||
return;
|
||||
|
||||
m_shader.Destroy();
|
||||
m_uniform_bindings.clear();
|
||||
|
||||
// load shader code
|
||||
std::string main_code = m_config.LoadShader();
|
||||
std::string options_code = LoadShaderOptions();
|
||||
std::string code = m_glsl_header + options_code + main_code;
|
||||
|
||||
// and compile it
|
||||
if (!ProgramShaderCache::CompileShader(m_shader, s_vertex_shader, code))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", m_config.GetShader().c_str());
|
||||
Config::SetCurrent(Config::GFX_ENHANCE_POST_SHADER, "");
|
||||
code = m_config.LoadShader();
|
||||
ProgramShaderCache::CompileShader(m_shader, s_vertex_shader, code);
|
||||
}
|
||||
|
||||
// read uniform locations
|
||||
m_uniform_resolution = glGetUniformLocation(m_shader.glprogid, "resolution");
|
||||
m_uniform_time = glGetUniformLocation(m_shader.glprogid, "time");
|
||||
m_uniform_src_rect = glGetUniformLocation(m_shader.glprogid, "src_rect");
|
||||
m_uniform_layer = glGetUniformLocation(m_shader.glprogid, "layer");
|
||||
|
||||
for (const auto& it : m_config.GetOptions())
|
||||
{
|
||||
std::string glsl_name = "options." + it.first;
|
||||
m_uniform_bindings[it.first] = glGetUniformLocation(m_shader.glprogid, glsl_name.c_str());
|
||||
}
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
void OpenGLPostProcessing::CreateHeader()
|
||||
{
|
||||
m_glsl_header =
|
||||
// Required variables
|
||||
// Shouldn't be accessed directly by the PP shader
|
||||
// Texture sampler
|
||||
"SAMPLER_BINDING(8) uniform sampler2D samp8;\n"
|
||||
"SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n"
|
||||
|
||||
// Output variable
|
||||
"out float4 ocol0;\n"
|
||||
// Input coordinates
|
||||
"in float2 uv0;\n"
|
||||
// Resolution
|
||||
"uniform float4 resolution;\n"
|
||||
// Time
|
||||
"uniform uint time;\n"
|
||||
// Layer
|
||||
"uniform int layer;\n"
|
||||
|
||||
// Interfacing functions
|
||||
"float4 Sample()\n"
|
||||
"{\n"
|
||||
"\treturn texture(samp9, float3(uv0, layer));\n"
|
||||
"}\n"
|
||||
|
||||
"float4 SampleLocation(float2 location)\n"
|
||||
"{\n"
|
||||
"\treturn texture(samp9, float3(location, layer));\n"
|
||||
"}\n"
|
||||
|
||||
"float4 SampleLayer(int layer)\n"
|
||||
"{\n"
|
||||
"\treturn texture(samp9, float3(uv0, layer));\n"
|
||||
"}\n"
|
||||
|
||||
"#define SampleOffset(offset) textureOffset(samp9, float3(uv0, layer), offset)\n"
|
||||
|
||||
"float2 GetResolution()\n"
|
||||
"{\n"
|
||||
"\treturn resolution.xy;\n"
|
||||
"}\n"
|
||||
|
||||
"float2 GetInvResolution()\n"
|
||||
"{\n"
|
||||
"\treturn resolution.zw;\n"
|
||||
"}\n"
|
||||
|
||||
"float2 GetCoordinates()\n"
|
||||
"{\n"
|
||||
"\treturn uv0;\n"
|
||||
"}\n"
|
||||
|
||||
"uint GetTime()\n"
|
||||
"{\n"
|
||||
"\treturn time;\n"
|
||||
"}\n"
|
||||
|
||||
"void SetOutput(float4 color)\n"
|
||||
"{\n"
|
||||
"\tocol0 = color;\n"
|
||||
"}\n"
|
||||
|
||||
"#define GetOption(x) (options.x)\n"
|
||||
"#define OptionEnabled(x) (options.x != 0)\n";
|
||||
}
|
||||
|
||||
std::string OpenGLPostProcessing::LoadShaderOptions()
|
||||
{
|
||||
m_uniform_bindings.clear();
|
||||
if (m_config.GetOptions().empty())
|
||||
return "";
|
||||
|
||||
std::string glsl_options = "struct Options\n{\n";
|
||||
|
||||
for (const auto& it : m_config.GetOptions())
|
||||
{
|
||||
if (it.second.m_type ==
|
||||
PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL)
|
||||
{
|
||||
glsl_options += StringFromFormat("int %s;\n", it.first.c_str());
|
||||
}
|
||||
else if (it.second.m_type ==
|
||||
PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER)
|
||||
{
|
||||
u32 count = static_cast<u32>(it.second.m_integer_values.size());
|
||||
if (count == 1)
|
||||
glsl_options += StringFromFormat("int %s;\n", it.first.c_str());
|
||||
else
|
||||
glsl_options += StringFromFormat("int%d %s;\n", count, it.first.c_str());
|
||||
}
|
||||
else if (it.second.m_type ==
|
||||
PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_FLOAT)
|
||||
{
|
||||
u32 count = static_cast<u32>(it.second.m_float_values.size());
|
||||
if (count == 1)
|
||||
glsl_options += StringFromFormat("float %s;\n", it.first.c_str());
|
||||
else
|
||||
glsl_options += StringFromFormat("float%d %s;\n", count, it.first.c_str());
|
||||
}
|
||||
|
||||
m_uniform_bindings[it.first] = 0;
|
||||
}
|
||||
|
||||
glsl_options += "};\n";
|
||||
glsl_options += "uniform Options options;\n";
|
||||
|
||||
return glsl_options;
|
||||
}
|
||||
|
||||
} // namespace OGL
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "Common/GL/GLUtil.h"
|
||||
|
||||
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||
|
||||
#include "VideoCommon/PostProcessing.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
class OpenGLPostProcessing : public PostProcessingShaderImplementation
|
||||
{
|
||||
public:
|
||||
OpenGLPostProcessing();
|
||||
~OpenGLPostProcessing();
|
||||
|
||||
void BlitFromTexture(TargetRectangle src, TargetRectangle dst, int src_texture, int src_width,
|
||||
int src_height, int layer);
|
||||
void ApplyShader();
|
||||
|
||||
private:
|
||||
bool m_initialized;
|
||||
SHADER m_shader;
|
||||
GLuint m_uniform_resolution;
|
||||
GLuint m_uniform_src_rect;
|
||||
GLuint m_uniform_time;
|
||||
GLuint m_uniform_layer;
|
||||
std::string m_glsl_header;
|
||||
|
||||
std::unordered_map<std::string, GLuint> m_uniform_bindings;
|
||||
|
||||
void CreateHeader();
|
||||
std::string LoadShaderOptions();
|
||||
};
|
||||
|
||||
} // namespace
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
@ -27,7 +28,6 @@
|
|||
#include "VideoBackends/OGL/VertexManager.h"
|
||||
|
||||
#include "VideoCommon/AsyncShaderCompiler.h"
|
||||
#include "VideoCommon/Debugger.h"
|
||||
#include "VideoCommon/DriverDetails.h"
|
||||
#include "VideoCommon/GeometryShaderManager.h"
|
||||
#include "VideoCommon/ImageWrite.h"
|
||||
|
@ -54,6 +54,7 @@ static GLuint CurrentProgram = 0;
|
|||
ProgramShaderCache::PipelineProgramMap ProgramShaderCache::s_pipeline_programs;
|
||||
std::mutex ProgramShaderCache::s_pipeline_program_lock;
|
||||
static std::string s_glsl_header = "";
|
||||
static std::atomic<u64> s_shader_counter{0};
|
||||
static thread_local bool s_is_shared_context = false;
|
||||
|
||||
static std::string GetGLSLVersionString()
|
||||
|
@ -109,13 +110,13 @@ void SHADER::SetProgramVariables()
|
|||
glUniformBlockBinding(glprogid, UBERBlock_id, 4);
|
||||
|
||||
// Bind Texture Samplers
|
||||
for (int a = 0; a < 10; ++a)
|
||||
for (int a = 0; a < 8; ++a)
|
||||
{
|
||||
std::string name = StringFromFormat(a < 8 ? "samp[%d]" : "samp%d", a);
|
||||
|
||||
// Still need to get sampler locations since we aren't binding them statically in the shaders
|
||||
int loc = glGetUniformLocation(glprogid, name.c_str());
|
||||
if (loc != -1)
|
||||
int loc = glGetUniformLocation(glprogid, StringFromFormat("samp[%d]", a).c_str());
|
||||
if (loc < 0)
|
||||
loc = glGetUniformLocation(glprogid, StringFromFormat("samp%d", a).c_str());
|
||||
if (loc >= 0)
|
||||
glUniform1i(loc, a);
|
||||
}
|
||||
|
||||
|
@ -191,21 +192,22 @@ bool PipelineProgramKey::operator!=(const PipelineProgramKey& rhs) const
|
|||
|
||||
bool PipelineProgramKey::operator==(const PipelineProgramKey& rhs) const
|
||||
{
|
||||
return std::tie(vertex_shader, geometry_shader, pixel_shader) ==
|
||||
std::tie(rhs.vertex_shader, rhs.geometry_shader, rhs.pixel_shader);
|
||||
return std::tie(vertex_shader_id, geometry_shader_id, pixel_shader_id) ==
|
||||
std::tie(rhs.vertex_shader_id, rhs.geometry_shader_id, rhs.pixel_shader_id);
|
||||
}
|
||||
|
||||
bool PipelineProgramKey::operator<(const PipelineProgramKey& rhs) const
|
||||
{
|
||||
return std::tie(vertex_shader, geometry_shader, pixel_shader) <
|
||||
std::tie(rhs.vertex_shader, rhs.geometry_shader, rhs.pixel_shader);
|
||||
return std::tie(vertex_shader_id, geometry_shader_id, pixel_shader_id) <
|
||||
std::tie(rhs.vertex_shader_id, rhs.geometry_shader_id, rhs.pixel_shader_id);
|
||||
}
|
||||
|
||||
std::size_t PipelineProgramKeyHash::operator()(const PipelineProgramKey& key) const
|
||||
{
|
||||
// We would really want std::hash_combine for this..
|
||||
std::hash<const void*> hasher;
|
||||
return hasher(key.vertex_shader) + hasher(key.geometry_shader) + hasher(key.pixel_shader);
|
||||
std::hash<u64> hasher;
|
||||
return hasher(key.vertex_shader_id) + hasher(key.geometry_shader_id) +
|
||||
hasher(key.pixel_shader_id);
|
||||
}
|
||||
|
||||
StreamBuffer* ProgramShaderCache::GetUniformBuffer()
|
||||
|
@ -218,13 +220,6 @@ u32 ProgramShaderCache::GetUniformBufferAlignment()
|
|||
return s_ubo_align;
|
||||
}
|
||||
|
||||
void ProgramShaderCache::InvalidateConstants()
|
||||
{
|
||||
VertexShaderManager::dirty = true;
|
||||
GeometryShaderManager::dirty = true;
|
||||
PixelShaderManager::dirty = true;
|
||||
}
|
||||
|
||||
void ProgramShaderCache::UploadConstants()
|
||||
{
|
||||
if (PixelShaderManager::dirty || VertexShaderManager::dirty || GeometryShaderManager::dirty)
|
||||
|
@ -574,7 +569,9 @@ const PipelineProgram* ProgramShaderCache::GetPipelineProgram(const GLVertexForm
|
|||
const OGLShader* geometry_shader,
|
||||
const OGLShader* pixel_shader)
|
||||
{
|
||||
PipelineProgramKey key = {vertex_shader, geometry_shader, pixel_shader};
|
||||
PipelineProgramKey key = {vertex_shader ? vertex_shader->GetID() : 0,
|
||||
geometry_shader ? geometry_shader->GetID() : 0,
|
||||
pixel_shader ? pixel_shader->GetID() : 0};
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(s_pipeline_program_lock);
|
||||
auto iter = s_pipeline_programs.find(key);
|
||||
|
@ -750,6 +747,7 @@ void ProgramShaderCache::CreateHeader()
|
|||
"%s\n"
|
||||
|
||||
// Silly differences
|
||||
"#define API_OPENGL 1\n"
|
||||
"#define float2 vec2\n"
|
||||
"#define float3 vec3\n"
|
||||
"#define float4 vec4\n"
|
||||
|
@ -759,8 +757,6 @@ void ProgramShaderCache::CreateHeader()
|
|||
"#define int2 ivec2\n"
|
||||
"#define int3 ivec3\n"
|
||||
"#define int4 ivec4\n"
|
||||
|
||||
// hlsl to glsl function translation
|
||||
"#define frac fract\n"
|
||||
"#define lerp mix\n"
|
||||
|
||||
|
@ -782,12 +778,17 @@ void ProgramShaderCache::CreateHeader()
|
|||
"#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y)\n"
|
||||
"#define UBO_BINDING(packing, x) layout(packing, binding = x)\n"
|
||||
"#define SAMPLER_BINDING(x) layout(binding = x)\n"
|
||||
"#define SSBO_BINDING(x) layout(binding = x)\n" :
|
||||
"#define TEXEL_BUFFER_BINDING(x) layout(binding = x)\n"
|
||||
"#define SSBO_BINDING(x) layout(binding = x)\n"
|
||||
"#define IMAGE_BINDING(format, x) layout(format, binding = x)\n" :
|
||||
"#define ATTRIBUTE_LOCATION(x)\n"
|
||||
"#define FRAGMENT_OUTPUT_LOCATION(x)\n"
|
||||
"#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y)\n"
|
||||
"#define UBO_BINDING(packing, x) layout(packing)\n"
|
||||
"#define SAMPLER_BINDING(x)\n",
|
||||
"#define SAMPLER_BINDING(x)\n"
|
||||
"#define TEXEL_BUFFER_BINDING(x)\n"
|
||||
"#define SSBO_BINDING(x)\n"
|
||||
"#define IMAGE_BINDING(format, x) layout(format)\n",
|
||||
// Input/output blocks are matched by name during program linking
|
||||
"#define VARYING_LOCATION(x)\n",
|
||||
!is_glsles && g_ActiveConfig.backend_info.bSupportsFragmentStoresAndAtomics ?
|
||||
|
@ -823,6 +824,11 @@ void ProgramShaderCache::CreateHeader()
|
|||
v >= GlslEs310 ? "precision highp image2DArray;" : "");
|
||||
}
|
||||
|
||||
u64 ProgramShaderCache::GenerateShaderID()
|
||||
{
|
||||
return s_shader_counter++;
|
||||
}
|
||||
|
||||
bool SharedContextAsyncShaderCompiler::WorkerThreadInitMainThread(void** param)
|
||||
{
|
||||
std::unique_ptr<GLContext> context =
|
||||
|
|
|
@ -44,9 +44,9 @@ struct SHADER
|
|||
|
||||
struct PipelineProgramKey
|
||||
{
|
||||
const OGLShader* vertex_shader;
|
||||
const OGLShader* geometry_shader;
|
||||
const OGLShader* pixel_shader;
|
||||
u64 vertex_shader_id;
|
||||
u64 geometry_shader_id;
|
||||
u64 pixel_shader_id;
|
||||
|
||||
bool operator==(const PipelineProgramKey& rhs) const;
|
||||
bool operator!=(const PipelineProgramKey& rhs) const;
|
||||
|
@ -82,7 +82,6 @@ public:
|
|||
const std::string& gcode);
|
||||
static StreamBuffer* GetUniformBuffer();
|
||||
static u32 GetUniformBufferAlignment();
|
||||
static void InvalidateConstants();
|
||||
static void UploadConstants();
|
||||
static void UploadConstants(const void* data, u32 data_size);
|
||||
|
||||
|
@ -90,6 +89,14 @@ public:
|
|||
static void Shutdown();
|
||||
static void CreateHeader();
|
||||
|
||||
// This counter increments with each shader object allocated, in order to give it a unique ID.
|
||||
// Since the shaders can be destroyed after a pipeline is created, we can't use the shader pointer
|
||||
// as a key for GL programs. For the same reason, we can't use the GL objects either. This ID is
|
||||
// guaranteed to be unique for the emulation session, even if the memory allocator or GL driver
|
||||
// re-uses pointers, therefore we won't have any collisions where the shaders attached to a
|
||||
// pipeline do not match the pipeline configuration.
|
||||
static u64 GenerateShaderID();
|
||||
|
||||
static const PipelineProgram* GetPipelineProgram(const GLVertexFormat* vertex_format,
|
||||
const OGLShader* vertex_shader,
|
||||
const OGLShader* geometry_shader,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,12 +11,11 @@
|
|||
#include "Common/GL/GLExtensions/GLExtensions.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
|
||||
struct XFBSourceBase;
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
class OGLFramebuffer;
|
||||
class OGLPipeline;
|
||||
void ClearEFBCache();
|
||||
class OGLTexture;
|
||||
|
||||
enum GlslVersion
|
||||
{
|
||||
|
@ -86,6 +85,8 @@ public:
|
|||
Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_scale);
|
||||
~Renderer() override;
|
||||
|
||||
static Renderer* GetInstance() { return static_cast<Renderer*>(g_renderer.get()); }
|
||||
|
||||
bool IsHeadless() const override;
|
||||
|
||||
bool Initialize() override;
|
||||
|
@ -98,73 +99,80 @@ public:
|
|||
size_t length) override;
|
||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||
size_t length) override;
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
|
||||
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config) override;
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment) override;
|
||||
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
|
||||
|
||||
void SetPipeline(const AbstractPipeline* pipeline) override;
|
||||
void SetFramebuffer(const AbstractFramebuffer* framebuffer) override;
|
||||
void SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer) override;
|
||||
void SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
|
||||
const ClearColor& color_value = {},
|
||||
void SetFramebuffer(AbstractFramebuffer* framebuffer) override;
|
||||
void SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) override;
|
||||
void SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value = {},
|
||||
float depth_value = 0.0f) override;
|
||||
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
|
||||
void SetTexture(u32 index, const AbstractTexture* texture) override;
|
||||
void SetSamplerState(u32 index, const SamplerState& state) override;
|
||||
void SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) override;
|
||||
void UnbindTexture(const AbstractTexture* texture) override;
|
||||
void SetInterlacingMode() override;
|
||||
void SetViewport(float x, float y, float width, float height, float near_depth,
|
||||
float far_depth) override;
|
||||
void Draw(u32 base_vertex, u32 num_vertices) override;
|
||||
void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override;
|
||||
void DispatchComputeShader(const AbstractShader* shader, u32 groups_x, u32 groups_y,
|
||||
u32 groups_z) override;
|
||||
void BindBackbuffer(const ClearColor& clear_color = {}) override;
|
||||
void PresentBackbuffer() override;
|
||||
|
||||
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
|
||||
void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override;
|
||||
|
||||
u16 BBoxRead(int index) override;
|
||||
void BBoxWrite(int index, u16 value) override;
|
||||
|
||||
void ResetAPIState() override;
|
||||
void RestoreAPIState() override;
|
||||
|
||||
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
|
||||
void BeginUtilityDrawing() override;
|
||||
void EndUtilityDrawing() override;
|
||||
|
||||
void Flush() override;
|
||||
void WaitForGPUIdle() override;
|
||||
void RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc) override;
|
||||
void OnConfigChanged(u32 bits) override;
|
||||
|
||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
|
||||
u32 color, u32 z) override;
|
||||
|
||||
void ReinterpretPixelData(unsigned int convtype) override;
|
||||
|
||||
std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler() override;
|
||||
|
||||
// Only call methods from this on the GPU thread.
|
||||
GLContext* GetMainGLContext() const { return m_main_gl_context.get(); }
|
||||
bool IsGLES() const { return m_main_gl_context->IsGLES(); }
|
||||
|
||||
const OGLPipeline* GetCurrentGraphicsPipeline() const { return m_graphics_pipeline; }
|
||||
// Invalidates a cached texture binding. Required for texel buffers when they borrow the units.
|
||||
void InvalidateTextureBinding(u32 index) { m_bound_textures[index] = nullptr; }
|
||||
|
||||
// The shared framebuffer exists for copying textures when extensions are not available. It is
|
||||
// slower, but the only way to do these things otherwise.
|
||||
GLuint GetSharedReadFramebuffer() const { return m_shared_read_framebuffer; }
|
||||
GLuint GetSharedDrawFramebuffer() const { return m_shared_draw_framebuffer; }
|
||||
void BindSharedReadFramebuffer();
|
||||
void BindSharedDrawFramebuffer();
|
||||
|
||||
// Restores FBO binding after it's been changed.
|
||||
void RestoreFramebufferBinding();
|
||||
|
||||
private:
|
||||
void UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc,
|
||||
const TargetRectangle& targetPixelRc, const void* data);
|
||||
|
||||
void CheckForSurfaceChange();
|
||||
void CheckForSurfaceResize();
|
||||
|
||||
void ApplyBlendingState(const BlendingState state, bool force = false);
|
||||
void ApplyRasterizationState(const RasterizationState state, bool force = false);
|
||||
void ApplyDepthState(const DepthState state, bool force = false);
|
||||
void ApplyRasterizationState(const RasterizationState state);
|
||||
void ApplyDepthState(const DepthState state);
|
||||
void ApplyBlendingState(const BlendingState state);
|
||||
|
||||
std::unique_ptr<GLContext> m_main_gl_context;
|
||||
std::array<const AbstractTexture*, 8> m_bound_textures{};
|
||||
const OGLPipeline* m_graphics_pipeline = nullptr;
|
||||
std::unique_ptr<OGLFramebuffer> m_system_framebuffer;
|
||||
std::array<const OGLTexture*, 8> m_bound_textures{};
|
||||
AbstractTexture* m_bound_image_texture = nullptr;
|
||||
RasterizationState m_current_rasterization_state;
|
||||
DepthState m_current_depth_state;
|
||||
BlendingState m_current_blend_state;
|
||||
GLuint m_shared_read_framebuffer = 0;
|
||||
GLuint m_shared_draw_framebuffer = 0;
|
||||
};
|
||||
} // namespace OGL
|
||||
|
|
|
@ -19,6 +19,8 @@ public:
|
|||
static std::unique_ptr<StreamBuffer> Create(u32 type, u32 size);
|
||||
virtual ~StreamBuffer();
|
||||
|
||||
u32 GetGLBufferId() const { return m_buffer; }
|
||||
u32 GetSize() const { return m_size; }
|
||||
u32 GetCurrentOffset() const { return m_iterator; }
|
||||
|
||||
/* This mapping function will return a pair of:
|
||||
|
@ -64,4 +66,4 @@ private:
|
|||
|
||||
std::array<GLsync, SYNC_POINTS> m_fences{};
|
||||
};
|
||||
}
|
||||
} // namespace OGL
|
||||
|
|
|
@ -1,574 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "VideoBackends/OGL/FramebufferManager.h"
|
||||
#include "VideoBackends/OGL/GPUTimer.h"
|
||||
#include "VideoBackends/OGL/OGLTexture.h"
|
||||
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||
#include "VideoBackends/OGL/Render.h"
|
||||
#include "VideoBackends/OGL/SamplerCache.h"
|
||||
#include "VideoBackends/OGL/StreamBuffer.h"
|
||||
#include "VideoBackends/OGL/TextureCache.h"
|
||||
#include "VideoBackends/OGL/TextureConverter.h"
|
||||
|
||||
#include "VideoCommon/ImageWrite.h"
|
||||
#include "VideoCommon/TextureConversionShader.h"
|
||||
#include "VideoCommon/TextureConverterShaderGen.h"
|
||||
#include "VideoCommon/TextureDecoder.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
constexpr const char GLSL_PROGRAM_VS[] = R"GLSL(
|
||||
out vec3 %c_uv0;
|
||||
SAMPLER_BINDING(9) uniform sampler2DArray samp9;
|
||||
uniform vec4 copy_position; // left, top, right, bottom
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);
|
||||
%c_uv0 = vec3(mix(copy_position.xy, copy_position.zw, rawpos) / vec2(textureSize(samp9, 0).xy), 0.0);
|
||||
gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);
|
||||
}
|
||||
)GLSL";
|
||||
|
||||
constexpr const char GLSL_PROGRAM_GS[] = R"GLSL(
|
||||
layout(triangles) in;
|
||||
layout(triangle_strip, max_vertices = 6) out;
|
||||
in vec3 v_uv0[3];
|
||||
out vec3 f_uv0;
|
||||
SAMPLER_BINDING(9) uniform sampler2DArray samp9;
|
||||
|
||||
void main()
|
||||
{
|
||||
int layers = textureSize(samp9, 0).z;
|
||||
for (int layer = 0; layer < layers; ++layer) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
f_uv0 = vec3(v_uv0[i].xy, layer);
|
||||
gl_Position = gl_in[i].gl_Position;
|
||||
gl_Layer = layer;
|
||||
EmitVertex();
|
||||
}
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
)GLSL";
|
||||
|
||||
constexpr const char GLSL_COLOR_COPY_FS[] = R"GLSL(
|
||||
SAMPLER_BINDING(9) uniform sampler2DArray samp9;
|
||||
in vec3 f_uv0;
|
||||
out vec4 ocol0;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 texcol = texture(samp9, f_uv0);
|
||||
ocol0 = texcol;
|
||||
}
|
||||
)GLSL";
|
||||
|
||||
constexpr const char GLSL_PALETTE_FS[] = R"GLSL(
|
||||
uniform int texture_buffer_offset;
|
||||
uniform float multiplier;
|
||||
SAMPLER_BINDING(9) uniform sampler2DArray samp9;
|
||||
SAMPLER_BINDING(10) uniform usamplerBuffer samp10;
|
||||
|
||||
in vec3 f_uv0;
|
||||
out vec4 ocol0;
|
||||
|
||||
int Convert3To8(int v)
|
||||
{
|
||||
// Swizzle bits: 00000123 -> 12312312
|
||||
return (v << 5) | (v << 2) | (v >> 1);
|
||||
}
|
||||
|
||||
int Convert4To8(int v)
|
||||
{
|
||||
// Swizzle bits: 00001234 -> 12341234
|
||||
return (v << 4) | v;
|
||||
}
|
||||
|
||||
int Convert5To8(int v)
|
||||
{
|
||||
// Swizzle bits: 00012345 -> 12345123
|
||||
return (v << 3) | (v >> 2);
|
||||
}
|
||||
|
||||
int Convert6To8(int v)
|
||||
{
|
||||
// Swizzle bits: 00123456 -> 12345612
|
||||
return (v << 2) | (v >> 4);
|
||||
}
|
||||
|
||||
float4 DecodePixel_RGB5A3(int val)
|
||||
{
|
||||
int r,g,b,a;
|
||||
if ((val&0x8000) > 0)
|
||||
{
|
||||
r=Convert5To8((val>>10) & 0x1f);
|
||||
g=Convert5To8((val>>5 ) & 0x1f);
|
||||
b=Convert5To8((val ) & 0x1f);
|
||||
a=0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
a=Convert3To8((val>>12) & 0x7);
|
||||
r=Convert4To8((val>>8 ) & 0xf);
|
||||
g=Convert4To8((val>>4 ) & 0xf);
|
||||
b=Convert4To8((val ) & 0xf);
|
||||
}
|
||||
return float4(r, g, b, a) / 255.0;
|
||||
}
|
||||
|
||||
float4 DecodePixel_RGB565(int val)
|
||||
{
|
||||
int r, g, b, a;
|
||||
r = Convert5To8((val >> 11) & 0x1f);
|
||||
g = Convert6To8((val >> 5) & 0x3f);
|
||||
b = Convert5To8((val) & 0x1f);
|
||||
a = 0xFF;
|
||||
return float4(r, g, b, a) / 255.0;
|
||||
}
|
||||
|
||||
float4 DecodePixel_IA8(int val)
|
||||
{
|
||||
int i = val & 0xFF;
|
||||
int a = val >> 8;
|
||||
return float4(i, i, i, a) / 255.0;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
int src = int(round(texture(samp9, f_uv0).r * multiplier));
|
||||
src = int(texelFetch(samp10, src + texture_buffer_offset).r);
|
||||
src = ((src << 8) & 0xFF00) | (src >> 8);
|
||||
ocol0 = DecodePixel_%s(src);
|
||||
}
|
||||
)GLSL";
|
||||
|
||||
//#define TIME_TEXTURE_DECODING 1
|
||||
|
||||
void TextureCache::CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams& params,
|
||||
u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
|
||||
const EFBRectangle& src_rect, bool scale_by_half, float y_scale,
|
||||
float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients)
|
||||
{
|
||||
// Flip top/bottom due to lower-left coordinate system.
|
||||
float clamp_top_val =
|
||||
clamp_bottom ? (1.0f - src_rect.bottom / static_cast<float>(EFB_HEIGHT)) : 0.0f;
|
||||
float clamp_bottom_val =
|
||||
clamp_top ? (1.0f - src_rect.top / static_cast<float>(EFB_HEIGHT)) : 1.0f;
|
||||
TextureConverter::EncodeToRamFromTexture(dst, params, native_width, bytes_per_row, num_blocks_y,
|
||||
memory_stride, src_rect, scale_by_half, y_scale, gamma,
|
||||
clamp_top_val, clamp_bottom_val, filter_coefficients);
|
||||
}
|
||||
|
||||
TextureCache::TextureCache()
|
||||
{
|
||||
CompileShaders();
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
|
||||
{
|
||||
s32 buffer_size_mb = (g_ActiveConfig.backend_info.bSupportsGPUTextureDecoding ? 32 : 1);
|
||||
s32 buffer_size = buffer_size_mb * 1024 * 1024;
|
||||
s32 max_buffer_size = 0;
|
||||
|
||||
// The minimum MAX_TEXTURE_BUFFER_SIZE that the spec mandates is 65KB, we are asking for a 1MB
|
||||
// buffer here. This buffer is also used as storage for undecoded textures when compute shader
|
||||
// texture decoding is enabled, in which case the requested size is 32MB.
|
||||
glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &max_buffer_size);
|
||||
|
||||
// Clamp the buffer size to the maximum size that the driver supports.
|
||||
buffer_size = std::min(buffer_size, max_buffer_size);
|
||||
|
||||
m_palette_stream_buffer = StreamBuffer::Create(GL_TEXTURE_BUFFER, buffer_size);
|
||||
glGenTextures(1, &m_palette_resolv_texture);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, m_palette_resolv_texture);
|
||||
glTexBuffer(GL_TEXTURE_BUFFER, GL_R16UI, m_palette_stream_buffer->m_buffer);
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsGPUTextureDecoding)
|
||||
CreateTextureDecodingResources();
|
||||
}
|
||||
}
|
||||
|
||||
TextureCache::~TextureCache()
|
||||
{
|
||||
DeleteShaders();
|
||||
if (g_ActiveConfig.backend_info.bSupportsGPUTextureDecoding)
|
||||
DestroyTextureDecodingResources();
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
|
||||
{
|
||||
glDeleteTextures(1, &m_palette_resolv_texture);
|
||||
}
|
||||
}
|
||||
|
||||
TextureCache* TextureCache::GetInstance()
|
||||
{
|
||||
return static_cast<TextureCache*>(g_texture_cache.get());
|
||||
}
|
||||
|
||||
const SHADER& TextureCache::GetColorCopyProgram() const
|
||||
{
|
||||
return m_colorCopyProgram;
|
||||
}
|
||||
|
||||
GLuint TextureCache::GetColorCopyPositionUniform() const
|
||||
{
|
||||
return m_colorCopyPositionUniform;
|
||||
}
|
||||
|
||||
bool TextureCache::CompilePaletteShader(TLUTFormat tlutfmt, const std::string& vcode,
|
||||
const std::string& pcode, const std::string& gcode)
|
||||
{
|
||||
ASSERT(IsValidTLUTFormat(tlutfmt));
|
||||
PaletteShader& shader = m_palette_shaders[static_cast<int>(tlutfmt)];
|
||||
|
||||
if (!ProgramShaderCache::CompileShader(shader.shader, vcode, pcode, gcode))
|
||||
return false;
|
||||
|
||||
shader.buffer_offset_uniform =
|
||||
glGetUniformLocation(shader.shader.glprogid, "texture_buffer_offset");
|
||||
shader.multiplier_uniform = glGetUniformLocation(shader.shader.glprogid, "multiplier");
|
||||
shader.copy_position_uniform = glGetUniformLocation(shader.shader.glprogid, "copy_position");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextureCache::CompileShaders()
|
||||
{
|
||||
std::string geo_program = "";
|
||||
char prefix = 'f';
|
||||
if (g_ActiveConfig.stereo_mode != StereoMode::Off)
|
||||
{
|
||||
geo_program = GLSL_PROGRAM_GS;
|
||||
prefix = 'v';
|
||||
}
|
||||
|
||||
if (!ProgramShaderCache::CompileShader(m_colorCopyProgram,
|
||||
StringFromFormat(GLSL_PROGRAM_VS, prefix, prefix),
|
||||
GLSL_COLOR_COPY_FS, geo_program))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_colorCopyPositionUniform = glGetUniformLocation(m_colorCopyProgram.glprogid, "copy_position");
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
|
||||
{
|
||||
if (!CompilePaletteShader(TLUTFormat::IA8, StringFromFormat(GLSL_PROGRAM_VS, prefix, prefix),
|
||||
StringFromFormat(GLSL_PALETTE_FS, "IA8"), geo_program))
|
||||
return false;
|
||||
|
||||
if (!CompilePaletteShader(TLUTFormat::RGB565, StringFromFormat(GLSL_PROGRAM_VS, prefix, prefix),
|
||||
StringFromFormat(GLSL_PALETTE_FS, "RGB565"), geo_program))
|
||||
return false;
|
||||
|
||||
if (!CompilePaletteShader(TLUTFormat::RGB5A3, StringFromFormat(GLSL_PROGRAM_VS, prefix, prefix),
|
||||
StringFromFormat(GLSL_PALETTE_FS, "RGB5A3"), geo_program))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextureCache::DeleteShaders()
|
||||
{
|
||||
for (auto& it : m_efb_copy_programs)
|
||||
it.second.shader.Destroy();
|
||||
m_efb_copy_programs.clear();
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
|
||||
for (auto& shader : m_palette_shaders)
|
||||
shader.shader.Destroy();
|
||||
}
|
||||
|
||||
void TextureCache::ConvertTexture(TCacheEntry* destination, TCacheEntry* source,
|
||||
const void* palette, TLUTFormat tlutfmt)
|
||||
{
|
||||
if (!g_ActiveConfig.backend_info.bSupportsPaletteConversion)
|
||||
return;
|
||||
|
||||
ASSERT(IsValidTLUTFormat(tlutfmt));
|
||||
const PaletteShader& palette_shader = m_palette_shaders[static_cast<int>(tlutfmt)];
|
||||
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
OGLTexture* source_texture = static_cast<OGLTexture*>(source->texture.get());
|
||||
OGLTexture* destination_texture = static_cast<OGLTexture*>(destination->texture.get());
|
||||
|
||||
glActiveTexture(GL_TEXTURE9);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, source_texture->GetRawTexIdentifier());
|
||||
g_sampler_cache->BindNearestSampler(9);
|
||||
|
||||
FramebufferManager::SetFramebuffer(destination_texture->GetFramebuffer());
|
||||
glViewport(0, 0, destination->GetWidth(), destination->GetHeight());
|
||||
palette_shader.shader.Bind();
|
||||
|
||||
// C14 textures are currently unsupported
|
||||
int size = source->format == TextureFormat::I4 ? 32 : 512;
|
||||
auto buffer = m_palette_stream_buffer->Map(size);
|
||||
memcpy(buffer.first, palette, size);
|
||||
m_palette_stream_buffer->Unmap(size);
|
||||
glUniform1i(palette_shader.buffer_offset_uniform, buffer.second / 2);
|
||||
glUniform1f(palette_shader.multiplier_uniform,
|
||||
source->format == TextureFormat::I4 ? 15.0f : 255.0f);
|
||||
glUniform4f(palette_shader.copy_position_uniform, 0.0f, 0.0f,
|
||||
static_cast<float>(source->GetWidth()), static_cast<float>(source->GetHeight()));
|
||||
|
||||
glActiveTexture(GL_TEXTURE10);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, m_palette_resolv_texture);
|
||||
g_sampler_cache->BindNearestSampler(10);
|
||||
|
||||
ProgramShaderCache::BindVertexFormat(nullptr);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
static const std::string decoding_vertex_shader = R"(
|
||||
void main()
|
||||
{
|
||||
vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);
|
||||
gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
void TextureCache::CreateTextureDecodingResources()
|
||||
{
|
||||
static const GLenum gl_view_types[TextureConversionShaderTiled::BUFFER_FORMAT_COUNT] = {
|
||||
GL_R8UI, // BUFFER_FORMAT_R8_UINT
|
||||
GL_R16UI, // BUFFER_FORMAT_R16_UINT
|
||||
GL_RG32UI, // BUFFER_FORMAT_R32G32_UINT
|
||||
GL_RGBA8UI, // BUFFER_FORMAT_RGBA8_UINT
|
||||
};
|
||||
|
||||
glGenTextures(TextureConversionShaderTiled::BUFFER_FORMAT_COUNT,
|
||||
m_texture_decoding_buffer_views.data());
|
||||
for (size_t i = 0; i < TextureConversionShaderTiled::BUFFER_FORMAT_COUNT; i++)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_BUFFER, m_texture_decoding_buffer_views[i]);
|
||||
glTexBuffer(GL_TEXTURE_BUFFER, gl_view_types[i], m_palette_stream_buffer->m_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCache::DestroyTextureDecodingResources()
|
||||
{
|
||||
glDeleteTextures(TextureConversionShaderTiled::BUFFER_FORMAT_COUNT,
|
||||
m_texture_decoding_buffer_views.data());
|
||||
m_texture_decoding_buffer_views.fill(0);
|
||||
m_texture_decoding_program_info.clear();
|
||||
}
|
||||
|
||||
bool TextureCache::SupportsGPUTextureDecode(TextureFormat format, TLUTFormat palette_format)
|
||||
{
|
||||
auto key = std::make_pair(static_cast<u32>(format), static_cast<u32>(palette_format));
|
||||
auto iter = m_texture_decoding_program_info.find(key);
|
||||
if (iter != m_texture_decoding_program_info.end())
|
||||
return iter->second.valid;
|
||||
|
||||
TextureDecodingProgramInfo info;
|
||||
info.base_info = TextureConversionShaderTiled::GetDecodingShaderInfo(format);
|
||||
if (!info.base_info)
|
||||
{
|
||||
m_texture_decoding_program_info.emplace(key, info);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string shader_source =
|
||||
TextureConversionShaderTiled::GenerateDecodingShader(format, palette_format, APIType::OpenGL);
|
||||
if (shader_source.empty())
|
||||
{
|
||||
m_texture_decoding_program_info.emplace(key, info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ProgramShaderCache::CompileComputeShader(info.program, shader_source))
|
||||
{
|
||||
m_texture_decoding_program_info.emplace(key, info);
|
||||
return false;
|
||||
}
|
||||
|
||||
info.uniform_dst_size = glGetUniformLocation(info.program.glprogid, "u_dst_size");
|
||||
info.uniform_src_size = glGetUniformLocation(info.program.glprogid, "u_src_size");
|
||||
info.uniform_src_offset = glGetUniformLocation(info.program.glprogid, "u_src_offset");
|
||||
info.uniform_src_row_stride = glGetUniformLocation(info.program.glprogid, "u_src_row_stride");
|
||||
info.uniform_palette_offset = glGetUniformLocation(info.program.glprogid, "u_palette_offset");
|
||||
info.valid = true;
|
||||
m_texture_decoding_program_info.emplace(key, info);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextureCache::DecodeTextureOnGPU(TCacheEntry* entry, u32 dst_level, const u8* data,
|
||||
size_t data_size, TextureFormat format, u32 width, u32 height,
|
||||
u32 aligned_width, u32 aligned_height, u32 row_stride,
|
||||
const u8* palette, TLUTFormat palette_format)
|
||||
{
|
||||
auto key = std::make_pair(static_cast<u32>(format), static_cast<u32>(palette_format));
|
||||
auto iter = m_texture_decoding_program_info.find(key);
|
||||
if (iter == m_texture_decoding_program_info.end())
|
||||
return;
|
||||
|
||||
#ifdef TIME_TEXTURE_DECODING
|
||||
GPUTimer timer;
|
||||
#endif
|
||||
|
||||
// Copy to GPU-visible buffer, aligned to the data type.
|
||||
auto info = iter->second;
|
||||
u32 bytes_per_buffer_elem =
|
||||
TextureConversionShaderTiled::GetBytesPerBufferElement(info.base_info->buffer_format);
|
||||
|
||||
// Only copy palette if it is required.
|
||||
bool has_palette = info.base_info->palette_size > 0;
|
||||
u32 total_upload_size = static_cast<u32>(data_size);
|
||||
u32 palette_offset = total_upload_size;
|
||||
if (has_palette)
|
||||
{
|
||||
// Align to u16.
|
||||
if ((total_upload_size % sizeof(u16)) != 0)
|
||||
{
|
||||
total_upload_size++;
|
||||
palette_offset++;
|
||||
}
|
||||
|
||||
total_upload_size += info.base_info->palette_size;
|
||||
}
|
||||
|
||||
// Allocate space in stream buffer, and copy texture + palette across.
|
||||
auto buffer = m_palette_stream_buffer->Map(total_upload_size, bytes_per_buffer_elem);
|
||||
memcpy(buffer.first, data, data_size);
|
||||
if (has_palette)
|
||||
memcpy(buffer.first + palette_offset, palette, info.base_info->palette_size);
|
||||
m_palette_stream_buffer->Unmap(total_upload_size);
|
||||
|
||||
info.program.Bind();
|
||||
|
||||
// Calculate stride in buffer elements
|
||||
u32 row_stride_in_elements = row_stride / bytes_per_buffer_elem;
|
||||
u32 offset_in_elements = buffer.second / bytes_per_buffer_elem;
|
||||
u32 palette_offset_in_elements = (buffer.second + palette_offset) / sizeof(u16);
|
||||
if (info.uniform_dst_size >= 0)
|
||||
glUniform2ui(info.uniform_dst_size, width, height);
|
||||
if (info.uniform_src_size >= 0)
|
||||
glUniform2ui(info.uniform_src_size, aligned_width, aligned_height);
|
||||
if (info.uniform_src_offset >= 0)
|
||||
glUniform1ui(info.uniform_src_offset, offset_in_elements);
|
||||
if (info.uniform_src_row_stride >= 0)
|
||||
glUniform1ui(info.uniform_src_row_stride, row_stride_in_elements);
|
||||
if (info.uniform_palette_offset >= 0)
|
||||
glUniform1ui(info.uniform_palette_offset, palette_offset_in_elements);
|
||||
|
||||
glActiveTexture(GL_TEXTURE9);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, m_texture_decoding_buffer_views[info.base_info->buffer_format]);
|
||||
|
||||
if (has_palette)
|
||||
{
|
||||
// Use an R16UI view for the palette.
|
||||
glActiveTexture(GL_TEXTURE10);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, m_palette_resolv_texture);
|
||||
}
|
||||
|
||||
auto dispatch_groups =
|
||||
TextureConversionShaderTiled::GetDispatchCount(info.base_info, aligned_width, aligned_height);
|
||||
glBindImageTexture(0, static_cast<OGLTexture*>(entry->texture.get())->GetRawTexIdentifier(),
|
||||
dst_level, GL_TRUE, 0, GL_WRITE_ONLY, GL_RGBA8);
|
||||
glDispatchCompute(dispatch_groups.first, dispatch_groups.second, 1);
|
||||
glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
|
||||
|
||||
#ifdef TIME_TEXTURE_DECODING
|
||||
WARN_LOG(VIDEO, "Decode texture format %u size %ux%u took %.4fms", static_cast<u32>(format),
|
||||
width, height, timer.GetTimeMilliseconds());
|
||||
#endif
|
||||
}
|
||||
|
||||
void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
|
||||
const EFBRectangle& src_rect, bool scale_by_half,
|
||||
EFBCopyFormat dst_format, bool is_intensity, float gamma,
|
||||
bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients)
|
||||
{
|
||||
auto* destination_texture = static_cast<OGLTexture*>(entry->texture.get());
|
||||
g_renderer->ResetAPIState(); // reset any game specific settings
|
||||
|
||||
// Make sure to resolve anything we need to read from.
|
||||
const GLuint read_texture = is_depth_copy ?
|
||||
FramebufferManager::ResolveAndGetDepthTarget(src_rect) :
|
||||
FramebufferManager::ResolveAndGetRenderTarget(src_rect);
|
||||
|
||||
FramebufferManager::SetFramebuffer(destination_texture->GetFramebuffer());
|
||||
|
||||
glActiveTexture(GL_TEXTURE9);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, read_texture);
|
||||
if (scale_by_half)
|
||||
g_sampler_cache->BindLinearSampler(9);
|
||||
else
|
||||
g_sampler_cache->BindNearestSampler(9);
|
||||
|
||||
glViewport(0, 0, destination_texture->GetConfig().width, destination_texture->GetConfig().height);
|
||||
|
||||
auto uid = TextureConversionShaderGen::GetShaderUid(dst_format, is_depth_copy, is_intensity,
|
||||
scale_by_half,
|
||||
NeedsCopyFilterInShader(filter_coefficients));
|
||||
|
||||
auto it = m_efb_copy_programs.emplace(uid, EFBCopyShader());
|
||||
EFBCopyShader& shader = it.first->second;
|
||||
bool created = it.second;
|
||||
|
||||
if (created)
|
||||
{
|
||||
ShaderCode code = TextureConversionShaderGen::GenerateShader(APIType::OpenGL, uid.GetUidData());
|
||||
|
||||
std::string geo_program = "";
|
||||
char prefix = 'f';
|
||||
if (g_ActiveConfig.stereo_mode != StereoMode::Off)
|
||||
{
|
||||
geo_program = GLSL_PROGRAM_GS;
|
||||
prefix = 'v';
|
||||
}
|
||||
|
||||
ProgramShaderCache::CompileShader(shader.shader,
|
||||
StringFromFormat(GLSL_PROGRAM_VS, prefix, prefix),
|
||||
code.GetBuffer(), geo_program);
|
||||
|
||||
shader.position_uniform = glGetUniformLocation(shader.shader.glprogid, "copy_position");
|
||||
shader.pixel_height_uniform = glGetUniformLocation(shader.shader.glprogid, "pixel_height");
|
||||
shader.gamma_rcp_uniform = glGetUniformLocation(shader.shader.glprogid, "gamma_rcp");
|
||||
shader.clamp_tb_uniform = glGetUniformLocation(shader.shader.glprogid, "clamp_tb");
|
||||
shader.filter_coefficients_uniform =
|
||||
glGetUniformLocation(shader.shader.glprogid, "filter_coefficients");
|
||||
}
|
||||
|
||||
shader.shader.Bind();
|
||||
|
||||
TargetRectangle R = g_renderer->ConvertEFBRectangle(src_rect);
|
||||
glUniform4f(shader.position_uniform, static_cast<float>(R.left), static_cast<float>(R.top),
|
||||
static_cast<float>(R.right), static_cast<float>(R.bottom));
|
||||
glUniform1f(shader.pixel_height_uniform, g_ActiveConfig.bCopyEFBScaled ?
|
||||
1.0f / g_renderer->GetTargetHeight() :
|
||||
1.0f / EFB_HEIGHT);
|
||||
glUniform1f(shader.gamma_rcp_uniform, 1.0f / gamma);
|
||||
glUniform2f(shader.clamp_tb_uniform,
|
||||
clamp_bottom ? (1.0f - src_rect.bottom / static_cast<float>(EFB_HEIGHT)) : 0.0f,
|
||||
clamp_top ? (1.0f - src_rect.top / static_cast<float>(EFB_HEIGHT)) : 1.0f);
|
||||
glUniform3f(shader.filter_coefficients_uniform, filter_coefficients[0], filter_coefficients[1],
|
||||
filter_coefficients[2]);
|
||||
|
||||
ProgramShaderCache::BindVertexFormat(nullptr);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
} // namespace OGL
|
|
@ -1,108 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GL/GLUtil.h"
|
||||
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
#include "VideoCommon/TextureConversionShader.h"
|
||||
#include "VideoCommon/TextureConverterShaderGen.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
||||
class AbstractTexture;
|
||||
class StreamBuffer;
|
||||
struct TextureConfig;
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
class TextureCache : public TextureCacheBase
|
||||
{
|
||||
public:
|
||||
TextureCache();
|
||||
~TextureCache();
|
||||
|
||||
static TextureCache* GetInstance();
|
||||
|
||||
bool SupportsGPUTextureDecode(TextureFormat format, TLUTFormat palette_format) override;
|
||||
void DecodeTextureOnGPU(TCacheEntry* entry, u32 dst_level, const u8* data, size_t data_size,
|
||||
TextureFormat format, u32 width, u32 height, u32 aligned_width,
|
||||
u32 aligned_height, u32 row_stride, const u8* palette,
|
||||
TLUTFormat palette_format) override;
|
||||
|
||||
const SHADER& GetColorCopyProgram() const;
|
||||
GLuint GetColorCopyPositionUniform() const;
|
||||
|
||||
private:
|
||||
struct PaletteShader
|
||||
{
|
||||
SHADER shader;
|
||||
GLuint buffer_offset_uniform;
|
||||
GLuint multiplier_uniform;
|
||||
GLuint copy_position_uniform;
|
||||
};
|
||||
|
||||
struct TextureDecodingProgramInfo
|
||||
{
|
||||
const TextureConversionShaderTiled::DecodingShaderInfo* base_info = nullptr;
|
||||
SHADER program;
|
||||
GLint uniform_dst_size = -1;
|
||||
GLint uniform_src_size = -1;
|
||||
GLint uniform_src_row_stride = -1;
|
||||
GLint uniform_src_offset = -1;
|
||||
GLint uniform_palette_offset = -1;
|
||||
bool valid = false;
|
||||
};
|
||||
|
||||
void ConvertTexture(TCacheEntry* destination, TCacheEntry* source, const void* palette,
|
||||
TLUTFormat format) override;
|
||||
|
||||
void CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams& params, u32 native_width,
|
||||
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override;
|
||||
|
||||
void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, EFBCopyFormat dst_format, bool is_intensity,
|
||||
float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override;
|
||||
|
||||
bool CompileShaders() override;
|
||||
void DeleteShaders() override;
|
||||
|
||||
bool CompilePaletteShader(TLUTFormat tlutfmt, const std::string& vcode, const std::string& pcode,
|
||||
const std::string& gcode);
|
||||
|
||||
void CreateTextureDecodingResources();
|
||||
void DestroyTextureDecodingResources();
|
||||
|
||||
struct EFBCopyShader
|
||||
{
|
||||
SHADER shader;
|
||||
GLuint position_uniform;
|
||||
GLuint pixel_height_uniform;
|
||||
GLuint gamma_rcp_uniform;
|
||||
GLuint clamp_tb_uniform;
|
||||
GLuint filter_coefficients_uniform;
|
||||
};
|
||||
|
||||
std::map<TextureConversionShaderGen::TCShaderUid, EFBCopyShader> m_efb_copy_programs;
|
||||
|
||||
SHADER m_colorCopyProgram;
|
||||
GLuint m_colorCopyPositionUniform;
|
||||
|
||||
std::array<PaletteShader, 3> m_palette_shaders;
|
||||
std::unique_ptr<StreamBuffer> m_palette_stream_buffer;
|
||||
GLuint m_palette_resolv_texture = 0;
|
||||
|
||||
std::map<std::pair<u32, u32>, TextureDecodingProgramInfo> m_texture_decoding_program_info;
|
||||
std::array<GLuint, TextureConversionShaderTiled::BUFFER_FORMAT_COUNT>
|
||||
m_texture_decoding_buffer_views;
|
||||
};
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// Fast image conversion using OpenGL shaders.
|
||||
|
||||
#include "VideoBackends/OGL/TextureConverter.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/HW/Memmap.h"
|
||||
|
||||
#include "VideoBackends/OGL/FramebufferManager.h"
|
||||
#include "VideoBackends/OGL/OGLTexture.h"
|
||||
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||
#include "VideoBackends/OGL/Render.h"
|
||||
#include "VideoBackends/OGL/SamplerCache.h"
|
||||
#include "VideoBackends/OGL/TextureCache.h"
|
||||
|
||||
#include "VideoCommon/ImageWrite.h"
|
||||
#include "VideoCommon/TextureConversionShader.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
namespace TextureConverter
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct EncodingProgram
|
||||
{
|
||||
SHADER program;
|
||||
GLint copy_position_uniform;
|
||||
GLint y_scale_uniform;
|
||||
GLint gamma_rcp_uniform;
|
||||
GLint clamp_tb_uniform;
|
||||
GLint filter_coefficients_uniform;
|
||||
};
|
||||
|
||||
std::map<EFBCopyParams, EncodingProgram> s_encoding_programs;
|
||||
std::unique_ptr<AbstractTexture> s_encoding_render_texture;
|
||||
|
||||
const int renderBufferWidth = EFB_WIDTH * 4;
|
||||
const int renderBufferHeight = 1024;
|
||||
} // namespace
|
||||
|
||||
static EncodingProgram& GetOrCreateEncodingShader(const EFBCopyParams& params)
|
||||
{
|
||||
auto iter = s_encoding_programs.find(params);
|
||||
if (iter != s_encoding_programs.end())
|
||||
return iter->second;
|
||||
|
||||
const char* shader =
|
||||
TextureConversionShaderTiled::GenerateEncodingShader(params, APIType::OpenGL);
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader)
|
||||
{
|
||||
static int counter = 0;
|
||||
std::string filename =
|
||||
StringFromFormat("%senc_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++);
|
||||
|
||||
SaveData(filename, shader);
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* VProgram = "void main()\n"
|
||||
"{\n"
|
||||
" vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n"
|
||||
" gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n"
|
||||
"}\n";
|
||||
|
||||
EncodingProgram program;
|
||||
if (!ProgramShaderCache::CompileShader(program.program, VProgram, shader))
|
||||
PanicAlert("Failed to compile texture encoding shader.");
|
||||
|
||||
program.copy_position_uniform = glGetUniformLocation(program.program.glprogid, "position");
|
||||
program.y_scale_uniform = glGetUniformLocation(program.program.glprogid, "y_scale");
|
||||
program.gamma_rcp_uniform = glGetUniformLocation(program.program.glprogid, "gamma_rcp");
|
||||
program.clamp_tb_uniform = glGetUniformLocation(program.program.glprogid, "clamp_tb");
|
||||
program.filter_coefficients_uniform =
|
||||
glGetUniformLocation(program.program.glprogid, "filter_coefficients");
|
||||
return s_encoding_programs.emplace(params, program).first->second;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
s_encoding_render_texture = g_renderer->CreateTexture(TextureCache::GetEncodingTextureConfig());
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
s_encoding_render_texture.reset();
|
||||
|
||||
for (auto& program : s_encoding_programs)
|
||||
program.second.program.Destroy();
|
||||
s_encoding_programs.clear();
|
||||
}
|
||||
|
||||
// dst_line_size, writeStride in bytes
|
||||
|
||||
static void EncodeToRamUsingShader(GLuint srcTexture, AbstractStagingTexture* destAddr,
|
||||
u32 dst_line_size, u32 dstHeight, u32 writeStride,
|
||||
bool linearFilter, float y_scale)
|
||||
{
|
||||
FramebufferManager::SetFramebuffer(
|
||||
static_cast<OGLTexture*>(s_encoding_render_texture.get())->GetFramebuffer());
|
||||
|
||||
// set source texture
|
||||
glActiveTexture(GL_TEXTURE9);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, srcTexture);
|
||||
|
||||
// We also linear filtering for both box filtering and downsampling higher resolutions to 1x
|
||||
// TODO: This only produces perfect downsampling for 2x IR, other resolutions will need more
|
||||
// complex down filtering to average all pixels and produce the correct result.
|
||||
// Also, box filtering won't be correct for anything other than 1x IR
|
||||
if (linearFilter || g_renderer->GetEFBScale() != 1 || y_scale > 1.0f)
|
||||
g_sampler_cache->BindLinearSampler(9);
|
||||
else
|
||||
g_sampler_cache->BindNearestSampler(9);
|
||||
|
||||
glViewport(0, 0, (GLsizei)(dst_line_size / 4), (GLsizei)dstHeight);
|
||||
|
||||
ProgramShaderCache::BindVertexFormat(nullptr);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
MathUtil::Rectangle<int> copy_rect(0, 0, dst_line_size / 4, dstHeight);
|
||||
|
||||
destAddr->CopyFromTexture(s_encoding_render_texture.get(), copy_rect, 0, 0, copy_rect);
|
||||
}
|
||||
|
||||
void EncodeToRamFromTexture(AbstractStagingTexture* dest, const EFBCopyParams& params,
|
||||
u32 native_width, u32 bytes_per_row, u32 num_blocks_y,
|
||||
u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half,
|
||||
float y_scale, float gamma, float clamp_top, float clamp_bottom,
|
||||
const TextureCacheBase::CopyFilterCoefficientArray& filter_coefficients)
|
||||
{
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
EncodingProgram& texconv_shader = GetOrCreateEncodingShader(params);
|
||||
|
||||
texconv_shader.program.Bind();
|
||||
glUniform4i(texconv_shader.copy_position_uniform, src_rect.left, src_rect.top, native_width,
|
||||
scale_by_half ? 2 : 1);
|
||||
glUniform1f(texconv_shader.y_scale_uniform, y_scale);
|
||||
glUniform1f(texconv_shader.gamma_rcp_uniform, 1.0f / gamma);
|
||||
glUniform2f(texconv_shader.clamp_tb_uniform, clamp_top, clamp_bottom);
|
||||
glUniform3f(texconv_shader.filter_coefficients_uniform, filter_coefficients[0],
|
||||
filter_coefficients[1], filter_coefficients[2]);
|
||||
|
||||
const GLuint read_texture = params.depth ?
|
||||
FramebufferManager::ResolveAndGetDepthTarget(src_rect) :
|
||||
FramebufferManager::ResolveAndGetRenderTarget(src_rect);
|
||||
|
||||
EncodeToRamUsingShader(read_texture, dest, bytes_per_row, num_blocks_y, memory_stride,
|
||||
scale_by_half && !params.depth, y_scale);
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
} // namespace TextureConverter
|
||||
|
||||
} // namespace OGL
|
|
@ -1,33 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GL/GLUtil.h"
|
||||
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
||||
struct EFBCopyParams;
|
||||
class AbstractStagingTexture;
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
// Converts textures between formats using shaders
|
||||
// TODO: support multiple texture formats
|
||||
namespace TextureConverter
|
||||
{
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
// returns size of the encoded data (in bytes)
|
||||
void EncodeToRamFromTexture(
|
||||
AbstractStagingTexture* dest, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row,
|
||||
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half,
|
||||
float y_scale, float gamma, float clamp_top, float clamp_bottom,
|
||||
const TextureCacheBase::CopyFilterCoefficientArray& filter_coefficients);
|
||||
}
|
||||
|
||||
} // namespace OGL
|
|
@ -9,17 +9,14 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/Align.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/GL/GLExtensions/GLExtensions.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "VideoBackends/OGL/BoundingBox.h"
|
||||
#include "VideoBackends/OGL/OGLPipeline.h"
|
||||
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||
#include "VideoBackends/OGL/Render.h"
|
||||
#include "VideoBackends/OGL/StreamBuffer.h"
|
||||
#include "VideoCommon/BoundingBox.h"
|
||||
|
||||
#include "VideoCommon/IndexGenerator.h"
|
||||
#include "VideoCommon/Statistics.h"
|
||||
|
@ -28,38 +25,127 @@
|
|||
|
||||
namespace OGL
|
||||
{
|
||||
// This are the initially requested size for the buffers expressed in bytes
|
||||
const u32 MAX_IBUFFER_SIZE = 2 * 1024 * 1024;
|
||||
const u32 MAX_VBUFFER_SIZE = 32 * 1024 * 1024;
|
||||
|
||||
VertexManager::VertexManager() : m_cpu_v_buffer(MAX_VBUFFER_SIZE), m_cpu_i_buffer(MAX_IBUFFER_SIZE)
|
||||
static void CheckBufferBinding()
|
||||
{
|
||||
CreateDeviceObjects();
|
||||
// The index buffer is part of the VAO state, therefore we need to bind it first.
|
||||
if (!ProgramShaderCache::IsValidVertexFormatBound())
|
||||
{
|
||||
ProgramShaderCache::BindVertexFormat(
|
||||
static_cast<GLVertexFormat*>(VertexLoaderManager::GetCurrentVertexFormat()));
|
||||
}
|
||||
}
|
||||
|
||||
VertexManager::VertexManager() = default;
|
||||
|
||||
VertexManager::~VertexManager()
|
||||
{
|
||||
DestroyDeviceObjects();
|
||||
}
|
||||
if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
|
||||
{
|
||||
glDeleteTextures(static_cast<GLsizei>(m_texel_buffer_views.size()),
|
||||
m_texel_buffer_views.data());
|
||||
}
|
||||
|
||||
void VertexManager::CreateDeviceObjects()
|
||||
{
|
||||
m_vertex_buffer = StreamBuffer::Create(GL_ARRAY_BUFFER, MAX_VBUFFER_SIZE);
|
||||
m_index_buffer = StreamBuffer::Create(GL_ELEMENT_ARRAY_BUFFER, MAX_IBUFFER_SIZE);
|
||||
}
|
||||
|
||||
void VertexManager::DestroyDeviceObjects()
|
||||
{
|
||||
m_vertex_buffer.reset();
|
||||
// VAO must be found when destroying the index buffer.
|
||||
CheckBufferBinding();
|
||||
m_texel_buffer.reset();
|
||||
m_index_buffer.reset();
|
||||
m_vertex_buffer.reset();
|
||||
}
|
||||
|
||||
bool VertexManager::Initialize()
|
||||
{
|
||||
if (!VertexManagerBase::Initialize())
|
||||
return false;
|
||||
|
||||
m_vertex_buffer = StreamBuffer::Create(GL_ARRAY_BUFFER, VERTEX_STREAM_BUFFER_SIZE);
|
||||
m_index_buffer = StreamBuffer::Create(GL_ELEMENT_ARRAY_BUFFER, INDEX_STREAM_BUFFER_SIZE);
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
|
||||
{
|
||||
// The minimum MAX_TEXTURE_BUFFER_SIZE that the spec mandates is 65KB, we are asking for a 1MB
|
||||
// buffer here. This buffer is also used as storage for undecoded textures when compute shader
|
||||
// texture decoding is enabled, in which case the requested size is 32MB.
|
||||
GLint max_buffer_size;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &max_buffer_size);
|
||||
m_texel_buffer = StreamBuffer::Create(
|
||||
GL_TEXTURE_BUFFER, std::min(max_buffer_size, static_cast<GLint>(TEXEL_STREAM_BUFFER_SIZE)));
|
||||
|
||||
// Allocate texture views backed by buffer.
|
||||
static constexpr std::array<std::pair<TexelBufferFormat, GLenum>, NUM_TEXEL_BUFFER_FORMATS>
|
||||
format_mapping = {{
|
||||
{TEXEL_BUFFER_FORMAT_R8_UINT, GL_R8UI},
|
||||
{TEXEL_BUFFER_FORMAT_R16_UINT, GL_R16UI},
|
||||
{TEXEL_BUFFER_FORMAT_RGBA8_UINT, GL_RGBA8},
|
||||
{TEXEL_BUFFER_FORMAT_R32G32_UINT, GL_RG32UI},
|
||||
}};
|
||||
glGenTextures(static_cast<GLsizei>(m_texel_buffer_views.size()), m_texel_buffer_views.data());
|
||||
glActiveTexture(GL_MUTABLE_TEXTURE_INDEX);
|
||||
for (const auto& it : format_mapping)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[it.first]);
|
||||
glTexBuffer(GL_TEXTURE_BUFFER, it.second, m_texel_buffer->GetGLBufferId());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VertexManager::UploadUtilityUniforms(const void* uniforms, u32 uniforms_size)
|
||||
{
|
||||
ProgramShaderCache::InvalidateConstants();
|
||||
InvalidateConstants();
|
||||
ProgramShaderCache::UploadConstants(uniforms, uniforms_size);
|
||||
}
|
||||
|
||||
bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format,
|
||||
u32* out_offset)
|
||||
{
|
||||
if (data_size > m_texel_buffer->GetSize())
|
||||
return false;
|
||||
|
||||
const u32 elem_size = GetTexelBufferElementSize(format);
|
||||
const auto dst = m_texel_buffer->Map(data_size, elem_size);
|
||||
std::memcpy(dst.first, data, data_size);
|
||||
ADDSTAT(stats.thisFrame.bytesUniformStreamed, data_size);
|
||||
*out_offset = dst.second / elem_size;
|
||||
m_texel_buffer->Unmap(data_size);
|
||||
|
||||
// Bind the correct view to the texel buffer slot.
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(format)]);
|
||||
Renderer::GetInstance()->InvalidateTextureBinding(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format,
|
||||
u32* out_offset, const void* palette_data, u32 palette_size,
|
||||
TexelBufferFormat palette_format, u32* out_palette_offset)
|
||||
{
|
||||
const u32 elem_size = GetTexelBufferElementSize(format);
|
||||
const u32 palette_elem_size = GetTexelBufferElementSize(palette_format);
|
||||
const u32 reserve_size = data_size + palette_size + palette_elem_size;
|
||||
if (reserve_size > m_texel_buffer->GetSize())
|
||||
return false;
|
||||
|
||||
const auto dst = m_texel_buffer->Map(reserve_size, elem_size);
|
||||
const u32 palette_byte_offset = Common::AlignUp(data_size, palette_elem_size);
|
||||
std::memcpy(dst.first, data, data_size);
|
||||
std::memcpy(dst.first + palette_byte_offset, palette_data, palette_size);
|
||||
ADDSTAT(stats.thisFrame.bytesUniformStreamed, palette_byte_offset + palette_size);
|
||||
*out_offset = dst.second / elem_size;
|
||||
*out_palette_offset = (dst.second + palette_byte_offset) / palette_elem_size;
|
||||
m_texel_buffer->Unmap(palette_byte_offset + palette_size);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(format)]);
|
||||
Renderer::GetInstance()->InvalidateTextureBinding(0);
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(palette_format)]);
|
||||
Renderer::GetInstance()->InvalidateTextureBinding(1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GLuint VertexManager::GetVertexBufferHandle() const
|
||||
{
|
||||
return m_vertex_buffer->m_buffer;
|
||||
|
@ -70,37 +156,16 @@ GLuint VertexManager::GetIndexBufferHandle() const
|
|||
return m_index_buffer->m_buffer;
|
||||
}
|
||||
|
||||
static void CheckBufferBinding()
|
||||
void VertexManager::ResetBuffer(u32 vertex_stride)
|
||||
{
|
||||
// The index buffer is part of the VAO state, therefore we need to bind it first.
|
||||
if (!ProgramShaderCache::IsValidVertexFormatBound())
|
||||
{
|
||||
ProgramShaderCache::BindVertexFormat(
|
||||
static_cast<GLVertexFormat*>(VertexLoaderManager::GetCurrentVertexFormat()));
|
||||
}
|
||||
}
|
||||
CheckBufferBinding();
|
||||
|
||||
void VertexManager::ResetBuffer(u32 vertex_stride, bool cull_all)
|
||||
{
|
||||
if (cull_all)
|
||||
{
|
||||
// This buffer isn't getting sent to the GPU. Just allocate it on the cpu.
|
||||
m_cur_buffer_pointer = m_base_buffer_pointer = m_cpu_v_buffer.data();
|
||||
m_end_buffer_pointer = m_base_buffer_pointer + m_cpu_v_buffer.size();
|
||||
auto buffer = m_vertex_buffer->Map(MAXVBUFFERSIZE, vertex_stride);
|
||||
m_cur_buffer_pointer = m_base_buffer_pointer = buffer.first;
|
||||
m_end_buffer_pointer = buffer.first + MAXVBUFFERSIZE;
|
||||
|
||||
IndexGenerator::Start((u16*)m_cpu_i_buffer.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckBufferBinding();
|
||||
|
||||
auto buffer = m_vertex_buffer->Map(MAXVBUFFERSIZE, vertex_stride);
|
||||
m_cur_buffer_pointer = m_base_buffer_pointer = buffer.first;
|
||||
m_end_buffer_pointer = buffer.first + MAXVBUFFERSIZE;
|
||||
|
||||
buffer = m_index_buffer->Map(MAXIBUFFERSIZE * sizeof(u16));
|
||||
IndexGenerator::Start((u16*)buffer.first);
|
||||
}
|
||||
buffer = m_index_buffer->Map(MAXIBUFFERSIZE * sizeof(u16));
|
||||
IndexGenerator::Start((u16*)buffer.first);
|
||||
}
|
||||
|
||||
void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices,
|
||||
|
@ -120,31 +185,8 @@ void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_in
|
|||
ADDSTAT(stats.thisFrame.bytesIndexStreamed, index_data_size);
|
||||
}
|
||||
|
||||
void VertexManager::UploadConstants()
|
||||
void VertexManager::UploadUniforms()
|
||||
{
|
||||
ProgramShaderCache::UploadConstants();
|
||||
}
|
||||
|
||||
void VertexManager::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex)
|
||||
{
|
||||
if (::BoundingBox::active && !g_Config.BBoxUseFragmentShaderImplementation())
|
||||
{
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
}
|
||||
|
||||
if (m_current_pipeline_object)
|
||||
{
|
||||
static_cast<Renderer*>(g_renderer.get())->SetPipeline(m_current_pipeline_object);
|
||||
static_cast<Renderer*>(g_renderer.get())->DrawIndexed(base_index, num_indices, base_vertex);
|
||||
}
|
||||
|
||||
if (::BoundingBox::active && !g_Config.BBoxUseFragmentShaderImplementation())
|
||||
{
|
||||
OGL::BoundingBox::StencilWasUpdated();
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
}
|
||||
|
||||
g_Config.iSaveTargetId++;
|
||||
ClearEFBCache();
|
||||
}
|
||||
} // namespace OGL
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GL/GLUtil.h"
|
||||
|
@ -26,35 +26,34 @@ public:
|
|||
|
||||
// Handles the OpenGL details of drawing lots of vertices quickly.
|
||||
// Other functionality is moving out.
|
||||
class VertexManager : public VertexManagerBase
|
||||
class VertexManager final : public VertexManagerBase
|
||||
{
|
||||
public:
|
||||
VertexManager();
|
||||
~VertexManager();
|
||||
~VertexManager() override;
|
||||
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
|
||||
bool Initialize() override;
|
||||
|
||||
void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) override;
|
||||
bool UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format,
|
||||
u32* out_offset) override;
|
||||
bool UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format, u32* out_offset,
|
||||
const void* palette_data, u32 palette_size,
|
||||
TexelBufferFormat palette_format, u32* out_palette_offset) override;
|
||||
|
||||
GLuint GetVertexBufferHandle() const;
|
||||
GLuint GetIndexBufferHandle() const;
|
||||
|
||||
protected:
|
||||
void CreateDeviceObjects() override;
|
||||
void DestroyDeviceObjects() override;
|
||||
void ResetBuffer(u32 vertex_stride, bool cull_all) override;
|
||||
void ResetBuffer(u32 vertex_stride) override;
|
||||
void CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, u32* out_base_vertex,
|
||||
u32* out_base_index) override;
|
||||
void UploadConstants() override;
|
||||
void DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) override;
|
||||
void UploadUniforms() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<StreamBuffer> m_vertex_buffer;
|
||||
std::unique_ptr<StreamBuffer> m_index_buffer;
|
||||
|
||||
// Alternative buffers in CPU memory for primatives we are going to discard.
|
||||
std::vector<u8> m_cpu_v_buffer;
|
||||
std::vector<u16> m_cpu_i_buffer;
|
||||
std::unique_ptr<StreamBuffer> m_texel_buffer;
|
||||
std::array<GLuint, NUM_TEXEL_BUFFER_FORMATS> m_texel_buffer_views{};
|
||||
};
|
||||
} // namespace OGL
|
||||
|
|
|
@ -50,13 +50,11 @@ Make AA apply instantly during gameplay if possible
|
|||
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||
#include "VideoBackends/OGL/Render.h"
|
||||
#include "VideoBackends/OGL/SamplerCache.h"
|
||||
#include "VideoBackends/OGL/TextureCache.h"
|
||||
#include "VideoBackends/OGL/TextureConverter.h"
|
||||
#include "VideoBackends/OGL/VertexManager.h"
|
||||
#include "VideoBackends/OGL/VideoBackend.h"
|
||||
|
||||
#include "VideoCommon/OnScreenDisplay.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
#include "VideoCommon/FramebufferManager.h"
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace OGL
|
||||
|
@ -78,6 +76,7 @@ void VideoBackend::InitBackendInfo()
|
|||
{
|
||||
g_Config.backend_info.api_type = APIType::OpenGL;
|
||||
g_Config.backend_info.MaxTextureSize = 16384;
|
||||
g_Config.backend_info.bUsesLowerLeftOrigin = true;
|
||||
g_Config.backend_info.bSupportsExclusiveFullscreen = false;
|
||||
g_Config.backend_info.bSupportsOversizedViewports = true;
|
||||
g_Config.backend_info.bSupportsGeometryShaders = true;
|
||||
|
@ -89,6 +88,7 @@ void VideoBackend::InitBackendInfo()
|
|||
g_Config.backend_info.bSupportsLogicOp = true;
|
||||
g_Config.backend_info.bSupportsMultithreading = false;
|
||||
g_Config.backend_info.bSupportsCopyToVram = true;
|
||||
g_Config.backend_info.bSupportsLargePoints = true;
|
||||
|
||||
// TODO: There is a bug here, if texel buffers are not supported the graphics options
|
||||
// will show the option when it is not supported. The only way around this would be
|
||||
|
@ -173,17 +173,26 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
|
|||
return false;
|
||||
|
||||
g_renderer = std::make_unique<Renderer>(std::move(main_gl_context), wsi.render_surface_scale);
|
||||
g_vertex_manager = std::make_unique<VertexManager>();
|
||||
g_perf_query = GetPerfQuery();
|
||||
ProgramShaderCache::Init();
|
||||
g_texture_cache = std::make_unique<TextureCache>();
|
||||
g_sampler_cache = std::make_unique<SamplerCache>();
|
||||
g_vertex_manager = std::make_unique<VertexManager>();
|
||||
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
|
||||
if (!g_renderer->Initialize())
|
||||
g_framebuffer_manager = std::make_unique<FramebufferManager>();
|
||||
g_perf_query = GetPerfQuery();
|
||||
g_texture_cache = std::make_unique<TextureCacheBase>();
|
||||
g_sampler_cache = std::make_unique<SamplerCache>();
|
||||
BoundingBox::Init();
|
||||
|
||||
if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() ||
|
||||
!g_renderer->Initialize() || !g_framebuffer_manager->Initialize() ||
|
||||
!g_texture_cache->Initialize())
|
||||
{
|
||||
PanicAlert("Failed to initialize renderer classes");
|
||||
Shutdown();
|
||||
return false;
|
||||
TextureConverter::Init();
|
||||
BoundingBox::Init(g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight());
|
||||
return g_shader_cache->Initialize();
|
||||
}
|
||||
|
||||
g_shader_cache->InitializeShaderCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoBackend::Shutdown()
|
||||
|
@ -191,13 +200,13 @@ void VideoBackend::Shutdown()
|
|||
g_shader_cache->Shutdown();
|
||||
g_renderer->Shutdown();
|
||||
BoundingBox::Shutdown();
|
||||
TextureConverter::Shutdown();
|
||||
g_shader_cache.reset();
|
||||
g_sampler_cache.reset();
|
||||
g_texture_cache.reset();
|
||||
ProgramShaderCache::Shutdown();
|
||||
g_perf_query.reset();
|
||||
g_vertex_manager.reset();
|
||||
g_framebuffer_manager.reset();
|
||||
g_shader_cache.reset();
|
||||
ProgramShaderCache::Shutdown();
|
||||
g_renderer.reset();
|
||||
ShutdownShared();
|
||||
}
|
||||
|
|
|
@ -19,11 +19,15 @@
|
|||
|
||||
#include "VideoCommon/AbstractPipeline.h"
|
||||
#include "VideoCommon/AbstractShader.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
#include "VideoCommon/BoundingBox.h"
|
||||
#include "VideoCommon/NativeVertexFormat.h"
|
||||
#include "VideoCommon/OnScreenDisplay.h"
|
||||
#include "VideoCommon/VideoBackendBase.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace SW
|
||||
{
|
||||
SWRenderer::SWRenderer(std::unique_ptr<SWOGLWindow> window)
|
||||
: ::Renderer(static_cast<int>(MAX_XFB_WIDTH), static_cast<int>(MAX_XFB_HEIGHT), 1.0f,
|
||||
AbstractTextureFormat::RGBA8),
|
||||
|
@ -38,21 +42,20 @@ bool SWRenderer::IsHeadless() const
|
|||
|
||||
std::unique_ptr<AbstractTexture> SWRenderer::CreateTexture(const TextureConfig& config)
|
||||
{
|
||||
return std::make_unique<SW::SWTexture>(config);
|
||||
return std::make_unique<SWTexture>(config);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractStagingTexture>
|
||||
SWRenderer::CreateStagingTexture(StagingTextureType type, const TextureConfig& config)
|
||||
{
|
||||
return std::make_unique<SW::SWStagingTexture>(type, config);
|
||||
return std::make_unique<SWStagingTexture>(type, config);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
SWRenderer::CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment)
|
||||
SWRenderer::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment)
|
||||
{
|
||||
return SW::SWFramebuffer::Create(static_cast<const SW::SWTexture*>(color_attachment),
|
||||
static_cast<const SW::SWTexture*>(depth_attachment));
|
||||
return SWFramebuffer::Create(static_cast<SWTexture*>(color_attachment),
|
||||
static_cast<SWTexture*>(depth_attachment));
|
||||
}
|
||||
|
||||
class SWShader final : public AbstractShader
|
||||
|
@ -132,18 +135,15 @@ void SWRenderer::BBoxWrite(int index, u16 value)
|
|||
BoundingBox::coords[index] = value;
|
||||
}
|
||||
|
||||
TargetRectangle SWRenderer::ConvertEFBRectangle(const EFBRectangle& rc)
|
||||
{
|
||||
TargetRectangle result;
|
||||
result.left = rc.left;
|
||||
result.top = rc.top;
|
||||
result.right = rc.right;
|
||||
result.bottom = rc.bottom;
|
||||
return result;
|
||||
}
|
||||
|
||||
void SWRenderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable,
|
||||
bool zEnable, u32 color, u32 z)
|
||||
{
|
||||
EfbCopy::ClearEfb();
|
||||
}
|
||||
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
SWRenderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
{
|
||||
return std::make_unique<NativeVertexFormat>(vtx_decl);
|
||||
}
|
||||
} // namespace SW
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
|
||||
class SWOGLWindow;
|
||||
|
||||
class SWRenderer : public Renderer
|
||||
namespace SW
|
||||
{
|
||||
class SWRenderer final : public Renderer
|
||||
{
|
||||
public:
|
||||
SWRenderer(std::unique_ptr<SWOGLWindow> window);
|
||||
|
@ -23,13 +25,14 @@ public:
|
|||
std::unique_ptr<AbstractStagingTexture>
|
||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
CreateFramebuffer(const AbstractTexture* color_attachment,
|
||||
const AbstractTexture* depth_attachment) override;
|
||||
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
|
||||
|
||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, const char* source,
|
||||
size_t length) override;
|
||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||
size_t length) override;
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
|
||||
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config) override;
|
||||
|
||||
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
|
||||
|
@ -37,15 +40,18 @@ public:
|
|||
u16 BBoxRead(int index) override;
|
||||
void BBoxWrite(int index, u16 value) override;
|
||||
|
||||
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
|
||||
|
||||
void RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc) override;
|
||||
|
||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
|
||||
u32 color, u32 z) override;
|
||||
|
||||
void ReinterpretPixelData(unsigned int convtype) override {}
|
||||
void ReinterpretPixelData(EFBReinterpretType convtype) override {}
|
||||
|
||||
void ScaleTexture(AbstractFramebuffer* dst_framebuffer, const MathUtil::Rectangle<int>& dst_rect,
|
||||
const AbstractTexture* src_texture,
|
||||
const MathUtil::Rectangle<int>& src_rect) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<SWOGLWindow> m_window;
|
||||
};
|
||||
} // namespace SW
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/Software/SWTexture.h"
|
||||
#include "VideoBackends/Software/SWRenderer.h"
|
||||
|
||||
#include <cstring>
|
||||
#include "Common/Assert.h"
|
||||
|
@ -45,6 +46,25 @@ void CopyTextureData(const TextureConfig& src_config, const u8* src_ptr, u32 src
|
|||
dst_ptr += dst_stride;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void SWRenderer::ScaleTexture(AbstractFramebuffer* dst_framebuffer,
|
||||
const MathUtil::Rectangle<int>& dst_rect,
|
||||
const AbstractTexture* src_texture,
|
||||
const MathUtil::Rectangle<int>& src_rect)
|
||||
{
|
||||
const SWTexture* software_source_texture = static_cast<const SWTexture*>(src_texture);
|
||||
SWTexture* software_dest_texture = static_cast<SWTexture*>(dst_framebuffer->GetColorAttachment());
|
||||
|
||||
std::vector<Pixel> source_pixels;
|
||||
source_pixels.resize(src_rect.GetHeight() * src_rect.GetWidth() * 4);
|
||||
memcpy(source_pixels.data(), software_source_texture->GetData(), source_pixels.size());
|
||||
|
||||
std::vector<Pixel> destination_pixels;
|
||||
destination_pixels.resize(dst_rect.GetHeight() * dst_rect.GetWidth() * 4);
|
||||
|
||||
CopyRegion(source_pixels.data(), src_rect, destination_pixels.data(), dst_rect);
|
||||
memcpy(software_dest_texture->GetData(), destination_pixels.data(), destination_pixels.size());
|
||||
}
|
||||
|
||||
SWTexture::SWTexture(const TextureConfig& tex_config) : AbstractTexture(tex_config)
|
||||
|
@ -62,30 +82,6 @@ void SWTexture::CopyRectangleFromTexture(const AbstractTexture* src,
|
|||
src_rect.left, src_rect.top, src_rect.GetWidth(), src_rect.GetHeight(), m_config,
|
||||
m_data.data(), dst_rect.left, dst_rect.top);
|
||||
}
|
||||
void SWTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
const MathUtil::Rectangle<int>& srcrect,
|
||||
const MathUtil::Rectangle<int>& dstrect)
|
||||
{
|
||||
const SWTexture* software_source_texture = static_cast<const SWTexture*>(source);
|
||||
|
||||
if (srcrect.GetWidth() == dstrect.GetWidth() && srcrect.GetHeight() == dstrect.GetHeight())
|
||||
{
|
||||
m_data.assign(software_source_texture->GetData(),
|
||||
software_source_texture->GetData() + m_data.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<Pixel> source_pixels;
|
||||
source_pixels.resize(srcrect.GetHeight() * srcrect.GetWidth() * 4);
|
||||
memcpy(source_pixels.data(), software_source_texture->GetData(), source_pixels.size());
|
||||
|
||||
std::vector<Pixel> destination_pixels;
|
||||
destination_pixels.resize(dstrect.GetHeight() * dstrect.GetWidth() * 4);
|
||||
|
||||
CopyRegion(source_pixels.data(), srcrect, destination_pixels.data(), dstrect);
|
||||
memcpy(GetData(), destination_pixels.data(), destination_pixels.size());
|
||||
}
|
||||
}
|
||||
void SWTexture::ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
|
||||
u32 layer, u32 level)
|
||||
{
|
||||
|
@ -153,14 +149,16 @@ void SWStagingTexture::Flush()
|
|||
m_needs_flush = false;
|
||||
}
|
||||
|
||||
SWFramebuffer::SWFramebuffer(AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
|
||||
SWFramebuffer::SWFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
||||
AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
|
||||
u32 width, u32 height, u32 layers, u32 samples)
|
||||
: AbstractFramebuffer(color_format, depth_format, width, height, layers, samples)
|
||||
: AbstractFramebuffer(color_attachment, depth_attachment, color_format, depth_format, width,
|
||||
height, layers, samples)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<SWFramebuffer> SWFramebuffer::Create(const SWTexture* color_attachment,
|
||||
const SWTexture* depth_attachment)
|
||||
std::unique_ptr<SWFramebuffer> SWFramebuffer::Create(SWTexture* color_attachment,
|
||||
SWTexture* depth_attachment)
|
||||
{
|
||||
if (!ValidateConfig(color_attachment, depth_attachment))
|
||||
return nullptr;
|
||||
|
@ -175,8 +173,8 @@ std::unique_ptr<SWFramebuffer> SWFramebuffer::Create(const SWTexture* color_atta
|
|||
const u32 layers = either_attachment->GetLayers();
|
||||
const u32 samples = either_attachment->GetSamples();
|
||||
|
||||
return std::make_unique<SWFramebuffer>(color_format, depth_format, width, height, layers,
|
||||
samples);
|
||||
return std::make_unique<SWFramebuffer>(color_attachment, depth_attachment, color_format,
|
||||
depth_format, width, height, layers, samples);
|
||||
}
|
||||
|
||||
} // namespace SW
|
||||
|
|
|
@ -25,9 +25,6 @@ public:
|
|||
const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
|
||||
u32 src_level, const MathUtil::Rectangle<int>& dst_rect,
|
||||
u32 dst_layer, u32 dst_level) override;
|
||||
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||
const MathUtil::Rectangle<int>& srcrect,
|
||||
const MathUtil::Rectangle<int>& dstrect) override;
|
||||
void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
|
||||
u32 layer, u32 level) override;
|
||||
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
|
@ -66,12 +63,13 @@ private:
|
|||
class SWFramebuffer final : public AbstractFramebuffer
|
||||
{
|
||||
public:
|
||||
explicit SWFramebuffer(AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
|
||||
explicit SWFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
||||
AbstractTextureFormat color_format, AbstractTextureFormat depth_format,
|
||||
u32 width, u32 height, u32 layers, u32 samples);
|
||||
~SWFramebuffer() override = default;
|
||||
|
||||
static std::unique_ptr<SWFramebuffer> Create(const SWTexture* color_attachment,
|
||||
const SWTexture* depth_attachment);
|
||||
static std::unique_ptr<SWFramebuffer> Create(SWTexture* color_attachment,
|
||||
SWTexture* depth_attachment);
|
||||
};
|
||||
|
||||
} // namespace SW
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "VideoBackends/Software/DebugUtil.h"
|
||||
#include "VideoBackends/Software/NativeVertexFormat.h"
|
||||
#include "VideoBackends/Software/Rasterizer.h"
|
||||
#include "VideoBackends/Software/SWRenderer.h"
|
||||
#include "VideoBackends/Software/Tev.h"
|
||||
#include "VideoBackends/Software/TransformUnit.h"
|
||||
|
||||
|
@ -27,48 +28,9 @@
|
|||
#include "VideoCommon/VideoConfig.h"
|
||||
#include "VideoCommon/XFMemory.h"
|
||||
|
||||
class NullNativeVertexFormat : public NativeVertexFormat
|
||||
{
|
||||
public:
|
||||
NullNativeVertexFormat(const PortableVertexDeclaration& _vtx_decl) { vtx_decl = _vtx_decl; }
|
||||
};
|
||||
SWVertexLoader::SWVertexLoader() = default;
|
||||
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
SWVertexLoader::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
{
|
||||
return std::make_unique<NullNativeVertexFormat>(vtx_decl);
|
||||
}
|
||||
|
||||
SWVertexLoader::SWVertexLoader()
|
||||
: m_local_vertex_buffer(MAXVBUFFERSIZE), m_local_index_buffer(MAXIBUFFERSIZE)
|
||||
{
|
||||
}
|
||||
|
||||
SWVertexLoader::~SWVertexLoader()
|
||||
{
|
||||
}
|
||||
|
||||
void SWVertexLoader::UploadUtilityUniforms(const void* uniforms, u32 uniforms_size)
|
||||
{
|
||||
}
|
||||
|
||||
void SWVertexLoader::ResetBuffer(u32 vertex_stride, bool cull_all)
|
||||
{
|
||||
m_cur_buffer_pointer = m_base_buffer_pointer = m_local_vertex_buffer.data();
|
||||
m_end_buffer_pointer = m_cur_buffer_pointer + m_local_vertex_buffer.size();
|
||||
IndexGenerator::Start(m_local_index_buffer.data());
|
||||
}
|
||||
|
||||
void SWVertexLoader::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices,
|
||||
u32* out_base_vertex, u32* out_base_index)
|
||||
{
|
||||
*out_base_vertex = 0;
|
||||
*out_base_index = 0;
|
||||
}
|
||||
|
||||
void SWVertexLoader::UploadConstants()
|
||||
{
|
||||
}
|
||||
SWVertexLoader::~SWVertexLoader() = default;
|
||||
|
||||
void SWVertexLoader::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex)
|
||||
{
|
||||
|
@ -104,7 +66,7 @@ void SWVertexLoader::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_
|
|||
|
||||
for (u32 i = 0; i < IndexGenerator::GetIndexLen(); i++)
|
||||
{
|
||||
const u16 index = m_local_index_buffer[i];
|
||||
const u16 index = m_cpu_index_buffer[i];
|
||||
memset(static_cast<void*>(&m_vertex), 0, sizeof(m_vertex));
|
||||
|
||||
// Super Mario Sunshine requires those to be zero for those debug boxes.
|
||||
|
@ -224,8 +186,8 @@ static void ReadVertexAttribute(T* dst, DataReader src, const AttributeFormat& f
|
|||
|
||||
void SWVertexLoader::ParseVertex(const PortableVertexDeclaration& vdec, int index)
|
||||
{
|
||||
DataReader src(m_local_vertex_buffer.data(),
|
||||
m_local_vertex_buffer.data() + m_local_vertex_buffer.size());
|
||||
DataReader src(m_cpu_vertex_buffer.data(),
|
||||
m_cpu_vertex_buffer.data() + m_cpu_vertex_buffer.size());
|
||||
src.Skip(index * vdec.stride);
|
||||
|
||||
ReadVertexAttribute<float>(&m_vertex.position[0], src, vdec.position, 0, 3, false);
|
||||
|
|
|
@ -20,24 +20,12 @@ public:
|
|||
SWVertexLoader();
|
||||
~SWVertexLoader();
|
||||
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
CreateNativeVertexFormat(const PortableVertexDeclaration& vdec) override;
|
||||
|
||||
void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) override;
|
||||
|
||||
protected:
|
||||
void ResetBuffer(u32 vertex_stride, bool cull_all) override;
|
||||
void CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, u32* out_base_vertex,
|
||||
u32* out_base_index) override;
|
||||
void UploadConstants() override;
|
||||
void DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) override;
|
||||
|
||||
void SetFormat(u8 attributeIndex, u8 primitiveType);
|
||||
void ParseVertex(const PortableVertexDeclaration& vdec, int index);
|
||||
|
||||
std::vector<u8> m_local_vertex_buffer;
|
||||
std::vector<u16> m_local_index_buffer;
|
||||
|
||||
InputVertexData m_vertex;
|
||||
SetupUnit m_setup_unit;
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "Common/Common.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GL/GLContext.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
#include "VideoBackends/Software/Clipper.h"
|
||||
#include "VideoBackends/Software/DebugUtil.h"
|
||||
|
@ -22,14 +23,11 @@
|
|||
#include "VideoBackends/Software/TextureCache.h"
|
||||
#include "VideoBackends/Software/VideoBackend.h"
|
||||
|
||||
#include "VideoCommon/FramebufferManagerBase.h"
|
||||
#include "VideoCommon/OnScreenDisplay.h"
|
||||
#include "VideoCommon/FramebufferManager.h"
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
#define VSYNC_ENABLED 0
|
||||
|
||||
namespace SW
|
||||
{
|
||||
class PerfQuery : public PerfQueryBase
|
||||
|
@ -59,6 +57,7 @@ void VideoSoftware::InitBackendInfo()
|
|||
{
|
||||
g_Config.backend_info.api_type = APIType::Nothing;
|
||||
g_Config.backend_info.MaxTextureSize = 16384;
|
||||
g_Config.backend_info.bUsesLowerLeftOrigin = false;
|
||||
g_Config.backend_info.bSupports3DVision = false;
|
||||
g_Config.backend_info.bSupportsDualSourceBlend = true;
|
||||
g_Config.backend_info.bSupportsEarlyZ = true;
|
||||
|
@ -70,6 +69,7 @@ void VideoSoftware::InitBackendInfo()
|
|||
g_Config.backend_info.bSupportsST3CTextures = false;
|
||||
g_Config.backend_info.bSupportsBPTCTextures = false;
|
||||
g_Config.backend_info.bSupportsCopyToVram = false;
|
||||
g_Config.backend_info.bSupportsLargePoints = false;
|
||||
g_Config.backend_info.bSupportsFramebufferFetch = false;
|
||||
g_Config.backend_info.bSupportsBackgroundCompiling = false;
|
||||
g_Config.backend_info.bSupportsLogicOp = true;
|
||||
|
@ -92,10 +92,22 @@ bool VideoSoftware::Initialize(const WindowSystemInfo& wsi)
|
|||
|
||||
g_renderer = std::make_unique<SWRenderer>(std::move(window));
|
||||
g_vertex_manager = std::make_unique<SWVertexLoader>();
|
||||
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
|
||||
g_framebuffer_manager = std::make_unique<FramebufferManager>();
|
||||
g_perf_query = std::make_unique<PerfQuery>();
|
||||
g_texture_cache = std::make_unique<TextureCache>();
|
||||
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
|
||||
return g_renderer->Initialize() && g_shader_cache->Initialize();
|
||||
|
||||
if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() ||
|
||||
!g_renderer->Initialize() || !g_framebuffer_manager->Initialize() ||
|
||||
!g_texture_cache->Initialize())
|
||||
{
|
||||
PanicAlert("Failed to initialize renderer classes");
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
g_shader_cache->InitializeShaderCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoSoftware::Shutdown()
|
||||
|
@ -107,9 +119,10 @@ void VideoSoftware::Shutdown()
|
|||
g_renderer->Shutdown();
|
||||
|
||||
DebugUtil::Shutdown();
|
||||
g_framebuffer_manager.reset();
|
||||
g_texture_cache.reset();
|
||||
g_perf_query.reset();
|
||||
g_framebuffer_manager.reset();
|
||||
g_shader_cache.reset();
|
||||
g_vertex_manager.reset();
|
||||
g_renderer.reset();
|
||||
ShutdownShared();
|
||||
|
|
|
@ -9,27 +9,19 @@ namespace SW
|
|||
{
|
||||
class TextureCache : public TextureCacheBase
|
||||
{
|
||||
public:
|
||||
bool CompileShaders() override { return true; }
|
||||
void DeleteShaders() override {}
|
||||
void ConvertTexture(TCacheEntry* entry, TCacheEntry* unconverted, const void* palette,
|
||||
TLUTFormat format) override
|
||||
{
|
||||
}
|
||||
protected:
|
||||
void CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams& params, u32 native_width,
|
||||
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override
|
||||
const EFBCopyFilterCoefficients& filter_coefficients) override
|
||||
{
|
||||
TextureEncoder::Encode(dst, params, native_width, bytes_per_row, num_blocks_y, memory_stride,
|
||||
src_rect, scale_by_half, y_scale, gamma);
|
||||
}
|
||||
|
||||
private:
|
||||
void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, EFBCopyFormat dst_format, bool is_intensity,
|
||||
float gamma, bool clamp_top, bool clamp_bottom,
|
||||
const CopyFilterCoefficientArray& filter_coefficients) override
|
||||
const EFBCopyFilterCoefficients& filter_coefficients) override
|
||||
{
|
||||
// TODO: If we ever want to "fake" vram textures, we would need to implement this
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "VideoBackends/Vulkan/Renderer.h"
|
||||
#include "VideoBackends/Vulkan/StagingBuffer.h"
|
||||
#include "VideoBackends/Vulkan/StateTracker.h"
|
||||
#include "VideoBackends/Vulkan/Util.h"
|
||||
#include "VideoBackends/Vulkan/VulkanContext.h"
|
||||
|
||||
namespace Vulkan
|
||||
|
@ -33,7 +32,7 @@ BoundingBox::~BoundingBox()
|
|||
|
||||
bool BoundingBox::Initialize()
|
||||
{
|
||||
if (!g_vulkan_context->SupportsBoundingBox())
|
||||
if (!g_ActiveConfig.backend_info.bSupportsBBox)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Vulkan: Bounding box is unsupported by your device.");
|
||||
return true;
|
||||
|
@ -45,6 +44,8 @@ bool BoundingBox::Initialize()
|
|||
if (!CreateReadbackBuffer())
|
||||
return false;
|
||||
|
||||
// Bind bounding box to state tracker
|
||||
StateTracker::GetInstance()->SetSSBO(m_gpu_buffer, 0, BUFFER_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -79,7 +80,7 @@ void BoundingBox::Flush()
|
|||
StateTracker::GetInstance()->EndRenderPass();
|
||||
|
||||
// Ensure GPU buffer is in a state where it can be transferred to.
|
||||
Util::BufferMemoryBarrier(
|
||||
StagingBuffer::BufferMemoryBarrier(
|
||||
g_command_buffer_mgr->GetCurrentCommandBuffer(), m_gpu_buffer,
|
||||
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, 0,
|
||||
BUFFER_SIZE, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
|
@ -95,7 +96,7 @@ void BoundingBox::Flush()
|
|||
// Restore fragment shader access to the buffer.
|
||||
if (updated_buffer)
|
||||
{
|
||||
Util::BufferMemoryBarrier(
|
||||
StagingBuffer::BufferMemoryBarrier(
|
||||
g_command_buffer_mgr->GetCurrentCommandBuffer(), m_gpu_buffer, VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, 0, BUFFER_SIZE,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
|
||||
|
@ -219,7 +220,7 @@ void BoundingBox::Readback()
|
|||
StateTracker::GetInstance()->EndRenderPass();
|
||||
|
||||
// Ensure all writes are completed to the GPU buffer prior to the transfer.
|
||||
Util::BufferMemoryBarrier(
|
||||
StagingBuffer::BufferMemoryBarrier(
|
||||
g_command_buffer_mgr->GetCurrentCommandBuffer(), m_gpu_buffer,
|
||||
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, 0,
|
||||
BUFFER_SIZE, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
|
@ -233,15 +234,15 @@ void BoundingBox::Readback()
|
|||
m_readback_buffer->GetBuffer(), 1, ®ion);
|
||||
|
||||
// Restore GPU buffer access.
|
||||
Util::BufferMemoryBarrier(g_command_buffer_mgr->GetCurrentCommandBuffer(), m_gpu_buffer,
|
||||
VK_ACCESS_TRANSFER_READ_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, 0, BUFFER_SIZE,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
|
||||
StagingBuffer::BufferMemoryBarrier(
|
||||
g_command_buffer_mgr->GetCurrentCommandBuffer(), m_gpu_buffer, VK_ACCESS_TRANSFER_READ_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, 0, BUFFER_SIZE,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
|
||||
m_readback_buffer->FlushGPUCache(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
|
||||
// Wait until these commands complete.
|
||||
Util::ExecuteCurrentCommandsAndRestoreState(false, true);
|
||||
Renderer::GetInstance()->ExecuteCommandBuffer(false, true);
|
||||
|
||||
// Cache is now valid.
|
||||
m_readback_buffer->InvalidateCPUCache();
|
||||
|
|
|
@ -24,9 +24,6 @@ public:
|
|||
|
||||
bool Initialize();
|
||||
|
||||
VkBuffer GetGPUBuffer() const { return m_gpu_buffer; }
|
||||
VkDeviceSize GetGPUBufferOffset() const { return 0; }
|
||||
VkDeviceSize GetGPUBufferSize() const { return BUFFER_SIZE; }
|
||||
s32 Get(size_t index);
|
||||
void Set(size_t index, s32 value);
|
||||
|
||||
|
|
|
@ -1,21 +1,14 @@
|
|||
add_library(videovulkan
|
||||
BoundingBox.cpp
|
||||
CommandBufferManager.cpp
|
||||
FramebufferManager.cpp
|
||||
ObjectCache.cpp
|
||||
PerfQuery.cpp
|
||||
PostProcessing.cpp
|
||||
Renderer.cpp
|
||||
ShaderCache.cpp
|
||||
ShaderCompiler.cpp
|
||||
StateTracker.cpp
|
||||
StagingBuffer.cpp
|
||||
StreamBuffer.cpp
|
||||
SwapChain.cpp
|
||||
Texture2D.cpp
|
||||
TextureCache.cpp
|
||||
TextureConverter.cpp
|
||||
Util.cpp
|
||||
VertexFormat.cpp
|
||||
VertexManager.cpp
|
||||
VKPipeline.cpp
|
||||
|
|
|
@ -44,12 +44,16 @@ bool CommandBufferManager::Initialize()
|
|||
|
||||
bool CommandBufferManager::CreateCommandBuffers()
|
||||
{
|
||||
static constexpr VkSemaphoreCreateInfo semaphore_create_info = {
|
||||
VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0};
|
||||
|
||||
VkDevice device = g_vulkan_context->GetDevice();
|
||||
VkResult res;
|
||||
|
||||
for (FrameResources& resources : m_frame_resources)
|
||||
{
|
||||
resources.init_command_buffer_used = false;
|
||||
resources.semaphore_used = false;
|
||||
resources.needs_fence_wait = false;
|
||||
|
||||
VkCommandPoolCreateInfo pool_info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr, 0,
|
||||
|
@ -83,6 +87,13 @@ bool CommandBufferManager::CreateCommandBuffers()
|
|||
return false;
|
||||
}
|
||||
|
||||
res = vkCreateSemaphore(device, &semaphore_create_info, nullptr, &resources.semaphore);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: A better way to choose the number of descriptors.
|
||||
VkDescriptorPoolSize pool_sizes[] = {{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 500000},
|
||||
{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 500000},
|
||||
|
@ -105,9 +116,16 @@ bool CommandBufferManager::CreateCommandBuffers()
|
|||
}
|
||||
}
|
||||
|
||||
res = vkCreateSemaphore(device, &semaphore_create_info, nullptr, &m_present_semaphore);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Activate the first command buffer. ActivateCommandBuffer moves forward, so start with the last
|
||||
m_current_frame = m_frame_resources.size() - 1;
|
||||
ActivateCommandBuffer();
|
||||
m_current_frame = static_cast<u32>(m_frame_resources.size()) - 1;
|
||||
BeginCommandBuffer();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -122,28 +140,23 @@ void CommandBufferManager::DestroyCommandBuffers()
|
|||
// We destroy the command pool first, to avoid any warnings from the validation layers about
|
||||
// objects which are pending destruction being in-use.
|
||||
if (resources.command_pool != VK_NULL_HANDLE)
|
||||
{
|
||||
vkDestroyCommandPool(device, resources.command_pool, nullptr);
|
||||
resources.command_pool = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
// Destroy any pending objects.
|
||||
for (auto& it : resources.cleanup_resources)
|
||||
it();
|
||||
resources.cleanup_resources.clear();
|
||||
|
||||
if (resources.semaphore != VK_NULL_HANDLE)
|
||||
vkDestroySemaphore(device, resources.semaphore, nullptr);
|
||||
|
||||
if (resources.fence != VK_NULL_HANDLE)
|
||||
{
|
||||
vkDestroyFence(device, resources.fence, nullptr);
|
||||
resources.fence = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
if (resources.descriptor_pool != VK_NULL_HANDLE)
|
||||
{
|
||||
vkDestroyDescriptorPool(device, resources.descriptor_pool, nullptr);
|
||||
resources.descriptor_pool = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
vkDestroySemaphore(device, m_present_semaphore, nullptr);
|
||||
}
|
||||
|
||||
VkDescriptorSet CommandBufferManager::AllocateDescriptorSet(VkDescriptorSetLayout set_layout)
|
||||
|
@ -183,22 +196,14 @@ bool CommandBufferManager::CreateSubmitThread()
|
|||
m_pending_submits.pop_front();
|
||||
}
|
||||
|
||||
SubmitCommandBuffer(submit.index, submit.wait_semaphore, submit.signal_semaphore,
|
||||
submit.present_swap_chain, submit.present_image_index);
|
||||
SubmitCommandBuffer(submit.command_buffer_index, submit.present_swap_chain,
|
||||
submit.present_image_index);
|
||||
});
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CommandBufferManager::PrepareToSubmitCommandBuffer()
|
||||
{
|
||||
// Grab the semaphore before submitting command buffer either on-thread or off-thread.
|
||||
// This prevents a race from occurring where a second command buffer is executed
|
||||
// before the worker thread has woken and executed the first one yet.
|
||||
m_submit_semaphore.Wait();
|
||||
}
|
||||
|
||||
void CommandBufferManager::WaitForWorkerThreadIdle()
|
||||
{
|
||||
// Drain the semaphore, then allow another request in the future.
|
||||
|
@ -215,8 +220,8 @@ void CommandBufferManager::WaitForGPUIdle()
|
|||
void CommandBufferManager::WaitForFence(VkFence fence)
|
||||
{
|
||||
// Find the command buffer that this fence corresponds to.
|
||||
size_t command_buffer_index = 0;
|
||||
for (; command_buffer_index < m_frame_resources.size(); command_buffer_index++)
|
||||
u32 command_buffer_index = 0;
|
||||
for (; command_buffer_index < static_cast<u32>(m_frame_resources.size()); command_buffer_index++)
|
||||
{
|
||||
if (m_frame_resources[command_buffer_index].fence == fence)
|
||||
break;
|
||||
|
@ -227,6 +232,9 @@ void CommandBufferManager::WaitForFence(VkFence fence)
|
|||
if (!m_frame_resources[command_buffer_index].needs_fence_wait)
|
||||
return;
|
||||
|
||||
// Ensure this command buffer has been submitted.
|
||||
WaitForWorkerThreadIdle();
|
||||
|
||||
// Wait for this command buffer to be completed.
|
||||
VkResult res =
|
||||
vkWaitForFences(g_vulkan_context->GetDevice(), 1,
|
||||
|
@ -240,19 +248,11 @@ void CommandBufferManager::WaitForFence(VkFence fence)
|
|||
}
|
||||
|
||||
void CommandBufferManager::SubmitCommandBuffer(bool submit_on_worker_thread,
|
||||
VkSemaphore wait_semaphore,
|
||||
VkSemaphore signal_semaphore,
|
||||
VkSwapchainKHR present_swap_chain,
|
||||
uint32_t present_image_index)
|
||||
{
|
||||
FrameResources& resources = m_frame_resources[m_current_frame];
|
||||
|
||||
// Fire fence tracking callbacks. This can't happen on the worker thread.
|
||||
// We invoke these before submitting so that any last-minute commands can be added.
|
||||
for (const auto& iter : m_fence_point_callbacks)
|
||||
iter.second.first(resources.command_buffers[1], resources.fence);
|
||||
|
||||
// End the current command buffer.
|
||||
FrameResources& resources = m_frame_resources[m_current_frame];
|
||||
for (VkCommandBuffer command_buffer : resources.command_buffers)
|
||||
{
|
||||
VkResult res = vkEndCommandBuffer(command_buffer);
|
||||
|
@ -266,14 +266,18 @@ void CommandBufferManager::SubmitCommandBuffer(bool submit_on_worker_thread,
|
|||
// This command buffer now has commands, so can't be re-used without waiting.
|
||||
resources.needs_fence_wait = true;
|
||||
|
||||
// Grab the semaphore before submitting command buffer either on-thread or off-thread.
|
||||
// This prevents a race from occurring where a second command buffer is executed
|
||||
// before the worker thread has woken and executed the first one yet.
|
||||
m_submit_semaphore.Wait();
|
||||
|
||||
// Submitting off-thread?
|
||||
if (m_use_threaded_submission && submit_on_worker_thread)
|
||||
{
|
||||
// Push to the pending submit queue.
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_pending_submit_lock);
|
||||
m_pending_submits.push_back({m_current_frame, wait_semaphore, signal_semaphore,
|
||||
present_swap_chain, present_image_index});
|
||||
m_pending_submits.push_back({present_swap_chain, present_image_index, m_current_frame});
|
||||
}
|
||||
|
||||
// Wake up the worker thread for a single iteration.
|
||||
|
@ -282,17 +286,18 @@ void CommandBufferManager::SubmitCommandBuffer(bool submit_on_worker_thread,
|
|||
else
|
||||
{
|
||||
// Pass through to normal submission path.
|
||||
SubmitCommandBuffer(m_current_frame, wait_semaphore, signal_semaphore, present_swap_chain,
|
||||
present_image_index);
|
||||
SubmitCommandBuffer(m_current_frame, present_swap_chain, present_image_index);
|
||||
}
|
||||
|
||||
// Switch to next cmdbuffer.
|
||||
BeginCommandBuffer();
|
||||
}
|
||||
|
||||
void CommandBufferManager::SubmitCommandBuffer(size_t index, VkSemaphore wait_semaphore,
|
||||
VkSemaphore signal_semaphore,
|
||||
void CommandBufferManager::SubmitCommandBuffer(u32 command_buffer_index,
|
||||
VkSwapchainKHR present_swap_chain,
|
||||
uint32_t present_image_index)
|
||||
u32 present_image_index)
|
||||
{
|
||||
FrameResources& resources = m_frame_resources[index];
|
||||
FrameResources& resources = m_frame_resources[command_buffer_index];
|
||||
|
||||
// This may be executed on the worker thread, so don't modify any state of the manager class.
|
||||
uint32_t wait_bits = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
|
@ -307,22 +312,22 @@ void CommandBufferManager::SubmitCommandBuffer(size_t index, VkSemaphore wait_se
|
|||
nullptr};
|
||||
|
||||
// If the init command buffer did not have any commands recorded, don't submit it.
|
||||
if (!m_frame_resources[index].init_command_buffer_used)
|
||||
if (!resources.init_command_buffer_used)
|
||||
{
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = &m_frame_resources[index].command_buffers[1];
|
||||
submit_info.pCommandBuffers = &resources.command_buffers[1];
|
||||
}
|
||||
|
||||
if (wait_semaphore != VK_NULL_HANDLE)
|
||||
if (resources.semaphore_used != VK_NULL_HANDLE)
|
||||
{
|
||||
submit_info.pWaitSemaphores = &wait_semaphore;
|
||||
submit_info.pWaitSemaphores = &resources.semaphore;
|
||||
submit_info.waitSemaphoreCount = 1;
|
||||
}
|
||||
|
||||
if (signal_semaphore != VK_NULL_HANDLE)
|
||||
if (present_swap_chain != VK_NULL_HANDLE)
|
||||
{
|
||||
submit_info.signalSemaphoreCount = 1;
|
||||
submit_info.pSignalSemaphores = &signal_semaphore;
|
||||
submit_info.pSignalSemaphores = &m_present_semaphore;
|
||||
}
|
||||
|
||||
VkResult res =
|
||||
|
@ -337,11 +342,10 @@ void CommandBufferManager::SubmitCommandBuffer(size_t index, VkSemaphore wait_se
|
|||
if (present_swap_chain != VK_NULL_HANDLE)
|
||||
{
|
||||
// Should have a signal semaphore.
|
||||
ASSERT(signal_semaphore != VK_NULL_HANDLE);
|
||||
VkPresentInfoKHR present_info = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
nullptr,
|
||||
1,
|
||||
&signal_semaphore,
|
||||
&m_present_semaphore,
|
||||
1,
|
||||
&present_swap_chain,
|
||||
&present_image_index,
|
||||
|
@ -361,15 +365,15 @@ void CommandBufferManager::SubmitCommandBuffer(size_t index, VkSemaphore wait_se
|
|||
m_submit_semaphore.Post();
|
||||
}
|
||||
|
||||
void CommandBufferManager::OnCommandBufferExecuted(size_t index)
|
||||
void CommandBufferManager::OnCommandBufferExecuted(u32 index)
|
||||
{
|
||||
FrameResources& resources = m_frame_resources[index];
|
||||
|
||||
// Fire fence tracking callbacks.
|
||||
for (auto iter = m_fence_point_callbacks.begin(); iter != m_fence_point_callbacks.end();)
|
||||
for (auto iter = m_fence_callbacks.begin(); iter != m_fence_callbacks.end();)
|
||||
{
|
||||
auto backup_iter = iter++;
|
||||
backup_iter->second.second(resources.fence);
|
||||
backup_iter->second(resources.fence);
|
||||
}
|
||||
|
||||
// Clean up all objects pending destruction on this command buffer
|
||||
|
@ -378,7 +382,7 @@ void CommandBufferManager::OnCommandBufferExecuted(size_t index)
|
|||
resources.cleanup_resources.clear();
|
||||
}
|
||||
|
||||
void CommandBufferManager::ActivateCommandBuffer()
|
||||
void CommandBufferManager::BeginCommandBuffer()
|
||||
{
|
||||
// Move to the next command buffer.
|
||||
m_current_frame = (m_current_frame + 1) % NUM_COMMAND_BUFFERS;
|
||||
|
@ -422,19 +426,7 @@ void CommandBufferManager::ActivateCommandBuffer()
|
|||
|
||||
// Reset upload command buffer state
|
||||
resources.init_command_buffer_used = false;
|
||||
}
|
||||
|
||||
void CommandBufferManager::ExecuteCommandBuffer(bool submit_off_thread, bool wait_for_completion)
|
||||
{
|
||||
VkFence pending_fence = GetCurrentCommandBufferFence();
|
||||
|
||||
// If we're waiting for completion, don't bother waking the worker thread.
|
||||
PrepareToSubmitCommandBuffer();
|
||||
SubmitCommandBuffer((submit_off_thread && wait_for_completion));
|
||||
ActivateCommandBuffer();
|
||||
|
||||
if (wait_for_completion)
|
||||
WaitForFence(pending_fence);
|
||||
resources.semaphore_used = false;
|
||||
}
|
||||
|
||||
void CommandBufferManager::DeferBufferDestruction(VkBuffer object)
|
||||
|
@ -479,20 +471,18 @@ void CommandBufferManager::DeferImageViewDestruction(VkImageView object)
|
|||
[object]() { vkDestroyImageView(g_vulkan_context->GetDevice(), object, nullptr); });
|
||||
}
|
||||
|
||||
void CommandBufferManager::AddFencePointCallback(
|
||||
const void* key, const CommandBufferQueuedCallback& queued_callback,
|
||||
const CommandBufferExecutedCallback& executed_callback)
|
||||
void CommandBufferManager::AddFenceSignaledCallback(const void* key, FenceSignaledCallback callback)
|
||||
{
|
||||
// Shouldn't be adding twice.
|
||||
ASSERT(m_fence_point_callbacks.find(key) == m_fence_point_callbacks.end());
|
||||
m_fence_point_callbacks.emplace(key, std::make_pair(queued_callback, executed_callback));
|
||||
ASSERT(m_fence_callbacks.find(key) == m_fence_callbacks.end());
|
||||
m_fence_callbacks.emplace(key, std::move(callback));
|
||||
}
|
||||
|
||||
void CommandBufferManager::RemoveFencePointCallback(const void* key)
|
||||
void CommandBufferManager::RemoveFenceSignaledCallback(const void* key)
|
||||
{
|
||||
auto iter = m_fence_point_callbacks.find(key);
|
||||
ASSERT(iter != m_fence_point_callbacks.end());
|
||||
m_fence_point_callbacks.erase(iter);
|
||||
auto iter = m_fence_callbacks.find(key);
|
||||
ASSERT(iter != m_fence_callbacks.end());
|
||||
m_fence_callbacks.erase(iter);
|
||||
}
|
||||
|
||||
std::unique_ptr<CommandBufferManager> g_command_buffer_mgr;
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "VideoCommon/VideoCommon.h"
|
||||
|
||||
#include "VideoBackends/Vulkan/Constants.h"
|
||||
#include "VideoBackends/Vulkan/Util.h"
|
||||
|
||||
namespace Vulkan
|
||||
{
|
||||
|
@ -55,8 +54,14 @@ public:
|
|||
// Gets the fence that will be signaled when the currently executing command buffer is
|
||||
// queued and executed. Do not wait for this fence before the buffer is executed.
|
||||
VkFence GetCurrentCommandBufferFence() const { return m_frame_resources[m_current_frame].fence; }
|
||||
// Ensure the worker thread has submitted the previous frame's command buffer.
|
||||
void PrepareToSubmitCommandBuffer();
|
||||
|
||||
// Returns the semaphore for the current command buffer, which can be used to ensure the
|
||||
// swap chain image is ready before the command buffer executes.
|
||||
VkSemaphore GetCurrentCommandBufferSemaphore()
|
||||
{
|
||||
m_frame_resources[m_current_frame].semaphore_used = true;
|
||||
return m_frame_resources[m_current_frame].semaphore;
|
||||
}
|
||||
|
||||
// Ensure that the worker thread has submitted any previous command buffers and is idle.
|
||||
void WaitForWorkerThreadIdle();
|
||||
|
@ -70,17 +75,12 @@ public:
|
|||
void WaitForFence(VkFence fence);
|
||||
|
||||
void SubmitCommandBuffer(bool submit_on_worker_thread,
|
||||
VkSemaphore wait_semaphore = VK_NULL_HANDLE,
|
||||
VkSemaphore signal_semaphore = VK_NULL_HANDLE,
|
||||
VkSwapchainKHR present_swap_chain = VK_NULL_HANDLE,
|
||||
uint32_t present_image_index = 0xFFFFFFFF);
|
||||
|
||||
void ActivateCommandBuffer();
|
||||
|
||||
void ExecuteCommandBuffer(bool submit_off_thread, bool wait_for_completion);
|
||||
|
||||
// Was the last present submitted to the queue a failure? If so, we must recreate our swapchain.
|
||||
bool CheckLastPresentFail() { return m_present_failed_flag.TestAndClear(); }
|
||||
|
||||
// Schedule a vulkan resource for destruction later on. This will occur when the command buffer
|
||||
// is next re-used, and the GPU has finished working with the specified resource.
|
||||
void DeferBufferDestruction(VkBuffer object);
|
||||
|
@ -93,13 +93,9 @@ public:
|
|||
// Instruct the manager to fire the specified callback when a fence is flagged to be signaled.
|
||||
// This happens when command buffers are executed, and can be tested if signaled, which means
|
||||
// that all commands up to the point when the callback was fired have completed.
|
||||
using CommandBufferQueuedCallback = std::function<void(VkCommandBuffer, VkFence)>;
|
||||
using CommandBufferExecutedCallback = std::function<void(VkFence)>;
|
||||
|
||||
void AddFencePointCallback(const void* key, const CommandBufferQueuedCallback& queued_callback,
|
||||
const CommandBufferExecutedCallback& executed_callback);
|
||||
|
||||
void RemoveFencePointCallback(const void* key);
|
||||
using FenceSignaledCallback = std::function<void(VkFence)>;
|
||||
void AddFenceSignaledCallback(const void* key, FenceSignaledCallback callback);
|
||||
void RemoveFenceSignaledCallback(const void* key);
|
||||
|
||||
private:
|
||||
bool CreateCommandBuffers();
|
||||
|
@ -107,30 +103,32 @@ private:
|
|||
|
||||
bool CreateSubmitThread();
|
||||
|
||||
void SubmitCommandBuffer(size_t index, VkSemaphore wait_semaphore, VkSemaphore signal_semaphore,
|
||||
VkSwapchainKHR present_swap_chain, uint32_t present_image_index);
|
||||
void SubmitCommandBuffer(u32 command_buffer_index, VkSwapchainKHR present_swap_chain,
|
||||
u32 present_image_index);
|
||||
void BeginCommandBuffer();
|
||||
|
||||
void OnCommandBufferExecuted(size_t index);
|
||||
void OnCommandBufferExecuted(u32 index);
|
||||
|
||||
struct FrameResources
|
||||
{
|
||||
// [0] - Init (upload) command buffer, [1] - draw command buffer
|
||||
VkCommandPool command_pool;
|
||||
std::array<VkCommandBuffer, 2> command_buffers;
|
||||
VkDescriptorPool descriptor_pool;
|
||||
VkFence fence;
|
||||
bool init_command_buffer_used;
|
||||
bool needs_fence_wait;
|
||||
VkCommandPool command_pool = VK_NULL_HANDLE;
|
||||
std::array<VkCommandBuffer, 2> command_buffers = {};
|
||||
VkDescriptorPool descriptor_pool = VK_NULL_HANDLE;
|
||||
VkFence fence = VK_NULL_HANDLE;
|
||||
VkSemaphore semaphore = VK_NULL_HANDLE;
|
||||
bool init_command_buffer_used = false;
|
||||
bool semaphore_used = false;
|
||||
bool needs_fence_wait = false;
|
||||
|
||||
std::vector<std::function<void()>> cleanup_resources;
|
||||
};
|
||||
|
||||
std::array<FrameResources, NUM_COMMAND_BUFFERS> m_frame_resources = {};
|
||||
size_t m_current_frame;
|
||||
std::array<FrameResources, NUM_COMMAND_BUFFERS> m_frame_resources;
|
||||
u32 m_current_frame;
|
||||
|
||||
// callbacks when a fence point is set
|
||||
std::map<const void*, std::pair<CommandBufferQueuedCallback, CommandBufferExecutedCallback>>
|
||||
m_fence_point_callbacks;
|
||||
std::map<const void*, FenceSignaledCallback> m_fence_callbacks;
|
||||
|
||||
// Threaded command buffer execution
|
||||
// Semaphore determines when a command buffer can be queued
|
||||
|
@ -139,12 +137,11 @@ private:
|
|||
std::unique_ptr<Common::BlockingLoop> m_submit_loop;
|
||||
struct PendingCommandBufferSubmit
|
||||
{
|
||||
size_t index;
|
||||
VkSemaphore wait_semaphore;
|
||||
VkSemaphore signal_semaphore;
|
||||
VkSwapchainKHR present_swap_chain;
|
||||
uint32_t present_image_index;
|
||||
u32 present_image_index;
|
||||
u32 command_buffer_index;
|
||||
};
|
||||
VkSemaphore m_present_semaphore = VK_NULL_HANDLE;
|
||||
std::deque<PendingCommandBufferSubmit> m_pending_submits;
|
||||
std::mutex m_pending_submit_lock;
|
||||
Common::Flag m_present_failed_flag;
|
||||
|
|
|
@ -26,39 +26,29 @@ enum STAGING_BUFFER_TYPE
|
|||
// Descriptor set layouts
|
||||
enum DESCRIPTOR_SET_LAYOUT
|
||||
{
|
||||
DESCRIPTOR_SET_LAYOUT_SINGLE_UNIFORM_BUFFER,
|
||||
DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS,
|
||||
DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS,
|
||||
DESCRIPTOR_SET_LAYOUT_SHADER_STORAGE_BUFFERS,
|
||||
DESCRIPTOR_SET_LAYOUT_TEXEL_BUFFERS,
|
||||
DESCRIPTOR_SET_LAYOUT_STANDARD_UNIFORM_BUFFERS,
|
||||
DESCRIPTOR_SET_LAYOUT_STANDARD_SAMPLERS,
|
||||
DESCRIPTOR_SET_LAYOUT_STANDARD_SHADER_STORAGE_BUFFERS,
|
||||
DESCRIPTOR_SET_LAYOUT_UTILITY_UNIFORM_BUFFER,
|
||||
DESCRIPTOR_SET_LAYOUT_UTILITY_SAMPLERS,
|
||||
DESCRIPTOR_SET_LAYOUT_COMPUTE,
|
||||
NUM_DESCRIPTOR_SET_LAYOUTS
|
||||
};
|
||||
|
||||
// Descriptor set bind points
|
||||
enum DESCRIPTOR_SET_BIND_POINT
|
||||
{
|
||||
DESCRIPTOR_SET_BIND_POINT_UNIFORM_BUFFERS,
|
||||
DESCRIPTOR_SET_BIND_POINT_PIXEL_SHADER_SAMPLERS,
|
||||
DESCRIPTOR_SET_BIND_POINT_STORAGE_OR_TEXEL_BUFFER,
|
||||
NUM_DESCRIPTOR_SET_BIND_POINTS
|
||||
};
|
||||
|
||||
// We use four pipeline layouts:
|
||||
// - Standard
|
||||
// - Per-stage UBO (VS/GS/PS, VS constants accessible from PS)
|
||||
// - 8 combined image samplers (accessible from PS)
|
||||
// - 1 SSBO accessible from PS if supported
|
||||
// - Push Constant
|
||||
// - Same as standard, plus 128 bytes of push constants, accessible from all stages.
|
||||
// - Texture Decoding
|
||||
// - Same as push constant, plus a single texel buffer accessible from PS.
|
||||
// - Per-stage UBO (VS/GS/PS, VS constants accessible from PS) [set=0, binding=0-2]
|
||||
// - 8 combined image samplers (accessible from PS) [set=1, binding=0-7]
|
||||
// - 1 SSBO accessible from PS if supported [set=2, binding=0]
|
||||
// - Utility
|
||||
// - 1 combined UBO, accessible from VS/GS/PS [set=0, binding=0]
|
||||
// - 8 combined image samplers (accessible from PS) [set=1, binding=0-7]
|
||||
// - 1 texel buffer (accessible from PS) [set=1, binding=8]
|
||||
// - Compute
|
||||
// - 1 uniform buffer [set=0, binding=0]
|
||||
// - 4 combined image samplers [set=0, binding=1-4]
|
||||
// - 1 texel buffer [set=0, binding=5]
|
||||
// - 1 storage image [set=0, binding=6]
|
||||
// - 128 bytes of push constants
|
||||
// - 2 combined image samplers [set=0, binding=1-2]
|
||||
// - 2 texel buffers [set=0, binding=3-4]
|
||||
// - 1 storage image [set=0, binding=5]
|
||||
//
|
||||
// All four pipeline layout share the first two descriptor sets (uniform buffers, PS samplers).
|
||||
// The third descriptor set (see bind points above) is used for storage or texel buffers.
|
||||
|
@ -66,8 +56,6 @@ enum DESCRIPTOR_SET_BIND_POINT
|
|||
enum PIPELINE_LAYOUT
|
||||
{
|
||||
PIPELINE_LAYOUT_STANDARD,
|
||||
PIPELINE_LAYOUT_PUSH_CONSTANT,
|
||||
PIPELINE_LAYOUT_TEXTURE_CONVERSION,
|
||||
PIPELINE_LAYOUT_UTILITY,
|
||||
PIPELINE_LAYOUT_COMPUTE,
|
||||
NUM_PIPELINE_LAYOUTS
|
||||
|
@ -83,53 +71,22 @@ enum UNIFORM_BUFFER_DESCRIPTOR_SET_BINDING
|
|||
};
|
||||
|
||||
// Maximum number of attributes per vertex (we don't have any more than this?)
|
||||
constexpr size_t MAX_VERTEX_ATTRIBUTES = 16;
|
||||
constexpr u32 MAX_VERTEX_ATTRIBUTES = 16;
|
||||
|
||||
// Number of pixel shader texture slots
|
||||
constexpr size_t NUM_PIXEL_SHADER_SAMPLERS = 8;
|
||||
constexpr u32 NUM_PIXEL_SHADER_SAMPLERS = 8;
|
||||
constexpr u32 NUM_COMPUTE_SHADER_SAMPLERS = 2;
|
||||
|
||||
// Total number of binding points in the pipeline layout
|
||||
constexpr size_t TOTAL_PIPELINE_BINDING_POINTS =
|
||||
NUM_UBO_DESCRIPTOR_SET_BINDINGS + NUM_PIXEL_SHADER_SAMPLERS + 1;
|
||||
|
||||
// Format of EFB textures
|
||||
constexpr VkFormat EFB_COLOR_TEXTURE_FORMAT = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
constexpr VkFormat EFB_DEPTH_TEXTURE_FORMAT = VK_FORMAT_D32_SFLOAT;
|
||||
constexpr VkFormat EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT = VK_FORMAT_R32_SFLOAT;
|
||||
|
||||
// Format of texturecache textures
|
||||
constexpr VkFormat TEXTURECACHE_TEXTURE_FORMAT = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
// Number of texel buffer binding points.
|
||||
constexpr u32 NUM_COMPUTE_TEXEL_BUFFERS = 2;
|
||||
|
||||
// Textures that don't fit into this buffer will be uploaded with a separate buffer (see below).
|
||||
constexpr size_t INITIAL_TEXTURE_UPLOAD_BUFFER_SIZE = 16 * 1024 * 1024;
|
||||
constexpr size_t MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE = 64 * 1024 * 1024;
|
||||
constexpr u32 TEXTURE_UPLOAD_BUFFER_SIZE = 32 * 1024 * 1024;
|
||||
|
||||
// Textures greater than 1024*1024 will be put in staging textures that are released after
|
||||
// execution instead. A 2048x2048 texture is 16MB, and we'd only fit four of these in our
|
||||
// streaming buffer and be blocking frequently. Games are unlikely to have textures this
|
||||
// large anyway, so it's only really an issue for HD texture packs, and memory is not
|
||||
// a limiting factor in these scenarios anyway.
|
||||
constexpr size_t STAGING_TEXTURE_UPLOAD_THRESHOLD = 1024 * 1024 * 8;
|
||||
|
||||
// Streaming uniform buffer size
|
||||
constexpr size_t INITIAL_UNIFORM_STREAM_BUFFER_SIZE = 16 * 1024 * 1024;
|
||||
constexpr size_t MAXIMUM_UNIFORM_STREAM_BUFFER_SIZE = 32 * 1024 * 1024;
|
||||
|
||||
// Texel buffer size for palette and texture decoding.
|
||||
constexpr size_t TEXTURE_CONVERSION_TEXEL_BUFFER_SIZE = 8 * 1024 * 1024;
|
||||
|
||||
// Push constant buffer size for utility shaders
|
||||
constexpr u32 PUSH_CONSTANT_BUFFER_SIZE = 128;
|
||||
|
||||
// Minimum number of draw calls per command buffer when attempting to preempt a readback operation.
|
||||
constexpr u32 MINIMUM_DRAW_CALLS_PER_COMMAND_BUFFER_FOR_READBACK = 10;
|
||||
|
||||
// Multisampling state info that we don't expose in VideoCommon.
|
||||
union MultisamplingState
|
||||
{
|
||||
BitField<0, 5, u32> samples; // 1-16
|
||||
BitField<5, 1, u32> per_sample_shading; // SSAA
|
||||
u32 hex;
|
||||
};
|
||||
|
||||
constexpr u32 STAGING_TEXTURE_UPLOAD_THRESHOLD = 1024 * 1024 * 4;
|
||||
} // namespace Vulkan
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,161 +0,0 @@
|
|||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoBackends/Vulkan/Constants.h"
|
||||
#include "VideoBackends/Vulkan/TextureCache.h"
|
||||
#include "VideoCommon/FramebufferManagerBase.h"
|
||||
#include "VideoCommon/RenderState.h"
|
||||
|
||||
class AbstractStagingTexture;
|
||||
|
||||
namespace Vulkan
|
||||
{
|
||||
class StateTracker;
|
||||
class StreamBuffer;
|
||||
class Texture2D;
|
||||
class VertexFormat;
|
||||
class VKTexture;
|
||||
class XFBSource;
|
||||
|
||||
class FramebufferManager : public FramebufferManagerBase
|
||||
{
|
||||
public:
|
||||
FramebufferManager();
|
||||
~FramebufferManager();
|
||||
|
||||
static FramebufferManager* GetInstance();
|
||||
|
||||
bool Initialize();
|
||||
|
||||
VkRenderPass GetEFBLoadRenderPass() const { return m_efb_load_render_pass; }
|
||||
VkRenderPass GetEFBClearRenderPass() const { return m_efb_clear_render_pass; }
|
||||
Texture2D* GetEFBColorTexture() const { return m_efb_color_texture.get(); }
|
||||
Texture2D* GetEFBDepthTexture() const { return m_efb_depth_texture.get(); }
|
||||
VkFramebuffer GetEFBFramebuffer() const { return m_efb_framebuffer; }
|
||||
u32 GetEFBWidth() const;
|
||||
u32 GetEFBHeight() const;
|
||||
u32 GetEFBLayers() const;
|
||||
VkSampleCountFlagBits GetEFBSamples() const;
|
||||
MultisamplingState GetEFBMultisamplingState() const;
|
||||
|
||||
void RecreateEFBFramebuffer();
|
||||
|
||||
// Recompile shaders, use when MSAA mode changes.
|
||||
void RecompileShaders();
|
||||
|
||||
// Reinterpret pixel format of EFB color texture.
|
||||
// Assumes no render pass is currently in progress.
|
||||
// Swaps EFB framebuffers, so re-bind afterwards.
|
||||
void ReinterpretPixelData(int convtype);
|
||||
|
||||
// This render pass can be used for other readback operations.
|
||||
VkRenderPass GetColorCopyForReadbackRenderPass() const { return m_copy_color_render_pass; }
|
||||
// Resolve color/depth textures to a non-msaa texture, and return it.
|
||||
Texture2D* ResolveEFBColorTexture(const VkRect2D& region);
|
||||
Texture2D* ResolveEFBDepthTexture(const VkRect2D& region);
|
||||
|
||||
// Returns the texture that the EFB color texture is resolved to when multisampling is enabled.
|
||||
// Ensure ResolveEFBColorTexture is called before this method.
|
||||
Texture2D* GetResolvedEFBColorTexture() const { return m_efb_resolve_color_texture.get(); }
|
||||
// Reads a framebuffer value back from the GPU. This may block if the cache is not current.
|
||||
u32 PeekEFBColor(u32 x, u32 y);
|
||||
float PeekEFBDepth(u32 x, u32 y);
|
||||
void InvalidatePeekCache();
|
||||
|
||||
// Writes a value to the framebuffer. This will never block, and writes will be batched.
|
||||
void PokeEFBColor(u32 x, u32 y, u32 color);
|
||||
void PokeEFBDepth(u32 x, u32 y, float depth);
|
||||
void FlushEFBPokes();
|
||||
|
||||
private:
|
||||
struct EFBPokeVertex
|
||||
{
|
||||
float position[4];
|
||||
u32 color;
|
||||
};
|
||||
|
||||
bool CreateEFBRenderPasses();
|
||||
bool CreateEFBFramebuffer();
|
||||
void DestroyEFBFramebuffer();
|
||||
|
||||
bool CompileConversionShaders();
|
||||
void DestroyConversionShaders();
|
||||
|
||||
bool CreateReadbackRenderPasses();
|
||||
bool CompileReadbackShaders();
|
||||
void DestroyReadbackShaders();
|
||||
bool CreateReadbackTextures();
|
||||
void DestroyReadbackTextures();
|
||||
bool CreateReadbackFramebuffer();
|
||||
void DestroyReadbackFramebuffer();
|
||||
|
||||
void CreatePokeVertexFormat();
|
||||
bool CreatePokeVertexBuffer();
|
||||
void DestroyPokeVertexBuffer();
|
||||
bool CompilePokeShaders();
|
||||
void DestroyPokeShaders();
|
||||
|
||||
bool PopulateColorReadbackTexture();
|
||||
bool PopulateDepthReadbackTexture();
|
||||
|
||||
void CreatePokeVertices(std::vector<EFBPokeVertex>* destination_list, u32 x, u32 y, float z,
|
||||
u32 color);
|
||||
|
||||
void DrawPokeVertices(const EFBPokeVertex* vertices, size_t vertex_count, bool write_color,
|
||||
bool write_depth);
|
||||
|
||||
VkRenderPass m_efb_load_render_pass = VK_NULL_HANDLE;
|
||||
VkRenderPass m_efb_clear_render_pass = VK_NULL_HANDLE;
|
||||
VkRenderPass m_depth_resolve_render_pass = VK_NULL_HANDLE;
|
||||
|
||||
std::unique_ptr<Texture2D> m_efb_color_texture;
|
||||
std::unique_ptr<Texture2D> m_efb_convert_color_texture;
|
||||
std::unique_ptr<Texture2D> m_efb_depth_texture;
|
||||
std::unique_ptr<Texture2D> m_efb_resolve_color_texture;
|
||||
std::unique_ptr<Texture2D> m_efb_resolve_depth_texture;
|
||||
VkFramebuffer m_efb_framebuffer = VK_NULL_HANDLE;
|
||||
VkFramebuffer m_efb_convert_framebuffer = VK_NULL_HANDLE;
|
||||
VkFramebuffer m_depth_resolve_framebuffer = VK_NULL_HANDLE;
|
||||
|
||||
// Format conversion shaders
|
||||
VkShaderModule m_ps_rgb8_to_rgba6 = VK_NULL_HANDLE;
|
||||
VkShaderModule m_ps_rgba6_to_rgb8 = VK_NULL_HANDLE;
|
||||
VkShaderModule m_ps_depth_resolve = VK_NULL_HANDLE;
|
||||
|
||||
// EFB readback texture
|
||||
std::unique_ptr<Texture2D> m_color_copy_texture;
|
||||
std::unique_ptr<Texture2D> m_depth_copy_texture;
|
||||
VkFramebuffer m_color_copy_framebuffer = VK_NULL_HANDLE;
|
||||
VkFramebuffer m_depth_copy_framebuffer = VK_NULL_HANDLE;
|
||||
|
||||
// CPU-side EFB readback texture
|
||||
std::unique_ptr<AbstractStagingTexture> m_color_readback_texture;
|
||||
std::unique_ptr<AbstractStagingTexture> m_depth_readback_texture;
|
||||
bool m_color_readback_texture_valid = false;
|
||||
bool m_depth_readback_texture_valid = false;
|
||||
|
||||
// EFB poke drawing setup
|
||||
std::unique_ptr<VertexFormat> m_poke_vertex_format;
|
||||
std::unique_ptr<StreamBuffer> m_poke_vertex_stream_buffer;
|
||||
std::vector<EFBPokeVertex> m_color_poke_vertices;
|
||||
std::vector<EFBPokeVertex> m_depth_poke_vertices;
|
||||
PrimitiveType m_poke_primitive = PrimitiveType::TriangleStrip;
|
||||
|
||||
VkRenderPass m_copy_color_render_pass = VK_NULL_HANDLE;
|
||||
VkRenderPass m_copy_depth_render_pass = VK_NULL_HANDLE;
|
||||
VkShaderModule m_copy_color_shader = VK_NULL_HANDLE;
|
||||
VkShaderModule m_copy_depth_shader = VK_NULL_HANDLE;
|
||||
|
||||
VkShaderModule m_poke_vertex_shader = VK_NULL_HANDLE;
|
||||
VkShaderModule m_poke_geometry_shader = VK_NULL_HANDLE;
|
||||
VkShaderModule m_poke_fragment_shader = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
|
@ -19,7 +19,7 @@
|
|||
#include "VideoBackends/Vulkan/CommandBufferManager.h"
|
||||
#include "VideoBackends/Vulkan/ShaderCompiler.h"
|
||||
#include "VideoBackends/Vulkan/StreamBuffer.h"
|
||||
#include "VideoBackends/Vulkan/Util.h"
|
||||
#include "VideoBackends/Vulkan/VKTexture.h"
|
||||
#include "VideoBackends/Vulkan/VertexFormat.h"
|
||||
#include "VideoBackends/Vulkan/VulkanContext.h"
|
||||
#include "VideoCommon/Statistics.h"
|
||||
|
@ -28,16 +28,16 @@ namespace Vulkan
|
|||
{
|
||||
std::unique_ptr<ObjectCache> g_object_cache;
|
||||
|
||||
ObjectCache::ObjectCache()
|
||||
{
|
||||
}
|
||||
ObjectCache::ObjectCache() = default;
|
||||
|
||||
ObjectCache::~ObjectCache()
|
||||
{
|
||||
DestroyPipelineCache();
|
||||
DestroySamplers();
|
||||
DestroyPipelineLayouts();
|
||||
DestroyDescriptorSetLayouts();
|
||||
DestroyRenderPassCache();
|
||||
m_dummy_texture.reset();
|
||||
}
|
||||
|
||||
bool ObjectCache::Initialize()
|
||||
|
@ -48,44 +48,37 @@ bool ObjectCache::Initialize()
|
|||
if (!CreatePipelineLayouts())
|
||||
return false;
|
||||
|
||||
if (!CreateUtilityShaderVertexFormat())
|
||||
return false;
|
||||
|
||||
if (!CreateStaticSamplers())
|
||||
return false;
|
||||
|
||||
m_texture_upload_buffer =
|
||||
StreamBuffer::Create(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, INITIAL_TEXTURE_UPLOAD_BUFFER_SIZE,
|
||||
MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE);
|
||||
StreamBuffer::Create(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, TEXTURE_UPLOAD_BUFFER_SIZE);
|
||||
if (!m_texture_upload_buffer)
|
||||
{
|
||||
PanicAlert("Failed to create texture upload buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_utility_shader_vertex_buffer =
|
||||
StreamBuffer::Create(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 1024 * 1024, 4 * 1024 * 1024);
|
||||
m_utility_shader_uniform_buffer =
|
||||
StreamBuffer::Create(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, 1024, 4 * 1024 * 1024);
|
||||
if (!m_utility_shader_vertex_buffer || !m_utility_shader_uniform_buffer)
|
||||
return false;
|
||||
|
||||
m_dummy_texture = Texture2D::Create(1, 1, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT,
|
||||
VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
|
||||
m_dummy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
VkClearColorValue clear_color = {};
|
||||
VkImageSubresourceRange clear_range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
vkCmdClearColorImage(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
|
||||
m_dummy_texture->GetImage(), m_dummy_texture->GetLayout(), &clear_color, 1,
|
||||
&clear_range);
|
||||
m_dummy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
if (g_ActiveConfig.bShaderCache)
|
||||
{
|
||||
if (!LoadPipelineCache())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!CreatePipelineCache())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ObjectCache::Shutdown()
|
||||
{
|
||||
if (g_ActiveConfig.bShaderCache && m_pipeline_cache != VK_NULL_HANDLE)
|
||||
SavePipelineCache();
|
||||
}
|
||||
|
||||
void ObjectCache::ClearSamplerCache()
|
||||
{
|
||||
for (const auto& it : m_sampler_cache)
|
||||
|
@ -115,13 +108,9 @@ void ObjectCache::DestroySamplers()
|
|||
|
||||
bool ObjectCache::CreateDescriptorSetLayouts()
|
||||
{
|
||||
static const VkDescriptorSetLayoutBinding single_ubo_set_bindings[] = {
|
||||
0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
|
||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT};
|
||||
|
||||
// The geometry shader buffer must be last in this binding set, as we don't include it
|
||||
// if geometry shaders are not supported by the device. See the decrement below.
|
||||
static const VkDescriptorSetLayoutBinding per_stage_ubo_set_bindings[] = {
|
||||
static const VkDescriptorSetLayoutBinding standard_ubo_bindings[] = {
|
||||
{UBO_DESCRIPTOR_SET_BINDING_PS, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||
{UBO_DESCRIPTOR_SET_BINDING_VS, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
|
||||
|
@ -129,45 +118,56 @@ bool ObjectCache::CreateDescriptorSetLayouts()
|
|||
{UBO_DESCRIPTOR_SET_BINDING_GS, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
|
||||
VK_SHADER_STAGE_GEOMETRY_BIT}};
|
||||
|
||||
static const VkDescriptorSetLayoutBinding sampler_set_bindings[] = {
|
||||
static const VkDescriptorSetLayoutBinding standard_sampler_bindings[] = {
|
||||
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, static_cast<u32>(NUM_PIXEL_SHADER_SAMPLERS),
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT}};
|
||||
|
||||
static const VkDescriptorSetLayoutBinding ssbo_set_bindings[] = {
|
||||
static const VkDescriptorSetLayoutBinding standard_ssbo_bindings[] = {
|
||||
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}};
|
||||
|
||||
static const VkDescriptorSetLayoutBinding texel_buffer_set_bindings[] = {
|
||||
{0, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||
static const VkDescriptorSetLayoutBinding utility_ubo_bindings[] = {
|
||||
0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
|
||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT};
|
||||
|
||||
// Utility samplers aren't dynamically indexed.
|
||||
static const VkDescriptorSetLayoutBinding utility_sampler_bindings[] = {
|
||||
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||
{1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||
{2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||
{3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||
{4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||
{5, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||
{6, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||
{7, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||
{8, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||
};
|
||||
|
||||
static const VkDescriptorSetLayoutBinding compute_set_bindings[] = {
|
||||
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_COMPUTE_BIT},
|
||||
{1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
|
||||
{2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
|
||||
{3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
|
||||
{4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
|
||||
{5, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
|
||||
{6, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
|
||||
{7, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT},
|
||||
{3, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
|
||||
{4, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
|
||||
{5, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT},
|
||||
};
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo create_infos[NUM_DESCRIPTOR_SET_LAYOUTS] = {
|
||||
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(ArraySize(single_ubo_set_bindings)), single_ubo_set_bindings},
|
||||
static_cast<u32>(ArraySize(standard_ubo_bindings)), standard_ubo_bindings},
|
||||
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(ArraySize(per_stage_ubo_set_bindings)), per_stage_ubo_set_bindings},
|
||||
static_cast<u32>(ArraySize(standard_sampler_bindings)), standard_sampler_bindings},
|
||||
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(ArraySize(sampler_set_bindings)), sampler_set_bindings},
|
||||
static_cast<u32>(ArraySize(standard_ssbo_bindings)), standard_ssbo_bindings},
|
||||
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(ArraySize(ssbo_set_bindings)), ssbo_set_bindings},
|
||||
static_cast<u32>(ArraySize(utility_ubo_bindings)), utility_ubo_bindings},
|
||||
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(ArraySize(texel_buffer_set_bindings)), texel_buffer_set_bindings},
|
||||
static_cast<u32>(ArraySize(utility_sampler_bindings)), utility_sampler_bindings},
|
||||
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(ArraySize(compute_set_bindings)), compute_set_bindings}};
|
||||
|
||||
// Don't set the GS bit if geometry shaders aren't available.
|
||||
if (!g_vulkan_context->SupportsGeometryShaders())
|
||||
create_infos[DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS].bindingCount--;
|
||||
if (!g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
create_infos[DESCRIPTOR_SET_LAYOUT_STANDARD_UNIFORM_BUFFERS].bindingCount--;
|
||||
|
||||
for (size_t i = 0; i < NUM_DESCRIPTOR_SET_LAYOUTS; i++)
|
||||
{
|
||||
|
@ -199,22 +199,15 @@ bool ObjectCache::CreatePipelineLayouts()
|
|||
// Descriptor sets for each pipeline layout.
|
||||
// In the standard set, the SSBO must be the last descriptor, as we do not include it
|
||||
// when fragment stores and atomics are not supported by the device.
|
||||
VkDescriptorSetLayout standard_sets[] = {
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_SHADER_STORAGE_BUFFERS]};
|
||||
VkDescriptorSetLayout texture_conversion_sets[] = {
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_TEXEL_BUFFERS]};
|
||||
VkDescriptorSetLayout utility_sets[] = {
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_SINGLE_UNIFORM_BUFFER],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS]};
|
||||
VkDescriptorSetLayout compute_sets[] = {m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_COMPUTE]};
|
||||
VkPushConstantRange push_constant_range = {
|
||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, PUSH_CONSTANT_BUFFER_SIZE};
|
||||
VkPushConstantRange compute_push_constant_range = {VK_SHADER_STAGE_COMPUTE_BIT, 0,
|
||||
PUSH_CONSTANT_BUFFER_SIZE};
|
||||
const VkDescriptorSetLayout standard_sets[] = {
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_STANDARD_UNIFORM_BUFFERS],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_STANDARD_SAMPLERS],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_STANDARD_SHADER_STORAGE_BUFFERS]};
|
||||
const VkDescriptorSetLayout utility_sets[] = {
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_UTILITY_UNIFORM_BUFFER],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_UTILITY_SAMPLERS]};
|
||||
const VkDescriptorSetLayout compute_sets[] = {
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_COMPUTE]};
|
||||
|
||||
// Info for each pipeline layout
|
||||
VkPipelineLayoutCreateInfo pipeline_layout_info[NUM_PIPELINE_LAYOUTS] = {
|
||||
|
@ -222,25 +215,16 @@ bool ObjectCache::CreatePipelineLayouts()
|
|||
{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(ArraySize(standard_sets)), standard_sets, 0, nullptr},
|
||||
|
||||
// Push Constant
|
||||
{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(ArraySize(standard_sets)), standard_sets, 1, &push_constant_range},
|
||||
|
||||
// Texture Conversion
|
||||
{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(ArraySize(texture_conversion_sets)), texture_conversion_sets, 1,
|
||||
&push_constant_range},
|
||||
|
||||
// Texture Conversion
|
||||
// Utility
|
||||
{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(ArraySize(utility_sets)), utility_sets, 0, nullptr},
|
||||
|
||||
// Compute
|
||||
{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(ArraySize(compute_sets)), compute_sets, 1, &compute_push_constant_range}};
|
||||
static_cast<u32>(ArraySize(compute_sets)), compute_sets, 0, nullptr}};
|
||||
|
||||
// If bounding box is unsupported, don't bother with the SSBO descriptor set.
|
||||
if (!g_vulkan_context->SupportsBoundingBox())
|
||||
if (!g_ActiveConfig.backend_info.bSupportsBBox)
|
||||
pipeline_layout_info[PIPELINE_LAYOUT_STANDARD].setLayoutCount--;
|
||||
|
||||
for (size_t i = 0; i < NUM_PIPELINE_LAYOUTS; i++)
|
||||
|
@ -265,30 +249,6 @@ void ObjectCache::DestroyPipelineLayouts()
|
|||
}
|
||||
}
|
||||
|
||||
bool ObjectCache::CreateUtilityShaderVertexFormat()
|
||||
{
|
||||
PortableVertexDeclaration vtx_decl = {};
|
||||
vtx_decl.position.enable = true;
|
||||
vtx_decl.position.type = VAR_FLOAT;
|
||||
vtx_decl.position.components = 4;
|
||||
vtx_decl.position.integer = false;
|
||||
vtx_decl.position.offset = offsetof(UtilityShaderVertex, Position);
|
||||
vtx_decl.texcoords[0].enable = true;
|
||||
vtx_decl.texcoords[0].type = VAR_FLOAT;
|
||||
vtx_decl.texcoords[0].components = 4;
|
||||
vtx_decl.texcoords[0].integer = false;
|
||||
vtx_decl.texcoords[0].offset = offsetof(UtilityShaderVertex, TexCoord);
|
||||
vtx_decl.colors[0].enable = true;
|
||||
vtx_decl.colors[0].type = VAR_UNSIGNED_BYTE;
|
||||
vtx_decl.colors[0].components = 4;
|
||||
vtx_decl.colors[0].integer = false;
|
||||
vtx_decl.colors[0].offset = offsetof(UtilityShaderVertex, Color);
|
||||
vtx_decl.stride = sizeof(UtilityShaderVertex);
|
||||
|
||||
m_utility_shader_vertex_format = std::make_unique<VertexFormat>(vtx_decl);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ObjectCache::CreateStaticSamplers()
|
||||
{
|
||||
VkSamplerCreateInfo create_info = {
|
||||
|
@ -472,4 +432,199 @@ void ObjectCache::DestroyRenderPassCache()
|
|||
vkDestroyRenderPass(g_vulkan_context->GetDevice(), it.second, nullptr);
|
||||
m_render_pass_cache.clear();
|
||||
}
|
||||
|
||||
class PipelineCacheReadCallback : public LinearDiskCacheReader<u32, u8>
|
||||
{
|
||||
public:
|
||||
PipelineCacheReadCallback(std::vector<u8>* data) : m_data(data) {}
|
||||
void Read(const u32& key, const u8* value, u32 value_size) override
|
||||
{
|
||||
m_data->resize(value_size);
|
||||
if (value_size > 0)
|
||||
memcpy(m_data->data(), value, value_size);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<u8>* m_data;
|
||||
};
|
||||
|
||||
class PipelineCacheReadIgnoreCallback : public LinearDiskCacheReader<u32, u8>
|
||||
{
|
||||
public:
|
||||
void Read(const u32& key, const u8* value, u32 value_size) override {}
|
||||
};
|
||||
|
||||
bool ObjectCache::CreatePipelineCache()
|
||||
{
|
||||
// Vulkan pipeline caches can be shared between games for shader compile time reduction.
|
||||
// This assumes that drivers don't create all pipelines in the cache on load time, only
|
||||
// when a lookup occurs that matches a pipeline (or pipeline data) in the cache.
|
||||
m_pipeline_cache_filename = GetDiskShaderCacheFileName(APIType::Vulkan, "Pipeline", false, true);
|
||||
|
||||
VkPipelineCacheCreateInfo info = {
|
||||
VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType
|
||||
nullptr, // const void* pNext
|
||||
0, // VkPipelineCacheCreateFlags flags
|
||||
0, // size_t initialDataSize
|
||||
nullptr // const void* pInitialData
|
||||
};
|
||||
|
||||
VkResult res =
|
||||
vkCreatePipelineCache(g_vulkan_context->GetDevice(), &info, nullptr, &m_pipeline_cache);
|
||||
if (res == VK_SUCCESS)
|
||||
return true;
|
||||
|
||||
LOG_VULKAN_ERROR(res, "vkCreatePipelineCache failed: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ObjectCache::LoadPipelineCache()
|
||||
{
|
||||
// We have to keep the pipeline cache file name around since when we save it
|
||||
// we delete the old one, by which time the game's unique ID is already cleared.
|
||||
m_pipeline_cache_filename = GetDiskShaderCacheFileName(APIType::Vulkan, "Pipeline", false, true);
|
||||
|
||||
std::vector<u8> disk_data;
|
||||
LinearDiskCache<u32, u8> disk_cache;
|
||||
PipelineCacheReadCallback read_callback(&disk_data);
|
||||
if (disk_cache.OpenAndRead(m_pipeline_cache_filename, read_callback) != 1)
|
||||
disk_data.clear();
|
||||
|
||||
if (!disk_data.empty() && !ValidatePipelineCache(disk_data.data(), disk_data.size()))
|
||||
{
|
||||
// Don't use this data. In fact, we should delete it to prevent it from being used next time.
|
||||
File::Delete(m_pipeline_cache_filename);
|
||||
return CreatePipelineCache();
|
||||
}
|
||||
|
||||
VkPipelineCacheCreateInfo info = {
|
||||
VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType
|
||||
nullptr, // const void* pNext
|
||||
0, // VkPipelineCacheCreateFlags flags
|
||||
disk_data.size(), // size_t initialDataSize
|
||||
disk_data.data() // const void* pInitialData
|
||||
};
|
||||
|
||||
VkResult res =
|
||||
vkCreatePipelineCache(g_vulkan_context->GetDevice(), &info, nullptr, &m_pipeline_cache);
|
||||
if (res == VK_SUCCESS)
|
||||
return true;
|
||||
|
||||
// Failed to create pipeline cache, try with it empty.
|
||||
LOG_VULKAN_ERROR(res, "vkCreatePipelineCache failed, trying empty cache: ");
|
||||
return CreatePipelineCache();
|
||||
}
|
||||
|
||||
// Based on Vulkan 1.0 specification,
|
||||
// Table 9.1. Layout for pipeline cache header version VK_PIPELINE_CACHE_HEADER_VERSION_ONE
|
||||
// NOTE: This data is assumed to be in little-endian format.
|
||||
#pragma pack(push, 4)
|
||||
struct VK_PIPELINE_CACHE_HEADER
|
||||
{
|
||||
u32 header_length;
|
||||
u32 header_version;
|
||||
u32 vendor_id;
|
||||
u32 device_id;
|
||||
u8 uuid[VK_UUID_SIZE];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
static_assert(std::is_trivially_copyable<VK_PIPELINE_CACHE_HEADER>::value,
|
||||
"VK_PIPELINE_CACHE_HEADER must be trivially copyable");
|
||||
|
||||
bool ObjectCache::ValidatePipelineCache(const u8* data, size_t data_length)
|
||||
{
|
||||
if (data_length < sizeof(VK_PIPELINE_CACHE_HEADER))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Pipeline cache failed validation: Invalid header");
|
||||
return false;
|
||||
}
|
||||
|
||||
VK_PIPELINE_CACHE_HEADER header;
|
||||
std::memcpy(&header, data, sizeof(header));
|
||||
if (header.header_length < sizeof(VK_PIPELINE_CACHE_HEADER))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Pipeline cache failed validation: Invalid header length");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header.header_version != VK_PIPELINE_CACHE_HEADER_VERSION_ONE)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Pipeline cache failed validation: Invalid header version");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header.vendor_id != g_vulkan_context->GetDeviceProperties().vendorID)
|
||||
{
|
||||
ERROR_LOG(VIDEO,
|
||||
"Pipeline cache failed validation: Incorrect vendor ID (file: 0x%X, device: 0x%X)",
|
||||
header.vendor_id, g_vulkan_context->GetDeviceProperties().vendorID);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header.device_id != g_vulkan_context->GetDeviceProperties().deviceID)
|
||||
{
|
||||
ERROR_LOG(VIDEO,
|
||||
"Pipeline cache failed validation: Incorrect device ID (file: 0x%X, device: 0x%X)",
|
||||
header.device_id, g_vulkan_context->GetDeviceProperties().deviceID);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (std::memcmp(header.uuid, g_vulkan_context->GetDeviceProperties().pipelineCacheUUID,
|
||||
VK_UUID_SIZE) != 0)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Pipeline cache failed validation: Incorrect UUID");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ObjectCache::DestroyPipelineCache()
|
||||
{
|
||||
vkDestroyPipelineCache(g_vulkan_context->GetDevice(), m_pipeline_cache, nullptr);
|
||||
m_pipeline_cache = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void ObjectCache::SavePipelineCache()
|
||||
{
|
||||
size_t data_size;
|
||||
VkResult res =
|
||||
vkGetPipelineCacheData(g_vulkan_context->GetDevice(), m_pipeline_cache, &data_size, nullptr);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkGetPipelineCacheData failed: ");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<u8> data(data_size);
|
||||
res = vkGetPipelineCacheData(g_vulkan_context->GetDevice(), m_pipeline_cache, &data_size,
|
||||
data.data());
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkGetPipelineCacheData failed: ");
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete the old cache and re-create.
|
||||
File::Delete(m_pipeline_cache_filename);
|
||||
|
||||
// We write a single key of 1, with the entire pipeline cache data.
|
||||
// Not ideal, but our disk cache class does not support just writing a single blob
|
||||
// of data without specifying a key.
|
||||
LinearDiskCache<u32, u8> disk_cache;
|
||||
PipelineCacheReadIgnoreCallback callback;
|
||||
disk_cache.OpenAndRead(m_pipeline_cache_filename, callback);
|
||||
disk_cache.Append(1, data.data(), static_cast<u32>(data.size()));
|
||||
disk_cache.Close();
|
||||
}
|
||||
|
||||
void ObjectCache::ReloadPipelineCache()
|
||||
{
|
||||
SavePipelineCache();
|
||||
|
||||
if (g_ActiveConfig.bShaderCache)
|
||||
LoadPipelineCache();
|
||||
else
|
||||
CreatePipelineCache();
|
||||
}
|
||||
} // namespace Vulkan
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "Common/LinearDiskCache.h"
|
||||
|
||||
#include "VideoBackends/Vulkan/Constants.h"
|
||||
#include "VideoBackends/Vulkan/Texture2D.h"
|
||||
|
||||
#include "VideoCommon/GeometryShaderGen.h"
|
||||
#include "VideoCommon/PixelShaderGen.h"
|
||||
|
@ -27,6 +26,7 @@ namespace Vulkan
|
|||
{
|
||||
class CommandBufferManager;
|
||||
class VertexFormat;
|
||||
class VKTexture;
|
||||
class StreamBuffer;
|
||||
|
||||
class ObjectCache
|
||||
|
@ -35,29 +35,23 @@ public:
|
|||
ObjectCache();
|
||||
~ObjectCache();
|
||||
|
||||
// Perform at startup, create descriptor layouts, compiles all static shaders.
|
||||
bool Initialize();
|
||||
void Shutdown();
|
||||
|
||||
// Descriptor set layout accessor. Used for allocating descriptor sets.
|
||||
VkDescriptorSetLayout GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT layout) const
|
||||
{
|
||||
return m_descriptor_set_layouts[layout];
|
||||
}
|
||||
|
||||
// Pipeline layout accessor. Used to fill in required field in PipelineInfo.
|
||||
VkPipelineLayout GetPipelineLayout(PIPELINE_LAYOUT layout) const
|
||||
{
|
||||
return m_pipeline_layouts[layout];
|
||||
}
|
||||
// Shared utility shader resources
|
||||
VertexFormat* GetUtilityShaderVertexFormat() const
|
||||
{
|
||||
return m_utility_shader_vertex_format.get();
|
||||
}
|
||||
StreamBuffer* GetUtilityShaderVertexBuffer() const
|
||||
{
|
||||
return m_utility_shader_vertex_buffer.get();
|
||||
}
|
||||
StreamBuffer* GetUtilityShaderUniformBuffer() const
|
||||
{
|
||||
return m_utility_shader_uniform_buffer.get();
|
||||
}
|
||||
|
||||
// Staging buffer for textures.
|
||||
StreamBuffer* GetTextureUploadBuffer() const { return m_texture_upload_buffer.get(); }
|
||||
|
||||
// Static samplers
|
||||
|
@ -65,36 +59,39 @@ public:
|
|||
VkSampler GetLinearSampler() const { return m_linear_sampler; }
|
||||
VkSampler GetSampler(const SamplerState& info);
|
||||
|
||||
// Dummy image for samplers that are unbound
|
||||
Texture2D* GetDummyImage() const { return m_dummy_texture.get(); }
|
||||
VkImageView GetDummyImageView() const { return m_dummy_texture->GetView(); }
|
||||
// Render pass cache.
|
||||
VkRenderPass GetRenderPass(VkFormat color_format, VkFormat depth_format, u32 multisamples,
|
||||
VkAttachmentLoadOp load_op);
|
||||
|
||||
// Perform at startup, create descriptor layouts, compiles all static shaders.
|
||||
bool Initialize();
|
||||
// Pipeline cache. Used when creating pipelines for drivers to store compiled programs.
|
||||
VkPipelineCache GetPipelineCache() const { return m_pipeline_cache; }
|
||||
|
||||
// Clear sampler cache, use when anisotropy mode changes
|
||||
// WARNING: Ensure none of the objects from here are in use when calling
|
||||
void ClearSamplerCache();
|
||||
|
||||
// Saves the pipeline cache to disk. Call when shutting down.
|
||||
void SavePipelineCache();
|
||||
|
||||
// Reload pipeline cache. Call when host config changes.
|
||||
void ReloadPipelineCache();
|
||||
|
||||
private:
|
||||
bool CreateDescriptorSetLayouts();
|
||||
void DestroyDescriptorSetLayouts();
|
||||
bool CreatePipelineLayouts();
|
||||
void DestroyPipelineLayouts();
|
||||
bool CreateUtilityShaderVertexFormat();
|
||||
bool CreateStaticSamplers();
|
||||
void DestroySamplers();
|
||||
void DestroyRenderPassCache();
|
||||
bool CreatePipelineCache();
|
||||
bool LoadPipelineCache();
|
||||
bool ValidatePipelineCache(const u8* data, size_t data_length);
|
||||
void DestroyPipelineCache();
|
||||
|
||||
std::array<VkDescriptorSetLayout, NUM_DESCRIPTOR_SET_LAYOUTS> m_descriptor_set_layouts = {};
|
||||
std::array<VkPipelineLayout, NUM_PIPELINE_LAYOUTS> m_pipeline_layouts = {};
|
||||
|
||||
std::unique_ptr<VertexFormat> m_utility_shader_vertex_format;
|
||||
std::unique_ptr<StreamBuffer> m_utility_shader_vertex_buffer;
|
||||
std::unique_ptr<StreamBuffer> m_utility_shader_uniform_buffer;
|
||||
std::unique_ptr<StreamBuffer> m_texture_upload_buffer;
|
||||
|
||||
VkSampler m_point_sampler = VK_NULL_HANDLE;
|
||||
|
@ -103,11 +100,15 @@ private:
|
|||
std::map<SamplerState, VkSampler> m_sampler_cache;
|
||||
|
||||
// Dummy image for samplers that are unbound
|
||||
std::unique_ptr<Texture2D> m_dummy_texture;
|
||||
std::unique_ptr<VKTexture> m_dummy_texture;
|
||||
|
||||
// Render pass cache
|
||||
using RenderPassCacheKey = std::tuple<VkFormat, VkFormat, u32, VkAttachmentLoadOp>;
|
||||
std::map<RenderPassCacheKey, VkRenderPass> m_render_pass_cache;
|
||||
|
||||
// pipeline cache
|
||||
VkPipelineCache m_pipeline_cache = VK_NULL_HANDLE;
|
||||
std::string m_pipeline_cache_filename;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<ObjectCache> g_object_cache;
|
||||
|
|
|
@ -13,20 +13,18 @@
|
|||
#include "Common/MsgHandler.h"
|
||||
|
||||
#include "VideoBackends/Vulkan/CommandBufferManager.h"
|
||||
#include "VideoBackends/Vulkan/Renderer.h"
|
||||
#include "VideoBackends/Vulkan/StagingBuffer.h"
|
||||
#include "VideoBackends/Vulkan/StateTracker.h"
|
||||
#include "VideoBackends/Vulkan/Util.h"
|
||||
#include "VideoBackends/Vulkan/VulkanContext.h"
|
||||
|
||||
namespace Vulkan
|
||||
{
|
||||
PerfQuery::PerfQuery()
|
||||
{
|
||||
}
|
||||
PerfQuery::PerfQuery() = default;
|
||||
|
||||
PerfQuery::~PerfQuery()
|
||||
{
|
||||
g_command_buffer_mgr->RemoveFencePointCallback(this);
|
||||
g_command_buffer_mgr->RemoveFenceSignaledCallback(this);
|
||||
|
||||
if (m_query_pool != VK_NULL_HANDLE)
|
||||
vkDestroyQueryPool(g_vulkan_context->GetDevice(), m_query_pool, nullptr);
|
||||
|
@ -51,11 +49,8 @@ bool PerfQuery::Initialize()
|
|||
return false;
|
||||
}
|
||||
|
||||
g_command_buffer_mgr->AddFencePointCallback(
|
||||
this,
|
||||
std::bind(&PerfQuery::OnCommandBufferQueued, this, std::placeholders::_1,
|
||||
std::placeholders::_2),
|
||||
std::bind(&PerfQuery::OnCommandBufferExecuted, this, std::placeholders::_1));
|
||||
g_command_buffer_mgr->AddFenceSignaledCallback(
|
||||
this, std::bind(&PerfQuery::OnFenceSignaled, this, std::placeholders::_1));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -92,9 +87,6 @@ void PerfQuery::EnableQuery(PerfQueryGroup type)
|
|||
// TODO: Is this needed?
|
||||
StateTracker::GetInstance()->BeginRenderPass();
|
||||
vkCmdBeginQuery(g_command_buffer_mgr->GetCurrentCommandBuffer(), m_query_pool, index, flags);
|
||||
|
||||
// Prevent background command buffer submission while the query is active.
|
||||
StateTracker::GetInstance()->SetBackgroundCommandBufferExecution(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,8 +97,6 @@ void PerfQuery::DisableQuery(PerfQueryGroup type)
|
|||
// DisableQuery should be called for each EnableQuery, so subtract one to get the previous one.
|
||||
u32 index = (m_query_read_pos + m_query_count - 1) % PERF_QUERY_BUFFER_SIZE;
|
||||
vkCmdEndQuery(g_command_buffer_mgr->GetCurrentCommandBuffer(), m_query_pool, index);
|
||||
StateTracker::GetInstance()->SetBackgroundCommandBufferExecution(true);
|
||||
DEBUG_LOG(VIDEO, "end query %u", index);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,40 +188,42 @@ bool PerfQuery::CreateReadbackBuffer()
|
|||
return true;
|
||||
}
|
||||
|
||||
void PerfQuery::QueueCopyQueryResults(VkCommandBuffer command_buffer, VkFence fence,
|
||||
u32 start_index, u32 query_count)
|
||||
void PerfQuery::QueueCopyQueryResults(u32 start_index, u32 query_count)
|
||||
{
|
||||
DEBUG_LOG(VIDEO, "queue copy of queries %u-%u", start_index, start_index + query_count - 1);
|
||||
|
||||
// Transition buffer for GPU write
|
||||
// TODO: Is this needed?
|
||||
m_readback_buffer->PrepareForGPUWrite(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
m_readback_buffer->PrepareForGPUWrite(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
|
||||
// Copy from queries -> buffer
|
||||
vkCmdCopyQueryPoolResults(command_buffer, m_query_pool, start_index, query_count,
|
||||
m_readback_buffer->GetBuffer(), start_index * sizeof(PerfQueryDataType),
|
||||
sizeof(PerfQueryDataType), VK_QUERY_RESULT_WAIT_BIT);
|
||||
vkCmdCopyQueryPoolResults(g_command_buffer_mgr->GetCurrentCommandBuffer(), m_query_pool,
|
||||
start_index, query_count, m_readback_buffer->GetBuffer(),
|
||||
start_index * sizeof(PerfQueryDataType), sizeof(PerfQueryDataType),
|
||||
VK_QUERY_RESULT_WAIT_BIT);
|
||||
|
||||
// Prepare for host readback
|
||||
m_readback_buffer->FlushGPUCache(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
m_readback_buffer->FlushGPUCache(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
|
||||
// Reset queries so they're ready to use again
|
||||
vkCmdResetQueryPool(command_buffer, m_query_pool, start_index, query_count);
|
||||
vkCmdResetQueryPool(g_command_buffer_mgr->GetCurrentCommandBuffer(), m_query_pool, start_index,
|
||||
query_count);
|
||||
|
||||
// Flag all queries as available, but with a fence that has to be completed first
|
||||
for (u32 i = 0; i < query_count; i++)
|
||||
{
|
||||
u32 index = start_index + i;
|
||||
ActiveQuery& entry = m_query_buffer[index];
|
||||
entry.pending_fence = fence;
|
||||
entry.pending_fence = g_command_buffer_mgr->GetCurrentCommandBufferFence();
|
||||
entry.available = true;
|
||||
entry.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
void PerfQuery::OnCommandBufferQueued(VkCommandBuffer command_buffer, VkFence fence)
|
||||
void PerfQuery::FlushQueries()
|
||||
{
|
||||
// Flag all pending queries that aren't available as available after execution.
|
||||
u32 copy_start_index = 0;
|
||||
|
@ -254,7 +246,7 @@ void PerfQuery::OnCommandBufferQueued(VkCommandBuffer command_buffer, VkFence fe
|
|||
ASSERT(entry.active);
|
||||
if (index < copy_start_index)
|
||||
{
|
||||
QueueCopyQueryResults(command_buffer, fence, copy_start_index, copy_count);
|
||||
QueueCopyQueryResults(copy_start_index, copy_count);
|
||||
copy_start_index = index;
|
||||
copy_count = 0;
|
||||
}
|
||||
|
@ -266,10 +258,10 @@ void PerfQuery::OnCommandBufferQueued(VkCommandBuffer command_buffer, VkFence fe
|
|||
}
|
||||
|
||||
if (copy_count > 0)
|
||||
QueueCopyQueryResults(command_buffer, fence, copy_start_index, copy_count);
|
||||
QueueCopyQueryResults(copy_start_index, copy_count);
|
||||
}
|
||||
|
||||
void PerfQuery::OnCommandBufferExecuted(VkFence fence)
|
||||
void PerfQuery::OnFenceSignaled(VkFence fence)
|
||||
{
|
||||
// Need to save these since ProcessResults will modify them.
|
||||
u32 query_read_pos = m_query_read_pos;
|
||||
|
@ -350,7 +342,7 @@ void PerfQuery::NonBlockingPartialFlush()
|
|||
// Submit a command buffer in the background if the front query is not bound to one.
|
||||
// Ideally this will complete before the buffer fills.
|
||||
if (m_query_buffer[m_query_read_pos].pending_fence == VK_NULL_HANDLE)
|
||||
Util::ExecuteCurrentCommandsAndRestoreState(true, false);
|
||||
Renderer::GetInstance()->ExecuteCommandBuffer(true, false);
|
||||
}
|
||||
|
||||
void PerfQuery::BlockingPartialFlush()
|
||||
|
@ -364,7 +356,7 @@ void PerfQuery::BlockingPartialFlush()
|
|||
{
|
||||
// This will callback OnCommandBufferQueued which will set the fence on the entry.
|
||||
// We wait for completion, which will also call OnCommandBufferExecuted, and clear the fence.
|
||||
Util::ExecuteCurrentCommandsAndRestoreState(false, true);
|
||||
Renderer::GetInstance()->ExecuteCommandBuffer(false, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -373,4 +365,4 @@ void PerfQuery::BlockingPartialFlush()
|
|||
g_command_buffer_mgr->WaitForFence(entry.pending_fence);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Vulkan
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue