mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Merge pull request #10673 from iwubcode/spirv-backends
D3D: Generate HLSL from SPIRV*
This commit is contained in:
@@ -18,3 +18,8 @@
|
||||
url = https://github.com/libusb/libusb.git
|
||||
branch = master
|
||||
shallow = true
|
||||
[submodule "Externals/spirv_cross/SPIRV-Cross"]
|
||||
path = Externals/spirv_cross/SPIRV-Cross
|
||||
url = https://github.com/KhronosGroup/SPIRV-Cross.git
|
||||
branch = master
|
||||
shallow = true
|
||||
|
||||
@@ -660,6 +660,7 @@ else()
|
||||
endif()
|
||||
add_subdirectory(Externals/imgui)
|
||||
add_subdirectory(Externals/glslang)
|
||||
add_subdirectory(Externals/spirv_cross)
|
||||
|
||||
if(ENABLE_VULKAN)
|
||||
add_definitions(-DHAS_VULKAN)
|
||||
|
||||
+3
@@ -82,6 +82,9 @@
|
||||
<ProjectReference Include="$(ExternalsDir)soundtouch\SoundTouch.vcxproj">
|
||||
<Project>{ec082900-b4d8-42e9-9663-77f02f6936ae}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(ExternalsDir)spirv_cross\spirv_cross.vcxproj">
|
||||
<Project>{3d780617-ec8c-4721-b9fd-dfc9bb658c7c}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(ExternalsDir)xxhash\xxhash.vcxproj">
|
||||
<Project>{677ea016-1182-440c-9345-dc88d1e98c0c}</Project>
|
||||
</ProjectReference>
|
||||
|
||||
Vendored
+52
@@ -0,0 +1,52 @@
|
||||
set(SRCS
|
||||
SPIRV-Cross/GLSL.std.450.h
|
||||
SPIRV-Cross/spirv.h
|
||||
SPIRV-Cross/spirv.hpp
|
||||
SPIRV-Cross/spirv_cfg.cpp
|
||||
SPIRV-Cross/spirv_cfg.hpp
|
||||
SPIRV-Cross/spirv_common.hpp
|
||||
SPIRV-Cross/spirv_cpp.cpp
|
||||
SPIRV-Cross/spirv_cpp.hpp
|
||||
SPIRV-Cross/spirv_cross.cpp
|
||||
SPIRV-Cross/spirv_cross.hpp
|
||||
SPIRV-Cross/spirv_cross_c.cpp
|
||||
SPIRV-Cross/spirv_cross_c.h
|
||||
SPIRV-Cross/spirv_cross_containers.hpp
|
||||
SPIRV-Cross/spirv_cross_error_handling.hpp
|
||||
SPIRV-Cross/spirv_cross_parsed_ir.cpp
|
||||
SPIRV-Cross/spirv_cross_parsed_ir.hpp
|
||||
SPIRV-Cross/spirv_cross_util.cpp
|
||||
SPIRV-Cross/spirv_cross_util.hpp
|
||||
SPIRV-Cross/spirv_glsl.cpp
|
||||
SPIRV-Cross/spirv_glsl.hpp
|
||||
SPIRV-Cross/spirv_hlsl.cpp
|
||||
SPIRV-Cross/spirv_hlsl.hpp
|
||||
SPIRV-Cross/spirv_msl.cpp
|
||||
SPIRV-Cross/spirv_msl.hpp
|
||||
SPIRV-Cross/spirv_parser.cpp
|
||||
SPIRV-Cross/spirv_parser.hpp
|
||||
SPIRV-Cross/spirv_reflect.cpp
|
||||
SPIRV-Cross/spirv_reflect.hpp
|
||||
)
|
||||
|
||||
if(NOT MSVC)
|
||||
# spirv_cross requires C++11 at a minimum to compile.
|
||||
add_compile_options(-std=c++11)
|
||||
|
||||
# Silence some warnings that occur frequently to reduce noise in build logs.
|
||||
add_compile_options(-Wno-shadow)
|
||||
add_compile_options(-Wno-reorder)
|
||||
add_compile_options(-Wno-sign-compare)
|
||||
add_compile_options(-Wno-parentheses)
|
||||
add_compile_options(-Wno-unused-variable)
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
add_compile_options(-Wno-unused-but-set-variable)
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
add_compile_options(-Wno-missing-variable-declarations)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(spirv_cross STATIC ${SRCS})
|
||||
|
||||
target_compile_definitions(spirv_cross PUBLIC SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS)
|
||||
target_include_directories(spirv_cross PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Cross/include ${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Cross)
|
||||
+1
Submodule Externals/spirv_cross/SPIRV-Cross added at 50b4d5389b
+53
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\Source\VSProps\Base.Macros.props" />
|
||||
<Import Project="$(VSPropsDir)Base.Targets.props" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{3d780617-ec8c-4721-b9fd-dfc9bb658c7c}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<Import Project="$(VSPropsDir)Configuration.StaticLibrary.props" />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="$(VSPropsDir)Base.props" />
|
||||
<Import Project="$(VSPropsDir)ClDisableAllWarnings.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemGroup>
|
||||
<ClCompile Include="SPIRV-Cross\spirv_cfg.cpp" />
|
||||
<ClCompile Include="SPIRV-Cross\spirv_cpp.cpp" />
|
||||
<ClCompile Include="SPIRV-Cross\spirv_cross.cpp" />
|
||||
<ClCompile Include="SPIRV-Cross\spirv_cross_c.cpp" />
|
||||
<ClCompile Include="SPIRV-Cross\spirv_cross_parsed_ir.cpp" />
|
||||
<ClCompile Include="SPIRV-Cross\spirv_cross_util.cpp" />
|
||||
<ClCompile Include="SPIRV-Cross\spirv_glsl.cpp" />
|
||||
<ClCompile Include="SPIRV-Cross\spirv_hlsl.cpp" />
|
||||
<ClCompile Include="SPIRV-Cross\spirv_msl.cpp" />
|
||||
<ClCompile Include="SPIRV-Cross\spirv_parser.cpp" />
|
||||
<ClCompile Include="SPIRV-Cross\spirv_reflect.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="SPIRV-Cross\GLSL.std.450.h" />
|
||||
<ClInclude Include="SPIRV-Cross\spirv.h" />
|
||||
<ClInclude Include="SPIRV-Cross\spirv.hpp" />
|
||||
<ClInclude Include="SPIRV-Cross\spirv_cfg.hpp" />
|
||||
<ClInclude Include="SPIRV-Cross\spirv_common.hpp" />
|
||||
<ClInclude Include="SPIRV-Cross\spirv_cpp.hpp" />
|
||||
<ClInclude Include="SPIRV-Cross\spirv_cross.hpp" />
|
||||
<ClInclude Include="SPIRV-Cross\spirv_cross_c.h" />
|
||||
<ClInclude Include="SPIRV-Cross\spirv_cross_containers.hpp" />
|
||||
<ClInclude Include="SPIRV-Cross\spirv_cross_error_handling.hpp" />
|
||||
<ClInclude Include="SPIRV-Cross\spirv_cross_parsed_ir.hpp" />
|
||||
<ClInclude Include="SPIRV-Cross\spirv_cross_util.hpp" />
|
||||
<ClInclude Include="SPIRV-Cross\spirv_glsl.hpp" />
|
||||
<ClInclude Include="SPIRV-Cross\spirv_hlsl.hpp" />
|
||||
<ClInclude Include="SPIRV-Cross\spirv_msl.hpp" />
|
||||
<ClInclude Include="SPIRV-Cross\spirv_parser.hpp" />
|
||||
<ClInclude Include="SPIRV-Cross\spirv_reflect.hpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -666,6 +666,7 @@
|
||||
<ClInclude Include="VideoCommon\RenderState.h" />
|
||||
<ClInclude Include="VideoCommon\ShaderCache.h" />
|
||||
<ClInclude Include="VideoCommon\ShaderGenCommon.h" />
|
||||
<ClInclude Include="VideoCommon\Spirv.h" />
|
||||
<ClInclude Include="VideoCommon\Statistics.h" />
|
||||
<ClInclude Include="VideoCommon\TextureCacheBase.h" />
|
||||
<ClInclude Include="VideoCommon\TextureConfig.h" />
|
||||
@@ -1253,6 +1254,7 @@
|
||||
<ClCompile Include="VideoCommon\RenderState.cpp" />
|
||||
<ClCompile Include="VideoCommon\ShaderCache.cpp" />
|
||||
<ClCompile Include="VideoCommon\ShaderGenCommon.cpp" />
|
||||
<ClCompile Include="VideoCommon\Spirv.cpp" />
|
||||
<ClCompile Include="VideoCommon\Statistics.cpp" />
|
||||
<ClCompile Include="VideoCommon\TextureCacheBase.cpp" />
|
||||
<ClCompile Include="VideoCommon\TextureConfig.cpp" />
|
||||
|
||||
@@ -27,7 +27,8 @@ bool D3DBoundingBox::Initialize()
|
||||
// Create 2 buffers here.
|
||||
// First for unordered access on default pool.
|
||||
auto desc = CD3D11_BUFFER_DESC(NUM_BBOX_VALUES * sizeof(BBoxType), D3D11_BIND_UNORDERED_ACCESS,
|
||||
D3D11_USAGE_DEFAULT, 0, 0, sizeof(BBoxType));
|
||||
D3D11_USAGE_DEFAULT, 0, D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS,
|
||||
sizeof(BBoxType));
|
||||
const BBoxType initial_values[NUM_BBOX_VALUES] = {0, 0, 0, 0};
|
||||
D3D11_SUBRESOURCE_DATA data;
|
||||
data.pSysMem = initial_values;
|
||||
@@ -44,6 +45,7 @@ bool D3DBoundingBox::Initialize()
|
||||
desc.Usage = D3D11_USAGE_STAGING;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
desc.BindFlags = 0;
|
||||
desc.MiscFlags = 0;
|
||||
hr = D3D::device->CreateBuffer(&desc, nullptr, &m_staging_buffer);
|
||||
ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create BoundingBox Staging Buffer: {}",
|
||||
DX11HRWrap(hr));
|
||||
@@ -53,10 +55,10 @@ bool D3DBoundingBox::Initialize()
|
||||
|
||||
// UAV is required to allow concurrent access.
|
||||
D3D11_UNORDERED_ACCESS_VIEW_DESC UAVdesc = {};
|
||||
UAVdesc.Format = DXGI_FORMAT_R32_SINT;
|
||||
UAVdesc.Format = DXGI_FORMAT_R32_TYPELESS;
|
||||
UAVdesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
|
||||
UAVdesc.Buffer.FirstElement = 0;
|
||||
UAVdesc.Buffer.Flags = 0;
|
||||
UAVdesc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
|
||||
UAVdesc.Buffer.NumElements = NUM_BBOX_VALUES;
|
||||
hr = D3D::device->CreateUnorderedAccessView(m_buffer.Get(), &UAVdesc, &m_uav);
|
||||
ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create BoundingBox UAV: {}", DX11HRWrap(hr));
|
||||
|
||||
@@ -106,7 +106,8 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
const AttributeFormat* format = &vtx_decl.position;
|
||||
if (format->enable)
|
||||
{
|
||||
m_elems[m_num_elems].SemanticName = "POSITION";
|
||||
m_elems[m_num_elems].SemanticName = "TEXCOORD";
|
||||
m_elems[m_num_elems].SemanticIndex = SHADER_POSITION_ATTRIB;
|
||||
m_elems[m_num_elems].AlignedByteOffset = format->offset;
|
||||
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
|
||||
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
@@ -115,12 +116,11 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
static constexpr std::array<const char*, 3> NAMES = {"NORMAL", "TANGENT", "BINORMAL"};
|
||||
format = &vtx_decl.normals[i];
|
||||
if (format->enable)
|
||||
{
|
||||
m_elems[m_num_elems].SemanticName = NAMES[i];
|
||||
m_elems[m_num_elems].SemanticIndex = 0;
|
||||
m_elems[m_num_elems].SemanticName = "TEXCOORD";
|
||||
m_elems[m_num_elems].SemanticIndex = SHADER_NORMAL_ATTRIB + i;
|
||||
m_elems[m_num_elems].AlignedByteOffset = format->offset;
|
||||
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
|
||||
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
@@ -133,8 +133,8 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
format = &vtx_decl.colors[i];
|
||||
if (format->enable)
|
||||
{
|
||||
m_elems[m_num_elems].SemanticName = "COLOR";
|
||||
m_elems[m_num_elems].SemanticIndex = i;
|
||||
m_elems[m_num_elems].SemanticName = "TEXCOORD";
|
||||
m_elems[m_num_elems].SemanticIndex = SHADER_COLOR0_ATTRIB + i;
|
||||
m_elems[m_num_elems].AlignedByteOffset = format->offset;
|
||||
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
|
||||
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
@@ -148,7 +148,7 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
if (format->enable)
|
||||
{
|
||||
m_elems[m_num_elems].SemanticName = "TEXCOORD";
|
||||
m_elems[m_num_elems].SemanticIndex = i;
|
||||
m_elems[m_num_elems].SemanticIndex = SHADER_TEXTURE0_ATTRIB + i;
|
||||
m_elems[m_num_elems].AlignedByteOffset = format->offset;
|
||||
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
|
||||
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
@@ -159,7 +159,8 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
format = &vtx_decl.posmtx;
|
||||
if (format->enable)
|
||||
{
|
||||
m_elems[m_num_elems].SemanticName = "BLENDINDICES";
|
||||
m_elems[m_num_elems].SemanticName = "TEXCOORD";
|
||||
m_elems[m_num_elems].SemanticIndex = SHADER_POSMTX_ATTRIB;
|
||||
m_elems[m_num_elems].AlignedByteOffset = format->offset;
|
||||
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
|
||||
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
|
||||
@@ -76,6 +76,7 @@ void StateManager::Apply()
|
||||
if (m_current.vertexConstants != m_pending.vertexConstants)
|
||||
{
|
||||
D3D::context->VSSetConstantBuffers(0, 1, &m_pending.vertexConstants);
|
||||
D3D::context->VSSetConstantBuffers(1, 1, &m_pending.vertexConstants);
|
||||
m_current.vertexConstants = m_pending.vertexConstants;
|
||||
}
|
||||
|
||||
|
||||
@@ -578,6 +578,8 @@ bool Renderer::ApplyState()
|
||||
{
|
||||
cmdlist->SetGraphicsRootConstantBufferView(ROOT_PARAMETER_VS_CBV,
|
||||
m_state.constant_buffers[1]);
|
||||
cmdlist->SetGraphicsRootConstantBufferView(ROOT_PARAMETER_VS_CBV2,
|
||||
m_state.constant_buffers[1]);
|
||||
|
||||
if (g_ActiveConfig.bEnablePixelLighting)
|
||||
{
|
||||
|
||||
@@ -323,7 +323,7 @@ bool DXContext::CreateRootSignatures()
|
||||
bool DXContext::CreateGXRootSignature()
|
||||
{
|
||||
// GX:
|
||||
// - 3 constant buffers (bindings 0-2), 0/1 visible in PS, 1 visible in VS, 2 visible in GS.
|
||||
// - 3 constant buffers (bindings 0-2), 0/1 visible in PS, 2 visible in VS, 1 visible in GS.
|
||||
// - 8 textures (visible in PS).
|
||||
// - 8 samplers (visible in PS).
|
||||
// - 1 UAV (visible in PS).
|
||||
@@ -341,6 +341,8 @@ bool DXContext::CreateGXRootSignature()
|
||||
param_count++;
|
||||
SetRootParamCBV(¶ms[param_count], 0, D3D12_SHADER_VISIBILITY_VERTEX);
|
||||
param_count++;
|
||||
SetRootParamCBV(¶ms[param_count], 1, D3D12_SHADER_VISIBILITY_VERTEX);
|
||||
param_count++;
|
||||
SetRootParamCBV(¶ms[param_count], 0, D3D12_SHADER_VISIBILITY_GEOMETRY);
|
||||
param_count++;
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ enum ROOT_PARAMETER
|
||||
ROOT_PARAMETER_PS_SRV,
|
||||
ROOT_PARAMETER_PS_SAMPLERS,
|
||||
ROOT_PARAMETER_VS_CBV,
|
||||
ROOT_PARAMETER_VS_CBV2,
|
||||
ROOT_PARAMETER_GS_CBV,
|
||||
ROOT_PARAMETER_PS_UAV_OR_CBV2,
|
||||
ROOT_PARAMETER_PS_CBV2, // ROOT_PARAMETER_PS_UAV_OR_CBV2 if bbox is not enabled
|
||||
|
||||
@@ -83,7 +83,7 @@ void DXVertexFormat::MapAttributes()
|
||||
if (m_decl.position.enable)
|
||||
{
|
||||
AddAttribute(
|
||||
"POSITION", 0, 0,
|
||||
"TEXCOORD", SHADER_POSITION_ATTRIB, 0,
|
||||
VarToDXGIFormat(m_decl.position.type, m_decl.position.components, m_decl.position.integer),
|
||||
m_decl.position.offset);
|
||||
}
|
||||
@@ -92,8 +92,7 @@ void DXVertexFormat::MapAttributes()
|
||||
{
|
||||
if (m_decl.normals[i].enable)
|
||||
{
|
||||
static constexpr std::array<const char*, 3> NAMES = {"NORMAL", "TANGENT", "BINORMAL"};
|
||||
AddAttribute(NAMES[i], 0, 0,
|
||||
AddAttribute("TEXCOORD", SHADER_NORMAL_ATTRIB + i, 0,
|
||||
VarToDXGIFormat(m_decl.normals[i].type, m_decl.normals[i].components,
|
||||
m_decl.normals[i].integer),
|
||||
m_decl.normals[i].offset);
|
||||
@@ -104,7 +103,7 @@ void DXVertexFormat::MapAttributes()
|
||||
{
|
||||
if (m_decl.colors[i].enable)
|
||||
{
|
||||
AddAttribute("COLOR", i, 0,
|
||||
AddAttribute("TEXCOORD", SHADER_COLOR0_ATTRIB + i, 0,
|
||||
VarToDXGIFormat(m_decl.colors[i].type, m_decl.colors[i].components,
|
||||
m_decl.colors[i].integer),
|
||||
m_decl.colors[i].offset);
|
||||
@@ -115,7 +114,7 @@ void DXVertexFormat::MapAttributes()
|
||||
{
|
||||
if (m_decl.texcoords[i].enable)
|
||||
{
|
||||
AddAttribute("TEXCOORD", i, 0,
|
||||
AddAttribute("TEXCOORD", SHADER_TEXTURE0_ATTRIB + i, 0,
|
||||
VarToDXGIFormat(m_decl.texcoords[i].type, m_decl.texcoords[i].components,
|
||||
m_decl.texcoords[i].integer),
|
||||
m_decl.texcoords[i].offset);
|
||||
@@ -125,7 +124,7 @@ void DXVertexFormat::MapAttributes()
|
||||
if (m_decl.posmtx.enable)
|
||||
{
|
||||
AddAttribute(
|
||||
"BLENDINDICES", 0, 0,
|
||||
"TEXCOORD", SHADER_POSMTX_ATTRIB, 0,
|
||||
VarToDXGIFormat(m_decl.posmtx.type, m_decl.posmtx.components, m_decl.posmtx.integer),
|
||||
m_decl.posmtx.offset);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ target_link_libraries(videod3dcommon
|
||||
PUBLIC
|
||||
common
|
||||
videocommon
|
||||
spirv_cross
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
|
||||
@@ -4,7 +4,13 @@
|
||||
#include "VideoBackends/D3DCommon/Shader.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <wrl/client.h>
|
||||
#include "disassemble.h"
|
||||
#include "spirv_hlsl.hpp"
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/FileUtil.h"
|
||||
@@ -14,9 +20,141 @@
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Common/Version.h"
|
||||
|
||||
#include "VideoCommon/Spirv.h"
|
||||
#include "VideoCommon/VideoBackendBase.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
// Regarding the UBO bind points, we subtract one from the binding index because
|
||||
// the OpenGL backend requires UBO #0 for non-block uniforms (at least on NV).
|
||||
// This allows us to share the same shaders but use bind point #0 in the D3D
|
||||
// backends. None of the specific shaders use UBOs, instead they use push
|
||||
// constants, so when/if the GL backend moves to uniform blocks completely this
|
||||
// subtraction can be removed.
|
||||
constexpr std::string_view SHADER_HEADER = R"(
|
||||
// Target GLSL 4.5.
|
||||
#version 450 core
|
||||
#define ATTRIBUTE_LOCATION(x) layout(location = x)
|
||||
#define FRAGMENT_OUTPUT_LOCATION(x) layout(location = x)
|
||||
#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y) layout(location = x, index = y)
|
||||
#define UBO_BINDING(packing, x) layout(packing, binding = (x - 1))
|
||||
#define SAMPLER_BINDING(x) layout(binding = x)
|
||||
#define TEXEL_BUFFER_BINDING(x) layout(binding = x)
|
||||
#define SSBO_BINDING(x) layout(binding = (x + 2))
|
||||
#define VARYING_LOCATION(x) layout(location = x)
|
||||
#define FORCE_EARLY_Z layout(early_fragment_tests) in
|
||||
|
||||
// hlsl to glsl function translation
|
||||
#define float2 vec2
|
||||
#define float3 vec3
|
||||
#define float4 vec4
|
||||
#define uint2 uvec2
|
||||
#define uint3 uvec3
|
||||
#define uint4 uvec4
|
||||
#define int2 ivec2
|
||||
#define int3 ivec3
|
||||
#define int4 ivec4
|
||||
#define frac fract
|
||||
#define lerp mix
|
||||
|
||||
#define API_D3D 1
|
||||
)";
|
||||
constexpr std::string_view COMPUTE_SHADER_HEADER = R"(
|
||||
// Target GLSL 4.5.
|
||||
#version 450 core
|
||||
// All resources are packed into one descriptor set for compute.
|
||||
#define UBO_BINDING(packing, x) layout(packing, binding = (x - 1))
|
||||
#define SAMPLER_BINDING(x) layout(binding = x)
|
||||
#define TEXEL_BUFFER_BINDING(x) layout(binding = x)
|
||||
#define IMAGE_BINDING(format, x) layout(format, binding = x)
|
||||
|
||||
// hlsl to glsl function translation
|
||||
#define float2 vec2
|
||||
#define float3 vec3
|
||||
#define float4 vec4
|
||||
#define uint2 uvec2
|
||||
#define uint3 uvec3
|
||||
#define uint4 uvec4
|
||||
#define int2 ivec2
|
||||
#define int3 ivec3
|
||||
#define int4 ivec4
|
||||
#define frac fract
|
||||
#define lerp mix
|
||||
|
||||
#define API_D3D 1
|
||||
)";
|
||||
|
||||
std::optional<std::string> GetHLSLFromSPIRV(SPIRV::CodeVector spv, D3D_FEATURE_LEVEL feature_level)
|
||||
{
|
||||
spirv_cross::CompilerHLSL::Options options;
|
||||
switch (feature_level)
|
||||
{
|
||||
case D3D_FEATURE_LEVEL_10_0:
|
||||
options.shader_model = 40;
|
||||
break;
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
options.shader_model = 41;
|
||||
break;
|
||||
default:
|
||||
options.shader_model = 50;
|
||||
break;
|
||||
};
|
||||
|
||||
spirv_cross::CompilerHLSL compiler(std::move(spv));
|
||||
compiler.set_hlsl_options(options);
|
||||
|
||||
return compiler.compile();
|
||||
}
|
||||
|
||||
std::optional<SPIRV::CodeVector> GetSpirv(ShaderStage stage, std::string_view source)
|
||||
{
|
||||
switch (stage)
|
||||
{
|
||||
case ShaderStage::Vertex:
|
||||
{
|
||||
const auto full_source = fmt::format("{}{}", SHADER_HEADER, source);
|
||||
return SPIRV::CompileVertexShader(full_source, APIType::D3D, glslang::EShTargetSpv_1_0);
|
||||
}
|
||||
|
||||
case ShaderStage::Geometry:
|
||||
{
|
||||
// Spirv cross does not currently support hlsl geometry shaders
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
case ShaderStage::Pixel:
|
||||
{
|
||||
const auto full_source = fmt::format("{}{}", SHADER_HEADER, source);
|
||||
return SPIRV::CompileFragmentShader(full_source, APIType::D3D, glslang::EShTargetSpv_1_0);
|
||||
}
|
||||
|
||||
case ShaderStage::Compute:
|
||||
{
|
||||
const auto full_source = fmt::format("{}{}", COMPUTE_SHADER_HEADER, source);
|
||||
return SPIRV::CompileComputeShader(full_source, APIType::D3D, glslang::EShTargetSpv_1_0);
|
||||
}
|
||||
};
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> GetHLSL(D3D_FEATURE_LEVEL feature_level, ShaderStage stage,
|
||||
std::string_view source)
|
||||
{
|
||||
if (stage == ShaderStage::Geometry)
|
||||
{
|
||||
return std::string{source};
|
||||
}
|
||||
else if (const auto spirv = GetSpirv(stage, source))
|
||||
{
|
||||
return GetHLSLFromSPIRV(std::move(*spirv), feature_level);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace D3DCommon
|
||||
{
|
||||
Shader::Shader(ShaderStage stage, BinaryData bytecode)
|
||||
@@ -95,6 +233,10 @@ static const char* GetCompileTarget(D3D_FEATURE_LEVEL feature_level, ShaderStage
|
||||
std::optional<Shader::BinaryData> Shader::CompileShader(D3D_FEATURE_LEVEL feature_level,
|
||||
ShaderStage stage, std::string_view source)
|
||||
{
|
||||
const auto hlsl = GetHLSL(feature_level, stage, source);
|
||||
if (!hlsl)
|
||||
return std::nullopt;
|
||||
|
||||
static constexpr D3D_SHADER_MACRO macros[] = {{"API_D3D", "1"}, {nullptr, nullptr}};
|
||||
const UINT flags = g_ActiveConfig.bEnableValidationLayer ?
|
||||
(D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION) :
|
||||
@@ -103,7 +245,7 @@ std::optional<Shader::BinaryData> Shader::CompileShader(D3D_FEATURE_LEVEL featur
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> code;
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> errors;
|
||||
HRESULT hr = d3d_compile(source.data(), source.size(), nullptr, macros, nullptr, "main", target,
|
||||
HRESULT hr = d3d_compile(hlsl->data(), hlsl->size(), nullptr, macros, nullptr, "main", target,
|
||||
flags, 0, &code, &errors);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
@@ -111,12 +253,20 @@ std::optional<Shader::BinaryData> Shader::CompileShader(D3D_FEATURE_LEVEL featur
|
||||
std::string filename = VideoBackendBase::BadShaderFilename(target, num_failures++);
|
||||
std::ofstream file;
|
||||
File::OpenFStream(file, filename, std::ios_base::out);
|
||||
file.write(source.data(), source.size());
|
||||
file.write(hlsl->data(), hlsl->size());
|
||||
file << "\n";
|
||||
file.write(static_cast<const char*>(errors->GetBufferPointer()), errors->GetBufferSize());
|
||||
file << "\n";
|
||||
file << "Dolphin Version: " + Common::GetScmRevStr() + "\n";
|
||||
file << "Video Backend: " + g_video_backend->GetDisplayName();
|
||||
|
||||
if (const auto spirv = GetSpirv(stage, source))
|
||||
{
|
||||
file << "\nOriginal Source: \n";
|
||||
file << source << std::endl;
|
||||
file << "SPIRV: \n";
|
||||
spv::Disassemble(file, *spirv);
|
||||
}
|
||||
file.close();
|
||||
|
||||
PanicAlertFmt("Failed to compile {}: {}\nDebug info ({}):\n{}", filename, Common::HRWrap(hr),
|
||||
|
||||
@@ -54,15 +54,6 @@ PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/Externals/Vulkan/Include
|
||||
)
|
||||
|
||||
# Silence warnings on glslang by flagging it as a system include
|
||||
target_include_directories(videovulkan
|
||||
SYSTEM PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/Externals/glslang/StandAlone
|
||||
${CMAKE_SOURCE_DIR}/Externals/glslang/glslang/Public
|
||||
${CMAKE_SOURCE_DIR}/Externals/glslang/SPIRV
|
||||
${CMAKE_SOURCE_DIR}/Externals/glslang
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
# Add precompiled header
|
||||
target_link_libraries(videovulkan PRIVATE use_pch)
|
||||
|
||||
@@ -4,36 +4,13 @@
|
||||
#include "VideoBackends/Vulkan/ShaderCompiler.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
// glslang includes
|
||||
#include "GlslangToSpv.h"
|
||||
#include "ResourceLimits.h"
|
||||
#include "ShaderLang.h"
|
||||
#include "disassemble.h"
|
||||
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Common/Version.h"
|
||||
|
||||
#include "VideoBackends/Vulkan/VulkanContext.h"
|
||||
#include "VideoCommon/VideoBackendBase.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
#include "VideoCommon/Spirv.h"
|
||||
|
||||
namespace Vulkan::ShaderCompiler
|
||||
{
|
||||
// Registers itself for cleanup via atexit
|
||||
bool InitializeGlslang();
|
||||
|
||||
// Resource limits used when compiling shaders
|
||||
static const TBuiltInResource* GetCompilerResourceLimits();
|
||||
|
||||
// Regarding the UBO bind points, we subtract one from the binding index because
|
||||
// the OpenGL backend requires UBO #0 for non-block uniforms (at least on NV).
|
||||
// This allows us to share the same shaders but use bind point #0 in the Vulkan
|
||||
@@ -111,25 +88,9 @@ static const char SUBGROUP_HELPER_HEADER[] = R"(
|
||||
#define SUBGROUP_MAX(value) value = subgroupMax(value)
|
||||
)";
|
||||
|
||||
static std::optional<SPIRVCodeVector> CompileShaderToSPV(EShLanguage stage,
|
||||
const char* stage_filename,
|
||||
std::string_view source,
|
||||
std::string_view header)
|
||||
static std::string GetShaderCode(std::string_view source, std::string_view header)
|
||||
{
|
||||
if (!InitializeGlslang())
|
||||
return std::nullopt;
|
||||
|
||||
std::unique_ptr<glslang::TShader> shader = std::make_unique<glslang::TShader>(stage);
|
||||
std::unique_ptr<glslang::TProgram> program;
|
||||
glslang::TShader::ForbidIncluder includer;
|
||||
EProfile profile = ECoreProfile;
|
||||
EShMessages messages =
|
||||
static_cast<EShMessages>(EShMsgDefault | EShMsgSpvRules | EShMsgVulkanRules);
|
||||
int default_version = 450;
|
||||
|
||||
std::string full_source_code;
|
||||
const char* pass_source_code = source.data();
|
||||
int pass_source_code_length = static_cast<int>(source.size());
|
||||
if (!header.empty())
|
||||
{
|
||||
constexpr size_t subgroup_helper_header_length = std::size(SUBGROUP_HELPER_HEADER) - 1;
|
||||
@@ -138,168 +99,41 @@ static std::optional<SPIRVCodeVector> CompileShaderToSPV(EShLanguage stage,
|
||||
if (g_vulkan_context->SupportsShaderSubgroupOperations())
|
||||
full_source_code.append(SUBGROUP_HELPER_HEADER, subgroup_helper_header_length);
|
||||
full_source_code.append(source);
|
||||
pass_source_code = full_source_code.c_str();
|
||||
pass_source_code_length = static_cast<int>(full_source_code.length());
|
||||
}
|
||||
|
||||
return full_source_code;
|
||||
}
|
||||
|
||||
static glslang::EShTargetLanguageVersion GetLanguageVersion()
|
||||
{
|
||||
// Sub-group operations require Vulkan 1.1 and SPIR-V 1.3.
|
||||
if (g_vulkan_context->SupportsShaderSubgroupOperations())
|
||||
shader->setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_3);
|
||||
return glslang::EShTargetSpv_1_3;
|
||||
|
||||
shader->setStringsWithLengths(&pass_source_code, &pass_source_code_length, 1);
|
||||
|
||||
auto DumpBadShader = [&](const char* msg) {
|
||||
static int counter = 0;
|
||||
std::string filename = VideoBackendBase::BadShaderFilename(stage_filename, counter++);
|
||||
std::ofstream stream;
|
||||
File::OpenFStream(stream, filename, std::ios_base::out);
|
||||
if (stream.good())
|
||||
{
|
||||
stream << full_source_code << std::endl;
|
||||
stream << msg << std::endl;
|
||||
stream << "Shader Info Log:" << std::endl;
|
||||
stream << shader->getInfoLog() << std::endl;
|
||||
stream << shader->getInfoDebugLog() << std::endl;
|
||||
if (program)
|
||||
{
|
||||
stream << "Program Info Log:" << std::endl;
|
||||
stream << program->getInfoLog() << std::endl;
|
||||
stream << program->getInfoDebugLog() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
stream << "\n";
|
||||
stream << "Dolphin Version: " + Common::GetScmRevStr() + "\n";
|
||||
stream << "Video Backend: " + g_video_backend->GetDisplayName();
|
||||
stream.close();
|
||||
|
||||
PanicAlertFmt("{} (written to {})\nDebug info:\n{}", msg, filename, shader->getInfoLog());
|
||||
};
|
||||
|
||||
if (!shader->parse(GetCompilerResourceLimits(), default_version, profile, false, true, messages,
|
||||
includer))
|
||||
{
|
||||
DumpBadShader("Failed to parse shader");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Even though there's only a single shader, we still need to link it to generate SPV
|
||||
program = std::make_unique<glslang::TProgram>();
|
||||
program->addShader(shader.get());
|
||||
if (!program->link(messages))
|
||||
{
|
||||
DumpBadShader("Failed to link program");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
glslang::TIntermediate* intermediate = program->getIntermediate(stage);
|
||||
if (!intermediate)
|
||||
{
|
||||
DumpBadShader("Failed to generate SPIR-V");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
SPIRVCodeVector out_code;
|
||||
spv::SpvBuildLogger logger;
|
||||
glslang::SpvOptions options;
|
||||
|
||||
if (g_ActiveConfig.bEnableValidationLayer)
|
||||
{
|
||||
// Attach the source code to the SPIR-V for tools like RenderDoc.
|
||||
intermediate->addSourceText(pass_source_code, pass_source_code_length);
|
||||
|
||||
options.generateDebugInfo = true;
|
||||
options.disableOptimizer = true;
|
||||
options.optimizeSize = false;
|
||||
options.disassemble = false;
|
||||
options.validate = true;
|
||||
}
|
||||
|
||||
glslang::GlslangToSpv(*intermediate, out_code, &logger, &options);
|
||||
|
||||
// Write out messages
|
||||
// Temporary: skip if it contains "Warning, version 450 is not yet complete; most version-specific
|
||||
// features are present, but some are missing."
|
||||
if (strlen(shader->getInfoLog()) > 108)
|
||||
WARN_LOG_FMT(VIDEO, "Shader info log: {}", shader->getInfoLog());
|
||||
if (strlen(shader->getInfoDebugLog()) > 0)
|
||||
WARN_LOG_FMT(VIDEO, "Shader debug info log: {}", shader->getInfoDebugLog());
|
||||
if (strlen(program->getInfoLog()) > 25)
|
||||
WARN_LOG_FMT(VIDEO, "Program info log: {}", program->getInfoLog());
|
||||
if (strlen(program->getInfoDebugLog()) > 0)
|
||||
WARN_LOG_FMT(VIDEO, "Program debug info log: {}", program->getInfoDebugLog());
|
||||
const std::string spv_messages = logger.getAllMessages();
|
||||
if (!spv_messages.empty())
|
||||
WARN_LOG_FMT(VIDEO, "SPIR-V conversion messages: {}", spv_messages);
|
||||
|
||||
// Dump source code of shaders out to file if enabled.
|
||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS)
|
||||
{
|
||||
static int counter = 0;
|
||||
std::string filename = StringFromFormat("%s%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(),
|
||||
stage_filename, counter++);
|
||||
|
||||
std::ofstream stream;
|
||||
File::OpenFStream(stream, filename, std::ios_base::out);
|
||||
if (stream.good())
|
||||
{
|
||||
stream << full_source_code << std::endl;
|
||||
stream << "Shader Info Log:" << std::endl;
|
||||
stream << shader->getInfoLog() << std::endl;
|
||||
stream << shader->getInfoDebugLog() << std::endl;
|
||||
stream << "Program Info Log:" << std::endl;
|
||||
stream << program->getInfoLog() << std::endl;
|
||||
stream << program->getInfoDebugLog() << std::endl;
|
||||
stream << "SPIR-V conversion messages: " << std::endl;
|
||||
stream << spv_messages;
|
||||
stream << "SPIR-V:" << std::endl;
|
||||
spv::Disassemble(stream, out_code);
|
||||
}
|
||||
}
|
||||
|
||||
return out_code;
|
||||
}
|
||||
|
||||
bool InitializeGlslang()
|
||||
{
|
||||
static bool glslang_initialized = false;
|
||||
if (glslang_initialized)
|
||||
return true;
|
||||
|
||||
if (!glslang::InitializeProcess())
|
||||
{
|
||||
PanicAlertFmt("Failed to initialize glslang shader compiler");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::atexit([]() { glslang::FinalizeProcess(); });
|
||||
|
||||
glslang_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
const TBuiltInResource* GetCompilerResourceLimits()
|
||||
{
|
||||
return &glslang::DefaultTBuiltInResource;
|
||||
return glslang::EShTargetSpv_1_0;
|
||||
}
|
||||
|
||||
std::optional<SPIRVCodeVector> CompileVertexShader(std::string_view source_code)
|
||||
{
|
||||
return CompileShaderToSPV(EShLangVertex, "vs", source_code, SHADER_HEADER);
|
||||
return SPIRV::CompileVertexShader(GetShaderCode(source_code, SHADER_HEADER), APIType::Vulkan,
|
||||
GetLanguageVersion());
|
||||
}
|
||||
|
||||
std::optional<SPIRVCodeVector> CompileGeometryShader(std::string_view source_code)
|
||||
{
|
||||
return CompileShaderToSPV(EShLangGeometry, "gs", source_code, SHADER_HEADER);
|
||||
return SPIRV::CompileGeometryShader(GetShaderCode(source_code, SHADER_HEADER), APIType::Vulkan,
|
||||
GetLanguageVersion());
|
||||
}
|
||||
|
||||
std::optional<SPIRVCodeVector> CompileFragmentShader(std::string_view source_code)
|
||||
{
|
||||
return CompileShaderToSPV(EShLangFragment, "ps", source_code, SHADER_HEADER);
|
||||
return SPIRV::CompileFragmentShader(GetShaderCode(source_code, SHADER_HEADER), APIType::Vulkan,
|
||||
GetLanguageVersion());
|
||||
}
|
||||
|
||||
std::optional<SPIRVCodeVector> CompileComputeShader(std::string_view source_code)
|
||||
{
|
||||
return CompileShaderToSPV(EShLangCompute, "cs", source_code, COMPUTE_SHADER_HEADER);
|
||||
return SPIRV::CompileComputeShader(GetShaderCode(source_code, SHADER_HEADER), APIType::Vulkan,
|
||||
GetLanguageVersion());
|
||||
}
|
||||
} // namespace Vulkan::ShaderCompiler
|
||||
|
||||
@@ -100,6 +100,8 @@ add_library(videocommon
|
||||
ShaderCache.h
|
||||
ShaderGenCommon.cpp
|
||||
ShaderGenCommon.h
|
||||
Spirv.cpp
|
||||
Spirv.h
|
||||
Statistics.cpp
|
||||
Statistics.h
|
||||
TextureCacheBase.cpp
|
||||
@@ -165,6 +167,7 @@ PRIVATE
|
||||
png
|
||||
xxhash
|
||||
imgui
|
||||
glslang
|
||||
)
|
||||
|
||||
if(_M_X86)
|
||||
@@ -207,6 +210,16 @@ if(FFmpeg_FOUND)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Silence warnings on glslang by flagging it as a system include
|
||||
target_include_directories(videocommon
|
||||
SYSTEM PUBLIC
|
||||
${CMAKE_SOURCE_DIR}/Externals/glslang/glslang/Public
|
||||
SYSTEM PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/Externals/glslang/StandAlone
|
||||
${CMAKE_SOURCE_DIR}/Externals/glslang/SPIRV
|
||||
${CMAKE_SOURCE_DIR}/Externals/glslang
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
# Add precompiled header
|
||||
target_link_libraries(videocommon PRIVATE use_pch)
|
||||
|
||||
@@ -25,10 +25,7 @@ APIType GetAPIType()
|
||||
|
||||
void EmitUniformBufferDeclaration(ShaderCode& code)
|
||||
{
|
||||
if (GetAPIType() == APIType::D3D)
|
||||
code.Write("cbuffer PSBlock : register(b0)\n");
|
||||
else
|
||||
code.Write("UBO_BINDING(std140, 1) uniform PSBlock\n");
|
||||
code.Write("UBO_BINDING(std140, 1) uniform PSBlock\n");
|
||||
}
|
||||
|
||||
void EmitSamplerDeclarations(ShaderCode& code, u32 start = 0, u32 end = 1,
|
||||
@@ -37,17 +34,6 @@ void EmitSamplerDeclarations(ShaderCode& code, u32 start = 0, u32 end = 1,
|
||||
switch (GetAPIType())
|
||||
{
|
||||
case APIType::D3D:
|
||||
{
|
||||
const char* array_type = multisampled ? "Texture2DMSArray<float4>" : "Texture2DArray<float4>";
|
||||
|
||||
for (u32 i = start; i < end; i++)
|
||||
{
|
||||
code.Write("{} tex{} : register(t{});\n", array_type, i, i);
|
||||
code.Write("SamplerState samp{} : register(s{});\n", i, i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case APIType::OpenGL:
|
||||
case APIType::Vulkan:
|
||||
{
|
||||
@@ -69,9 +55,6 @@ void EmitSampleTexture(ShaderCode& code, u32 n, std::string_view coords)
|
||||
switch (GetAPIType())
|
||||
{
|
||||
case APIType::D3D:
|
||||
code.Write("tex{}.Sample(samp{}, {})", n, n, coords);
|
||||
break;
|
||||
|
||||
case APIType::OpenGL:
|
||||
case APIType::Vulkan:
|
||||
code.Write("texture(samp{}, {})", n, coords);
|
||||
@@ -89,9 +72,6 @@ void EmitTextureLoad(ShaderCode& code, u32 n, std::string_view coords)
|
||||
switch (GetAPIType())
|
||||
{
|
||||
case APIType::D3D:
|
||||
code.Write("tex{}.Load({})", n, coords);
|
||||
break;
|
||||
|
||||
case APIType::OpenGL:
|
||||
case APIType::Vulkan:
|
||||
code.Write("texelFetch(samp{}, ({}).xyz, ({}).w)", n, coords, coords);
|
||||
@@ -109,23 +89,6 @@ void EmitVertexMainDeclaration(ShaderCode& code, u32 num_tex_inputs, u32 num_col
|
||||
switch (GetAPIType())
|
||||
{
|
||||
case APIType::D3D:
|
||||
{
|
||||
code.Write("void main(");
|
||||
for (u32 i = 0; i < num_tex_inputs; i++)
|
||||
code.Write("in float3 rawtex{} : TEXCOORD{}, ", i, i);
|
||||
for (u32 i = 0; i < num_color_inputs; i++)
|
||||
code.Write("in float4 rawcolor{} : COLOR{}, ", i, i);
|
||||
if (position_input)
|
||||
code.Write("in float4 rawpos : POSITION, ");
|
||||
code.Write("{}", extra_inputs);
|
||||
for (u32 i = 0; i < num_tex_outputs; i++)
|
||||
code.Write("out float3 v_tex{} : TEXCOORD{}, ", i, i);
|
||||
for (u32 i = 0; i < num_color_outputs; i++)
|
||||
code.Write("out float4 v_col{} : COLOR{}, ", i, i);
|
||||
code.Write("out float4 opos : SV_Position)\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case APIType::OpenGL:
|
||||
case APIType::Vulkan:
|
||||
{
|
||||
@@ -175,18 +138,6 @@ void EmitPixelMainDeclaration(ShaderCode& code, u32 num_tex_inputs, u32 num_colo
|
||||
switch (GetAPIType())
|
||||
{
|
||||
case APIType::D3D:
|
||||
{
|
||||
code.Write("void main(");
|
||||
for (u32 i = 0; i < num_tex_inputs; i++)
|
||||
code.Write("in float3 v_tex{} : TEXCOORD{}, ", i, i);
|
||||
for (u32 i = 0; i < num_color_inputs; i++)
|
||||
code.Write("in float4 v_col{} : COLOR{}, ", i, i);
|
||||
if (emit_frag_coord)
|
||||
code.Write("in float4 frag_coord : SV_Position, ");
|
||||
code.Write("{}out {} ocol0 : SV_Target)\n", extra_vars, output_type);
|
||||
}
|
||||
break;
|
||||
|
||||
case APIType::OpenGL:
|
||||
case APIType::Vulkan:
|
||||
{
|
||||
@@ -225,8 +176,8 @@ std::string GenerateScreenQuadVertexShader()
|
||||
{
|
||||
ShaderCode code;
|
||||
EmitVertexMainDeclaration(code, 0, 0, false, 1, 0,
|
||||
GetAPIType() == APIType::D3D ? "in uint id : SV_VertexID, " :
|
||||
"#define id gl_VertexID\n");
|
||||
|
||||
"#define id gl_VertexID\n");
|
||||
code.Write(
|
||||
"{{\n"
|
||||
" v_tex0 = float3(float((id << 1) & 2), float(id & 2), 0.0f);\n"
|
||||
@@ -251,7 +202,7 @@ std::string GeneratePassthroughGeometryShader(u32 num_tex, u32 num_colors)
|
||||
for (u32 i = 0; i < num_tex; i++)
|
||||
code.Write(" float3 tex{} : TEXCOORD{};\n", i, i);
|
||||
for (u32 i = 0; i < num_colors; i++)
|
||||
code.Write(" float4 color{} : COLOR{};\n", i, i);
|
||||
code.Write(" float4 color{} : TEXCOORD{};\n", i, i + num_tex);
|
||||
code.Write(" float4 position : SV_Position;\n"
|
||||
"}};\n");
|
||||
|
||||
@@ -260,7 +211,7 @@ std::string GeneratePassthroughGeometryShader(u32 num_tex, u32 num_colors)
|
||||
for (u32 i = 0; i < num_tex; i++)
|
||||
code.Write(" float3 tex{} : TEXCOORD{};\n", i, i);
|
||||
for (u32 i = 0; i < num_colors; i++)
|
||||
code.Write(" float4 color{} : COLOR{};\n", i, i);
|
||||
code.Write(" float4 color{} : TEXCOORD{};\n", i, i + num_tex);
|
||||
code.Write(" float4 position : SV_Position;\n"
|
||||
" uint slice : SV_RenderTargetArrayIndex;\n"
|
||||
"}};\n\n");
|
||||
@@ -343,8 +294,8 @@ std::string GenerateTextureCopyVertexShader()
|
||||
"}};\n\n");
|
||||
|
||||
EmitVertexMainDeclaration(code, 0, 0, false, 1, 0,
|
||||
GetAPIType() == APIType::D3D ? "in uint id : SV_VertexID, " :
|
||||
"#define id gl_VertexID");
|
||||
|
||||
"#define id gl_VertexID");
|
||||
code.Write("{{\n"
|
||||
" v_tex0 = float3(float((id << 1) & 2), float(id & 2), 0.0f);\n"
|
||||
" opos = float4(v_tex0.xy * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n"
|
||||
@@ -386,25 +337,15 @@ std::string GenerateResolveDepthPixelShader(u32 samples)
|
||||
{
|
||||
ShaderCode code;
|
||||
EmitSamplerDeclarations(code, 0, 1, true);
|
||||
EmitPixelMainDeclaration(code, 1, 0, "float",
|
||||
GetAPIType() == APIType::D3D ? "in float4 ipos : SV_Position, " : "");
|
||||
EmitPixelMainDeclaration(code, 1, 0, "float", "");
|
||||
code.Write("{{\n"
|
||||
" int layer = int(v_tex0.z);\n");
|
||||
if (GetAPIType() == APIType::D3D)
|
||||
code.Write(" int3 coords = int3(int2(ipos.xy), layer);\n");
|
||||
else
|
||||
code.Write(" int3 coords = int3(int2(gl_FragCoord.xy), layer);\n");
|
||||
code.Write(" int3 coords = int3(int2(gl_FragCoord.xy), layer);\n");
|
||||
|
||||
// Take the minimum of all depth samples.
|
||||
if (GetAPIType() == APIType::D3D)
|
||||
code.Write(" ocol0 = tex0.Load(coords, 0).r;\n");
|
||||
else
|
||||
code.Write(" ocol0 = texelFetch(samp0, coords, 0).r;\n");
|
||||
code.Write(" ocol0 = texelFetch(samp0, coords, 0).r;\n");
|
||||
code.Write(" for (int i = 1; i < {}; i++)\n", samples);
|
||||
if (GetAPIType() == APIType::D3D)
|
||||
code.Write(" ocol0 = min(ocol0, tex0.Load(coords, i).r);\n");
|
||||
else
|
||||
code.Write(" ocol0 = min(ocol0, texelFetch(samp0, coords, i).r);\n");
|
||||
code.Write(" ocol0 = min(ocol0, texelFetch(samp0, coords, i).r);\n");
|
||||
|
||||
code.Write("}}\n");
|
||||
return code.GetBuffer();
|
||||
@@ -420,8 +361,8 @@ std::string GenerateClearVertexShader()
|
||||
"}};\n");
|
||||
|
||||
EmitVertexMainDeclaration(code, 0, 0, false, 0, 1,
|
||||
GetAPIType() == APIType::D3D ? "in uint id : SV_VertexID, " :
|
||||
"#define id gl_VertexID\n");
|
||||
|
||||
"#define id gl_VertexID\n");
|
||||
code.Write(
|
||||
"{{\n"
|
||||
" float2 coord = float2(float((id << 1) & 2), float(id & 2));\n"
|
||||
@@ -459,45 +400,29 @@ std::string GenerateFormatConversionShader(EFBReinterpretType convtype, u32 samp
|
||||
{
|
||||
ShaderCode code;
|
||||
EmitSamplerDeclarations(code, 0, 1, samples > 1);
|
||||
EmitPixelMainDeclaration(
|
||||
code, 1, 0, "float4",
|
||||
GetAPIType() == APIType::D3D ?
|
||||
(g_ActiveConfig.bSSAA ?
|
||||
"in float4 ipos : SV_Position, in uint isample : SV_SampleIndex, " :
|
||||
"in float4 ipos : SV_Position, ") :
|
||||
"");
|
||||
EmitPixelMainDeclaration(code, 1, 0, "float4",
|
||||
|
||||
"");
|
||||
code.Write("{{\n"
|
||||
" int layer = int(v_tex0.z);\n");
|
||||
if (GetAPIType() == APIType::D3D)
|
||||
code.Write(" int3 coords = int3(int2(ipos.xy), layer);\n");
|
||||
else
|
||||
code.Write(" int3 coords = int3(int2(gl_FragCoord.xy), layer);\n");
|
||||
code.Write(" int3 coords = int3(int2(gl_FragCoord.xy), layer);\n");
|
||||
|
||||
if (samples == 1)
|
||||
{
|
||||
// No MSAA at all.
|
||||
if (GetAPIType() == APIType::D3D)
|
||||
code.Write(" float4 val = tex0.Load(int4(coords, 0));\n");
|
||||
else
|
||||
code.Write(" float4 val = texelFetch(samp0, coords, 0);\n");
|
||||
code.Write(" float4 val = texelFetch(samp0, coords, 0);\n");
|
||||
}
|
||||
else if (g_ActiveConfig.bSSAA)
|
||||
{
|
||||
// Sample shading, shader runs once per sample
|
||||
if (GetAPIType() == APIType::D3D)
|
||||
code.Write(" float4 val = tex0.Load(coords, isample);");
|
||||
else
|
||||
code.Write(" float4 val = texelFetch(samp0, coords, gl_SampleID);");
|
||||
code.Write(" float4 val = texelFetch(samp0, coords, gl_SampleID);");
|
||||
}
|
||||
else
|
||||
{
|
||||
// MSAA without sample shading, average out all samples.
|
||||
code.Write(" float4 val = float4(0.0f, 0.0f, 0.0f, 0.0f);\n");
|
||||
code.Write(" for (int i = 0; i < {}; i++)\n", samples);
|
||||
if (GetAPIType() == APIType::D3D)
|
||||
code.Write(" val += tex0.Load(coords, i);\n");
|
||||
else
|
||||
code.Write(" val += texelFetch(samp0, coords, i);\n");
|
||||
code.Write(" val += texelFetch(samp0, coords, i);\n");
|
||||
code.Write(" val /= float({});\n", samples);
|
||||
}
|
||||
|
||||
@@ -689,13 +614,12 @@ std::string GenerateEFBRestorePixelShader()
|
||||
{
|
||||
ShaderCode code;
|
||||
EmitSamplerDeclarations(code, 0, 2, false);
|
||||
EmitPixelMainDeclaration(code, 1, 0, "float4",
|
||||
GetAPIType() == APIType::D3D ? "out float depth : SV_Depth, " : "");
|
||||
EmitPixelMainDeclaration(code, 1, 0, "float4", "");
|
||||
code.Write("{{\n"
|
||||
" ocol0 = ");
|
||||
EmitSampleTexture(code, 0, "v_tex0");
|
||||
code.Write(";\n");
|
||||
code.Write(" {} = ", GetAPIType() == APIType::D3D ? "depth" : "gl_FragDepth");
|
||||
code.Write(" gl_FragDepth = ");
|
||||
EmitSampleTexture(code, 1, "v_tex0");
|
||||
code.Write(".r;\n"
|
||||
"}}\n");
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user