Move most backend functionality to VideoCommon

This commit is contained in:
Stenzek 2019-02-15 11:59:50 +10:00
parent 933f3ba008
commit f039149198
182 changed files with 8334 additions and 15917 deletions

View File

@ -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);

View File

@ -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};

View File

@ -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;

View File

@ -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,

View File

@ -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));

View File

@ -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)

View File

@ -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;
};

View File

@ -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

View File

@ -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
)

View File

@ -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>

View File

@ -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>

View File

@ -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);

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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");

View File

@ -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

View File

@ -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;
};
}

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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, &params, 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

View File

@ -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;
};
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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">

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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 =

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
};
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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();

View File

@ -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
}

View File

@ -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, &region);
// 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();

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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