Merge pull request #10673 from iwubcode/spirv-backends
D3D: Generate HLSL from SPIRV*
This commit is contained in:
commit
828afc6735
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 50b4d5389b6a06f86fb63a2848e1a7da6d9755ca
|
|
@ -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");
|
||||
|
|
|
@ -103,7 +103,8 @@ ShaderCode GenerateGeometryShaderCode(APIType api_type, const ShaderHostConfig&
|
|||
"}};\n");
|
||||
|
||||
out.Write("struct VS_OUTPUT {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, host_config, "");
|
||||
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, host_config, "",
|
||||
ShaderStage::Geometry);
|
||||
out.Write("}};\n");
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
|
@ -113,15 +114,14 @@ ShaderCode GenerateGeometryShaderCode(APIType api_type, const ShaderHostConfig&
|
|||
|
||||
out.Write("VARYING_LOCATION(0) in VertexData {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, host_config,
|
||||
GetInterpolationQualifier(msaa, ssaa, true, true));
|
||||
GetInterpolationQualifier(msaa, ssaa, true, true),
|
||||
ShaderStage::Geometry);
|
||||
out.Write("}} vs[{}];\n", vertex_in);
|
||||
|
||||
out.Write("VARYING_LOCATION(0) out VertexData {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, host_config,
|
||||
GetInterpolationQualifier(msaa, ssaa, true, false));
|
||||
|
||||
if (stereo)
|
||||
out.Write("\tflat int layer;\n");
|
||||
GetInterpolationQualifier(msaa, ssaa, true, false),
|
||||
ShaderStage::Geometry);
|
||||
|
||||
out.Write("}} ps;\n");
|
||||
|
||||
|
@ -133,7 +133,10 @@ ShaderCode GenerateGeometryShaderCode(APIType api_type, const ShaderHostConfig&
|
|||
out.Write("\tVS_OUTPUT o;\n");
|
||||
|
||||
if (stereo)
|
||||
{
|
||||
out.Write("\tuint layer : SV_RenderTargetArrayIndex;\n");
|
||||
}
|
||||
out.Write("\tfloat4 posout : SV_Position;\n");
|
||||
|
||||
out.Write("}};\n");
|
||||
|
||||
|
@ -344,14 +347,18 @@ static void EmitVertex(ShaderCode& out, const ShaderHostConfig& host_config,
|
|||
else
|
||||
{
|
||||
out.Write("\tps.o = {};\n", vertex);
|
||||
out.Write("\tps.posout = {}.pos;\n", vertex);
|
||||
}
|
||||
|
||||
if (stereo)
|
||||
{
|
||||
// Select the output layer
|
||||
out.Write("\tps.layer = eye;\n");
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
out.Write("\tgl_Layer = eye;\n");
|
||||
else
|
||||
{
|
||||
out.Write("\tps.layer = eye;\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
|
|
|
@ -379,23 +379,10 @@ void WritePixelShaderCommonHeader(ShaderCode& out, APIType api_type,
|
|||
"int3 iround(float3 x) {{ return int3(round(x)); }}\n"
|
||||
"int4 iround(float4 x) {{ return int4(round(x)); }}\n\n");
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
{
|
||||
out.Write("SAMPLER_BINDING(0) uniform sampler2DArray samp[8];\n");
|
||||
}
|
||||
else // D3D
|
||||
{
|
||||
// Declare samplers
|
||||
out.Write("SamplerState samp[8] : register(s0);\n"
|
||||
"\n"
|
||||
"Texture2DArray tex[8] : register(t0);\n");
|
||||
}
|
||||
out.Write("SAMPLER_BINDING(0) uniform sampler2DArray samp[8];\n");
|
||||
out.Write("\n");
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
out.Write("UBO_BINDING(std140, 1) uniform PSBlock {{\n");
|
||||
else
|
||||
out.Write("cbuffer PSBlock : register(b0) {{\n");
|
||||
out.Write("UBO_BINDING(std140, 1) uniform PSBlock {{\n");
|
||||
|
||||
out.Write("\tint4 " I_COLORS "[4];\n"
|
||||
"\tint4 " I_KCOLORS "[4];\n"
|
||||
|
@ -445,10 +432,7 @@ void WritePixelShaderCommonHeader(ShaderCode& out, APIType api_type,
|
|||
{
|
||||
out.Write("{}", s_lighting_struct);
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
out.Write("UBO_BINDING(std140, 2) uniform VSBlock {{\n");
|
||||
else
|
||||
out.Write("cbuffer VSBlock : register(b1) {{\n");
|
||||
out.Write("UBO_BINDING(std140, 2) uniform VSBlock {{\n");
|
||||
|
||||
out.Write("{}", s_shader_uniforms);
|
||||
out.Write("}};\n");
|
||||
|
@ -456,18 +440,9 @@ void WritePixelShaderCommonHeader(ShaderCode& out, APIType api_type,
|
|||
|
||||
if (bounding_box)
|
||||
{
|
||||
if (api_type == APIType::D3D)
|
||||
{
|
||||
out.Write("globallycoherent RWBuffer<int> bbox_data : register(u2);\n"
|
||||
"#define atomicMin InterlockedMin\n"
|
||||
"#define atomicMax InterlockedMax");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write("SSBO_BINDING(0) buffer BBox {{\n"
|
||||
" int bbox_data[4];\n"
|
||||
"}};");
|
||||
}
|
||||
out.Write("SSBO_BINDING(0) coherent buffer BBox {{\n"
|
||||
" int bbox_data[4];\n"
|
||||
"}};");
|
||||
|
||||
out.Write(R"(
|
||||
#define bbox_left bbox_data[0]
|
||||
|
@ -535,24 +510,12 @@ void UpdateBoundingBox(float2 rawpos) {{
|
|||
|
||||
if (host_config.manual_texture_sampling)
|
||||
{
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
{
|
||||
out.Write(R"(
|
||||
out.Write(R"(
|
||||
int4 readTexture(in sampler2DArray tex, uint u, uint v, int layer, int lod) {{
|
||||
return iround(texelFetch(tex, int3(u, v, layer), lod) * 255.0);
|
||||
}}
|
||||
|
||||
int4 readTextureLinear(in sampler2DArray tex, uint2 uv1, uint2 uv2, int layer, int lod, int2 frac_uv) {{)");
|
||||
}
|
||||
else if (api_type == APIType::D3D)
|
||||
{
|
||||
out.Write(R"(
|
||||
int4 readTexture(in Texture2DArray tex, uint u, uint v, int layer, int lod) {{
|
||||
return iround(tex.Load(int4(u, v, layer, lod)) * 255.0);
|
||||
}}
|
||||
|
||||
int4 readTextureLinear(in Texture2DArray tex, uint2 uv1, uint2 uv2, int layer, int lod, int2 frac_uv) {{)");
|
||||
}
|
||||
|
||||
out.Write(R"(
|
||||
int4 result =
|
||||
|
@ -621,41 +584,26 @@ uint WrapCoord(int coord, uint wrap, int size) {{
|
|||
}
|
||||
}
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
{
|
||||
out.Write("\nint4 sampleTexture(uint texmap, in sampler2DArray tex, int2 uv, int layer) {{\n");
|
||||
}
|
||||
else if (api_type == APIType::D3D)
|
||||
{
|
||||
out.Write("\nint4 sampleTexture(uint texmap, in Texture2DArray tex, in SamplerState tex_samp, "
|
||||
"int2 uv, int layer) {{\n");
|
||||
}
|
||||
out.Write("\nint4 sampleTexture(uint texmap, in sampler2DArray tex, int2 uv, int layer) {{\n");
|
||||
|
||||
if (!host_config.manual_texture_sampling)
|
||||
{
|
||||
out.Write(" float size_s = float(" I_TEXDIMS "[texmap].x * 128);\n"
|
||||
" float size_t = float(" I_TEXDIMS "[texmap].y * 128);\n"
|
||||
" float3 coords = float3(float(uv.x) / size_s, float(uv.y) / size_t, layer);\n");
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
if (!host_config.backend_sampler_lod_bias)
|
||||
{
|
||||
if (!host_config.backend_sampler_lod_bias)
|
||||
{
|
||||
out.Write(" uint texmode0 = samp_texmode0(texmap);\n"
|
||||
" float lod_bias = float({}) / 256.0f;\n"
|
||||
" return iround(255.0 * texture(tex, coords, lod_bias));\n",
|
||||
BitfieldExtract<&SamplerState::TM0::lod_bias>("texmode0"));
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write(" return iround(255.0 * texture(tex, coords));\n");
|
||||
}
|
||||
out.Write(" uint texmode0 = samp_texmode0(texmap);\n"
|
||||
" float lod_bias = float({}) / 256.0f;\n"
|
||||
" return iround(255.0 * texture(tex, coords, lod_bias));\n",
|
||||
BitfieldExtract<&SamplerState::TM0::lod_bias>("texmode0"));
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write(" return iround(255.0 * texture(tex, coords));\n");
|
||||
}
|
||||
|
||||
out.Write("}}\n");
|
||||
}
|
||||
else if (api_type == APIType::D3D)
|
||||
{
|
||||
out.Write(" return iround(255.0 * tex.Sample(tex_samp, coords));\n}}\n");
|
||||
}
|
||||
out.Write("}}\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -694,31 +642,20 @@ uint WrapCoord(int coord, uint wrap, int size) {{
|
|||
int native_size_t = )" I_TEXDIMS R"([texmap].y;
|
||||
)");
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
{
|
||||
out.Write(R"(
|
||||
out.Write(R"(
|
||||
int3 size = textureSize(tex, 0);
|
||||
int size_s = size.x;
|
||||
int size_t = size.y;
|
||||
)");
|
||||
if (g_ActiveConfig.backend_info.bSupportsTextureQueryLevels)
|
||||
{
|
||||
out.Write(" int number_of_levels = textureQueryLevels(tex);\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write(" int number_of_levels = 256; // textureQueryLevels is not supported\n");
|
||||
ERROR_LOG_FMT(VIDEO, "textureQueryLevels is not supported! Odd graphical results may "
|
||||
"occur if custom textures are in use!");
|
||||
}
|
||||
}
|
||||
else if (api_type == APIType::D3D)
|
||||
if (g_ActiveConfig.backend_info.bSupportsTextureQueryLevels)
|
||||
{
|
||||
ASSERT(g_ActiveConfig.backend_info.bSupportsTextureQueryLevels);
|
||||
out.Write(R"(
|
||||
int size_s, size_t, layers, number_of_levels;
|
||||
tex.GetDimensions(0, size_s, size_t, layers, number_of_levels);
|
||||
)");
|
||||
out.Write(" int number_of_levels = textureQueryLevels(tex);\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write(" int number_of_levels = 256; // textureQueryLevels is not supported\n");
|
||||
ERROR_LOG_FMT(VIDEO, "textureQueryLevels is not supported! Odd graphical results may "
|
||||
"occur if custom textures are in use!");
|
||||
}
|
||||
|
||||
out.Write(R"(
|
||||
|
@ -737,34 +674,23 @@ uint WrapCoord(int coord, uint wrap, int size) {{
|
|||
)");
|
||||
}
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
if (g_ActiveConfig.backend_info.bSupportsCoarseDerivatives)
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.bSupportsCoarseDerivatives)
|
||||
{
|
||||
// The software renderer uses the equivalent of coarse derivatives, so use them here for
|
||||
// consistency. This hasn't been hardware tested.
|
||||
// Note that bSupportsCoarseDerivatives being false only means dFdxCoarse and dFdxFine don't
|
||||
// exist. The GPU may still implement dFdx using coarse derivatives; we just don't have the
|
||||
// ability to specifically require it.
|
||||
out.Write(R"(
|
||||
// The software renderer uses the equivalent of coarse derivatives, so use them here for
|
||||
// consistency. This hasn't been hardware tested.
|
||||
// Note that bSupportsCoarseDerivatives being false only means dFdxCoarse and dFdxFine don't
|
||||
// exist. The GPU may still implement dFdx using coarse derivatives; we just don't have the
|
||||
// ability to specifically require it.
|
||||
out.Write(R"(
|
||||
float2 uv_delta_x = abs(dFdxCoarse(float2(uv)));
|
||||
float2 uv_delta_y = abs(dFdyCoarse(float2(uv)));
|
||||
)");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write(R"(
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write(R"(
|
||||
float2 uv_delta_x = abs(dFdx(float2(uv)));
|
||||
float2 uv_delta_y = abs(dFdy(float2(uv)));
|
||||
)");
|
||||
}
|
||||
}
|
||||
else if (api_type == APIType::D3D)
|
||||
{
|
||||
ASSERT(g_ActiveConfig.backend_info.bSupportsCoarseDerivatives);
|
||||
out.Write(R"(
|
||||
float2 uv_delta_x = abs(ddx_coarse(float2(uv)));
|
||||
float2 uv_delta_y = abs(ddy_coarse(float2(uv)));
|
||||
)");
|
||||
}
|
||||
|
||||
|
@ -869,16 +795,8 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
|
|||
WriteBitfieldExtractHeader(out, api_type, host_config);
|
||||
WritePixelShaderCommonHeader(out, api_type, host_config, uid_data->bounding_box);
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
{
|
||||
out.Write("\n#define sampleTextureWrapper(texmap, uv, layer) "
|
||||
"sampleTexture(texmap, samp[texmap], uv, layer)\n");
|
||||
}
|
||||
else if (api_type == APIType::D3D)
|
||||
{
|
||||
out.Write("\n#define sampleTextureWrapper(texmap, uv, layer) "
|
||||
"sampleTexture(texmap, tex[texmap], samp[texmap], uv, layer)\n");
|
||||
}
|
||||
out.Write("\n#define sampleTextureWrapper(texmap, uv, layer) "
|
||||
"sampleTexture(texmap, samp[texmap], uv, layer)\n");
|
||||
|
||||
if (uid_data->forced_early_z && g_ActiveConfig.backend_info.bSupportsEarlyZ)
|
||||
{
|
||||
|
@ -915,16 +833,8 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
|
|||
// all of the
|
||||
// ARB_image_load_store extension yet.
|
||||
|
||||
// D3D11 also has a way to force the driver to enable early-z, so we're fine here.
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
{
|
||||
// This is a #define which signals whatever early-z method the driver supports.
|
||||
out.Write("FORCE_EARLY_Z; \n");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write("[earlydepthstencil]\n");
|
||||
}
|
||||
// This is a #define which signals whatever early-z method the driver supports.
|
||||
out.Write("FORCE_EARLY_Z; \n");
|
||||
}
|
||||
|
||||
// Only use dual-source blending when required on drivers that don't support it very well.
|
||||
|
@ -943,169 +853,126 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
|
|||
use_shader_blend || use_shader_logic_op ||
|
||||
DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DISCARD_WITH_EARLY_Z);
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
// Framebuffer fetch is only supported by Metal, so ensure that we're running Vulkan (MoltenVK)
|
||||
// if we want to use it.
|
||||
if (api_type == APIType::Vulkan)
|
||||
// Framebuffer fetch is only supported by Metal, so ensure that we're running Vulkan (MoltenVK)
|
||||
// if we want to use it.
|
||||
if (api_type == APIType::Vulkan)
|
||||
{
|
||||
if (use_dual_source)
|
||||
{
|
||||
if (use_dual_source)
|
||||
{
|
||||
out.Write("FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0) out vec4 {};\n"
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1) out vec4 ocol1;\n",
|
||||
use_framebuffer_fetch ? "real_ocol0" : "ocol0");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Metal doesn't support a single unified variable for both input and output,
|
||||
// so when using framebuffer fetch, we declare the input separately below.
|
||||
out.Write("FRAGMENT_OUTPUT_LOCATION(0) out vec4 {};\n",
|
||||
use_framebuffer_fetch ? "real_ocol0" : "ocol0");
|
||||
}
|
||||
|
||||
if (use_framebuffer_fetch)
|
||||
{
|
||||
// Subpass inputs will be converted to framebuffer fetch by SPIRV-Cross.
|
||||
out.Write("INPUT_ATTACHMENT_BINDING(0, 0, 0) uniform subpassInput in_ocol0;\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
bool has_broken_decoration =
|
||||
DriverDetails::HasBug(DriverDetails::BUG_BROKEN_FRAGMENT_SHADER_INDEX_DECORATION);
|
||||
|
||||
out.Write("{} {} vec4 {};\n",
|
||||
has_broken_decoration ? "FRAGMENT_OUTPUT_LOCATION(0)" :
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0)",
|
||||
use_framebuffer_fetch ? "FRAGMENT_INOUT" : "out",
|
||||
out.Write("FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0) out vec4 {};\n"
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1) out vec4 ocol1;\n",
|
||||
use_framebuffer_fetch ? "real_ocol0" : "ocol0");
|
||||
|
||||
if (use_dual_source)
|
||||
{
|
||||
out.Write("{} out vec4 ocol1;\n", has_broken_decoration ?
|
||||
"FRAGMENT_OUTPUT_LOCATION(1)" :
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1)");
|
||||
}
|
||||
}
|
||||
|
||||
if (uid_data->per_pixel_depth)
|
||||
out.Write("#define depth gl_FragDepth\n");
|
||||
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
out.Write("VARYING_LOCATION(0) in VertexData {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, uid_data->genMode_numtexgens, host_config,
|
||||
GetInterpolationQualifier(msaa, ssaa, true, true));
|
||||
|
||||
if (stereo)
|
||||
out.Write("\tflat int layer;\n");
|
||||
|
||||
out.Write("}};\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let's set up attributes
|
||||
u32 counter = 0;
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 colors_0;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 colors_1;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
for (u32 i = 0; i < uid_data->genMode_numtexgens; ++i)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 tex{};\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa), i);
|
||||
}
|
||||
if (!host_config.fast_depth_calc)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 clipPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
}
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 Normal;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 WorldPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
}
|
||||
// Metal doesn't support a single unified variable for both input and output,
|
||||
// so when using framebuffer fetch, we declare the input separately below.
|
||||
out.Write("FRAGMENT_OUTPUT_LOCATION(0) out vec4 {};\n",
|
||||
use_framebuffer_fetch ? "real_ocol0" : "ocol0");
|
||||
}
|
||||
|
||||
out.Write("void main()\n{{\n");
|
||||
out.Write("\tfloat4 rawpos = gl_FragCoord;\n");
|
||||
|
||||
if (use_framebuffer_fetch)
|
||||
{
|
||||
// Store off a copy of the initial framebuffer value.
|
||||
//
|
||||
// If FB_FETCH_VALUE isn't defined (i.e. no special keyword for fetching from the
|
||||
// framebuffer), we read from real_ocol0.
|
||||
out.Write("#ifdef FB_FETCH_VALUE\n"
|
||||
"\tfloat4 initial_ocol0 = FB_FETCH_VALUE;\n"
|
||||
"#else\n"
|
||||
"\tfloat4 initial_ocol0 = real_ocol0;\n"
|
||||
"#endif\n");
|
||||
|
||||
// QComm's Adreno driver doesn't seem to like using the framebuffer_fetch value as an
|
||||
// intermediate value with multiple reads & modifications, so we pull out the "real" output
|
||||
// value above and use a temporary for calculations, then set the output value once at the
|
||||
// end of the shader.
|
||||
out.Write("\tfloat4 ocol0;\n");
|
||||
}
|
||||
|
||||
if (use_shader_blend)
|
||||
{
|
||||
out.Write("\tfloat4 ocol1;\n");
|
||||
// Subpass inputs will be converted to framebuffer fetch by SPIRV-Cross.
|
||||
out.Write("INPUT_ATTACHMENT_BINDING(0, 0, 0) uniform subpassInput in_ocol0;\n");
|
||||
}
|
||||
}
|
||||
else // D3D
|
||||
else
|
||||
#endif
|
||||
{
|
||||
out.Write("void main(\n");
|
||||
if (uid_data->uint_output)
|
||||
{
|
||||
out.Write(" out uint4 ocol0 : SV_Target,\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write(" out float4 ocol0 : SV_Target0,\n"
|
||||
" out float4 ocol1 : SV_Target1,\n");
|
||||
}
|
||||
out.Write("{}"
|
||||
" in float4 rawpos : SV_Position,\n",
|
||||
uid_data->per_pixel_depth ? " out float depth : SV_Depth,\n" : "");
|
||||
bool has_broken_decoration =
|
||||
DriverDetails::HasBug(DriverDetails::BUG_BROKEN_FRAGMENT_SHADER_INDEX_DECORATION);
|
||||
|
||||
out.Write(" in {} float4 colors_0 : COLOR0,\n", GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write(" in {} float4 colors_1 : COLOR1\n", GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("{} {} {} {};\n",
|
||||
has_broken_decoration ? "FRAGMENT_OUTPUT_LOCATION(0)" :
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0)",
|
||||
use_framebuffer_fetch ? "FRAGMENT_INOUT" : "out",
|
||||
uid_data->uint_output ? "uvec4" : "vec4",
|
||||
use_framebuffer_fetch ? "real_ocol0" : "ocol0");
|
||||
|
||||
// compute window position if needed because binding semantic WPOS is not widely supported
|
||||
if (use_dual_source)
|
||||
{
|
||||
out.Write("{} out {} ocol1;\n",
|
||||
has_broken_decoration ? "FRAGMENT_OUTPUT_LOCATION(1)" :
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1)",
|
||||
uid_data->uint_output ? "uvec4" : "vec4");
|
||||
}
|
||||
}
|
||||
|
||||
if (uid_data->per_pixel_depth)
|
||||
out.Write("#define depth gl_FragDepth\n");
|
||||
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
out.Write("VARYING_LOCATION(0) in VertexData {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, uid_data->genMode_numtexgens, host_config,
|
||||
GetInterpolationQualifier(msaa, ssaa, true, true), ShaderStage::Pixel);
|
||||
|
||||
out.Write("}};\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let's set up attributes
|
||||
u32 counter = 0;
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 colors_0;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 colors_1;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
for (u32 i = 0; i < uid_data->genMode_numtexgens; ++i)
|
||||
{
|
||||
out.Write(",\n in {} float3 tex{} : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa), i,
|
||||
i);
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 tex{};\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa), i);
|
||||
}
|
||||
if (!host_config.fast_depth_calc)
|
||||
{
|
||||
out.Write(",\n in {} float4 clipPos : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa),
|
||||
uid_data->genMode_numtexgens);
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 clipPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
}
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write(",\n in {} float3 Normal : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa),
|
||||
uid_data->genMode_numtexgens + 1);
|
||||
out.Write(",\n in {} float3 WorldPos : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa),
|
||||
uid_data->genMode_numtexgens + 2);
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 Normal;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 WorldPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
}
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
out.Write(",\n in float clipDist0 : SV_ClipDistance0\n"
|
||||
",\n in float clipDist1 : SV_ClipDistance1\n");
|
||||
}
|
||||
if (stereo)
|
||||
out.Write(",\n in uint layer : SV_RenderTargetArrayIndex\n");
|
||||
out.Write(" ) {{\n");
|
||||
}
|
||||
if (!stereo)
|
||||
|
||||
out.Write("void main()\n{{\n");
|
||||
out.Write("\tfloat4 rawpos = gl_FragCoord;\n");
|
||||
|
||||
if (use_framebuffer_fetch)
|
||||
{
|
||||
// Store off a copy of the initial framebuffer value.
|
||||
//
|
||||
// If FB_FETCH_VALUE isn't defined (i.e. no special keyword for fetching from the
|
||||
// framebuffer), we read from real_ocol0.
|
||||
out.Write("#ifdef FB_FETCH_VALUE\n"
|
||||
"\tfloat4 initial_ocol0 = FB_FETCH_VALUE;\n"
|
||||
"#else\n"
|
||||
"\tfloat4 initial_ocol0 = real_ocol0;\n"
|
||||
"#endif\n");
|
||||
|
||||
// QComm's Adreno driver doesn't seem to like using the framebuffer_fetch value as an
|
||||
// intermediate value with multiple reads & modifications, so we pull out the "real" output
|
||||
// value above and use a temporary for calculations, then set the output value once at the
|
||||
// end of the shader.
|
||||
out.Write("\tfloat4 ocol0;\n");
|
||||
}
|
||||
|
||||
if (use_shader_blend)
|
||||
{
|
||||
out.Write("\tfloat4 ocol1;\n");
|
||||
}
|
||||
|
||||
if (host_config.backend_geometry_shaders && stereo)
|
||||
{
|
||||
out.Write("\tint layer = gl_Layer;\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write("\tint layer = 0;\n");
|
||||
}
|
||||
|
||||
out.Write("\tint4 c0 = " I_COLORS "[1], c1 = " I_COLORS "[2], c2 = " I_COLORS
|
||||
"[3], prev = " I_COLORS "[0];\n"
|
||||
|
|
|
@ -441,10 +441,7 @@ std::string PostProcessing::GetUniformBufferHeader() const
|
|||
{
|
||||
std::ostringstream ss;
|
||||
u32 unused_counter = 1;
|
||||
if (g_ActiveConfig.backend_info.api_type == APIType::D3D)
|
||||
ss << "cbuffer PSBlock : register(b0) {\n";
|
||||
else
|
||||
ss << "UBO_BINDING(std140, 1) uniform PSBlock {\n";
|
||||
ss << "UBO_BINDING(std140, 1) uniform PSBlock {\n";
|
||||
|
||||
// Builtin uniforms
|
||||
ss << " float4 resolution;\n";
|
||||
|
@ -499,42 +496,20 @@ std::string PostProcessing::GetHeader() const
|
|||
{
|
||||
std::ostringstream ss;
|
||||
ss << GetUniformBufferHeader();
|
||||
if (g_ActiveConfig.backend_info.api_type == APIType::D3D)
|
||||
ss << "SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n";
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
ss << "Texture2DArray samp0 : register(t0);\n";
|
||||
ss << "SamplerState samp0_ss : register(s0);\n";
|
||||
ss << "VARYING_LOCATION(0) in VertexData {\n";
|
||||
ss << " float3 v_tex0;\n";
|
||||
ss << "};\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << "SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n";
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
ss << "VARYING_LOCATION(0) in VertexData {\n";
|
||||
ss << " float3 v_tex0;\n";
|
||||
ss << "};\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << "VARYING_LOCATION(0) in float3 v_tex0;\n";
|
||||
}
|
||||
|
||||
ss << "FRAGMENT_OUTPUT_LOCATION(0) out float4 ocol0;\n";
|
||||
ss << "VARYING_LOCATION(0) in float3 v_tex0;\n";
|
||||
}
|
||||
|
||||
// Rename main, since we need to set up globals
|
||||
if (g_ActiveConfig.backend_info.api_type == APIType::D3D)
|
||||
{
|
||||
ss << R"(
|
||||
#define main real_main
|
||||
static float3 v_tex0;
|
||||
static float4 ocol0;
|
||||
|
||||
// Wrappers for sampling functions.
|
||||
#define texture(sampler, coords) sampler.Sample(sampler##_ss, coords)
|
||||
#define textureOffset(sampler, coords, offset) sampler.Sample(sampler##_ss, coords, offset)
|
||||
)";
|
||||
}
|
||||
ss << "FRAGMENT_OUTPUT_LOCATION(0) out float4 ocol0;\n";
|
||||
|
||||
ss << R"(
|
||||
float4 Sample() { return texture(samp0, v_tex0); }
|
||||
|
@ -591,22 +566,7 @@ void SetOutput(float4 color)
|
|||
|
||||
std::string PostProcessing::GetFooter() const
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.api_type == APIType::D3D)
|
||||
{
|
||||
return R"(
|
||||
|
||||
#undef main
|
||||
void main(in float3 v_tex0_ : TEXCOORD0, out float4 ocol0_ : SV_Target)
|
||||
{
|
||||
v_tex0 = v_tex0_;
|
||||
real_main();
|
||||
ocol0_ = ocol0;
|
||||
})";
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool PostProcessing::CompileVertexShader()
|
||||
|
@ -614,28 +574,20 @@ bool PostProcessing::CompileVertexShader()
|
|||
std::ostringstream ss;
|
||||
ss << GetUniformBufferHeader();
|
||||
|
||||
if (g_ActiveConfig.backend_info.api_type == APIType::D3D)
|
||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
ss << "void main(in uint id : SV_VertexID, out float3 v_tex0 : TEXCOORD0,\n";
|
||||
ss << " out float4 opos : SV_Position) {\n";
|
||||
ss << "VARYING_LOCATION(0) out VertexData {\n";
|
||||
ss << " float3 v_tex0;\n";
|
||||
ss << "};\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
ss << "VARYING_LOCATION(0) out VertexData {\n";
|
||||
ss << " float3 v_tex0;\n";
|
||||
ss << "};\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << "VARYING_LOCATION(0) out float3 v_tex0;\n";
|
||||
}
|
||||
|
||||
ss << "#define id gl_VertexID\n";
|
||||
ss << "#define opos gl_Position\n";
|
||||
ss << "void main() {\n";
|
||||
ss << "VARYING_LOCATION(0) out float3 v_tex0;\n";
|
||||
}
|
||||
|
||||
ss << "#define id gl_VertexID\n";
|
||||
ss << "#define opos gl_Position\n";
|
||||
ss << "void main() {\n";
|
||||
ss << " v_tex0 = float3(float((id << 1) & 2), float(id & 2), 0.0f);\n";
|
||||
ss << " opos = float4(v_tex0.xy * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n";
|
||||
ss << " v_tex0 = float3(src_rect.xy + (src_rect.zw * v_tex0.xy), float(src_layer));\n";
|
||||
|
|
|
@ -93,20 +93,7 @@ std::string GetDiskShaderCacheFileName(APIType api_type, const char* type, bool
|
|||
|
||||
void WriteIsNanHeader(ShaderCode& out, APIType api_type)
|
||||
{
|
||||
if (api_type == APIType::D3D)
|
||||
{
|
||||
out.Write("bool dolphin_isnan(float f) {{\n"
|
||||
" // Workaround for the HLSL compiler deciding that isnan can never be true and\n"
|
||||
" // optimising away the call, even though the value can actually be NaN\n"
|
||||
" // Just look for the bit pattern that indicates NaN instead\n"
|
||||
" return (asint(f) & 0x7FFFFFFF) > 0x7F800000;\n"
|
||||
"}}\n\n");
|
||||
// If isfinite is needed, (asint(f) & 0x7F800000) != 0x7F800000 can be used
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write("#define dolphin_isnan(f) isnan(f)\n");
|
||||
}
|
||||
out.Write("#define dolphin_isnan(f) isnan(f)\n");
|
||||
}
|
||||
|
||||
void WriteBitfieldExtractHeader(ShaderCode& out, APIType api_type,
|
||||
|
@ -135,14 +122,15 @@ void WriteBitfieldExtractHeader(ShaderCode& out, APIType api_type,
|
|||
|
||||
static void DefineOutputMember(ShaderCode& object, APIType api_type, std::string_view qualifier,
|
||||
std::string_view type, std::string_view name, int var_index,
|
||||
std::string_view semantic = {}, int semantic_index = -1)
|
||||
ShaderStage stage, std::string_view semantic = {},
|
||||
int semantic_index = -1)
|
||||
{
|
||||
object.Write("\t{} {} {}", qualifier, type, name);
|
||||
|
||||
if (var_index != -1)
|
||||
object.Write("{}", var_index);
|
||||
|
||||
if (api_type == APIType::D3D && !semantic.empty())
|
||||
if (api_type == APIType::D3D && !semantic.empty() && stage == ShaderStage::Geometry)
|
||||
{
|
||||
if (semantic_index != -1)
|
||||
object.Write(" : {}{}", semantic, semantic_index);
|
||||
|
@ -154,30 +142,83 @@ static void DefineOutputMember(ShaderCode& object, APIType api_type, std::string
|
|||
}
|
||||
|
||||
void GenerateVSOutputMembers(ShaderCode& object, APIType api_type, u32 texgens,
|
||||
const ShaderHostConfig& host_config, std::string_view qualifier)
|
||||
const ShaderHostConfig& host_config, std::string_view qualifier,
|
||||
ShaderStage stage)
|
||||
{
|
||||
DefineOutputMember(object, api_type, qualifier, "float4", "pos", -1, "SV_Position");
|
||||
DefineOutputMember(object, api_type, qualifier, "float4", "colors_", 0, "COLOR", 0);
|
||||
DefineOutputMember(object, api_type, qualifier, "float4", "colors_", 1, "COLOR", 1);
|
||||
|
||||
for (unsigned int i = 0; i < texgens; ++i)
|
||||
DefineOutputMember(object, api_type, qualifier, "float3", "tex", i, "TEXCOORD", i);
|
||||
|
||||
if (!host_config.fast_depth_calc)
|
||||
DefineOutputMember(object, api_type, qualifier, "float4", "clipPos", -1, "TEXCOORD", texgens);
|
||||
|
||||
if (host_config.per_pixel_lighting)
|
||||
// SPIRV-Cross names all semantics as "TEXCOORD"
|
||||
// Unfortunately Geometry shaders (which also uses this function)
|
||||
// aren't supported. The output semantic name needs to match
|
||||
// up with the input semantic name for both the next stage (pixel shader)
|
||||
// and the previous stage (vertex shader), so
|
||||
// we need to handle geometry in a special way...
|
||||
if (api_type == APIType::D3D && stage == ShaderStage::Geometry)
|
||||
{
|
||||
DefineOutputMember(object, api_type, qualifier, "float3", "Normal", -1, "TEXCOORD",
|
||||
texgens + 1);
|
||||
DefineOutputMember(object, api_type, qualifier, "float3", "WorldPos", -1, "TEXCOORD",
|
||||
texgens + 2);
|
||||
DefineOutputMember(object, api_type, qualifier, "float4", "pos", -1, stage, "TEXCOORD", 0);
|
||||
DefineOutputMember(object, api_type, qualifier, "float4", "colors_", 0, stage, "TEXCOORD", 1);
|
||||
DefineOutputMember(object, api_type, qualifier, "float4", "colors_", 1, stage, "TEXCOORD", 2);
|
||||
|
||||
const unsigned int index_base = 3;
|
||||
unsigned int index_offset = 0;
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
DefineOutputMember(object, api_type, qualifier, "float", "clipDist", 0, stage, "TEXCOORD",
|
||||
index_base + index_offset);
|
||||
DefineOutputMember(object, api_type, qualifier, "float", "clipDist", 1, stage, "TEXCOORD",
|
||||
index_base + index_offset + 1);
|
||||
index_offset += 2;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < texgens; ++i)
|
||||
{
|
||||
DefineOutputMember(object, api_type, qualifier, "float3", "tex", i, stage, "TEXCOORD",
|
||||
index_base + index_offset + i);
|
||||
}
|
||||
index_offset += texgens;
|
||||
|
||||
if (!host_config.fast_depth_calc)
|
||||
{
|
||||
DefineOutputMember(object, api_type, qualifier, "float4", "clipPos", -1, stage, "TEXCOORD",
|
||||
index_base + index_offset);
|
||||
index_offset++;
|
||||
}
|
||||
|
||||
if (host_config.per_pixel_lighting)
|
||||
{
|
||||
DefineOutputMember(object, api_type, qualifier, "float3", "Normal", -1, stage, "TEXCOORD",
|
||||
index_base + index_offset);
|
||||
DefineOutputMember(object, api_type, qualifier, "float3", "WorldPos", -1, stage, "TEXCOORD",
|
||||
index_base + index_offset + 1);
|
||||
index_offset += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (host_config.backend_geometry_shaders)
|
||||
else
|
||||
{
|
||||
DefineOutputMember(object, api_type, qualifier, "float", "clipDist", 0, "SV_ClipDistance", 0);
|
||||
DefineOutputMember(object, api_type, qualifier, "float", "clipDist", 1, "SV_ClipDistance", 1);
|
||||
DefineOutputMember(object, api_type, qualifier, "float4", "pos", -1, stage, "SV_Position");
|
||||
DefineOutputMember(object, api_type, qualifier, "float4", "colors_", 0, stage, "COLOR", 0);
|
||||
DefineOutputMember(object, api_type, qualifier, "float4", "colors_", 1, stage, "COLOR", 1);
|
||||
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
DefineOutputMember(object, api_type, qualifier, "float", "clipDist", 0, stage,
|
||||
"SV_ClipDistance", 0);
|
||||
DefineOutputMember(object, api_type, qualifier, "float", "clipDist", 1, stage,
|
||||
"SV_ClipDistance", 1);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < texgens; ++i)
|
||||
DefineOutputMember(object, api_type, qualifier, "float3", "tex", i, stage, "TEXCOORD", i);
|
||||
|
||||
if (!host_config.fast_depth_calc)
|
||||
DefineOutputMember(object, api_type, qualifier, "float4", "clipPos", -1, stage, "TEXCOORD",
|
||||
texgens);
|
||||
|
||||
if (host_config.per_pixel_lighting)
|
||||
{
|
||||
DefineOutputMember(object, api_type, qualifier, "float3", "Normal", -1, stage, "TEXCOORD",
|
||||
texgens + 1);
|
||||
DefineOutputMember(object, api_type, qualifier, "float3", "WorldPos", -1, stage, "TEXCOORD",
|
||||
texgens + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "Common/StringUtil.h"
|
||||
#include "Common/TypeUtils.h"
|
||||
|
||||
#include "VideoCommon/AbstractShader.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
||||
/**
|
||||
|
@ -189,7 +190,8 @@ void WriteBitfieldExtractHeader(ShaderCode& out, APIType api_type,
|
|||
const ShaderHostConfig& host_config);
|
||||
|
||||
void GenerateVSOutputMembers(ShaderCode& object, APIType api_type, u32 texgens,
|
||||
const ShaderHostConfig& host_config, std::string_view qualifier);
|
||||
const ShaderHostConfig& host_config, std::string_view qualifier,
|
||||
ShaderStage stage);
|
||||
|
||||
void AssignVSOutputMembers(ShaderCode& object, std::string_view a, std::string_view b, u32 texgens,
|
||||
const ShaderHostConfig& host_config);
|
||||
|
@ -220,57 +222,34 @@ void WriteSwitch(ShaderCode& out, APIType ApiType, std::string_view variable,
|
|||
const Common::EnumMap<std::string_view, last_member>& values, int indent,
|
||||
bool break_)
|
||||
{
|
||||
const bool make_switch = (ApiType == APIType::D3D);
|
||||
|
||||
// The second template argument is needed to avoid compile errors from ambiguity with multiple
|
||||
// enums with the same number of members in GCC prior to 8. See https://godbolt.org/z/xcKaW1seW
|
||||
// and https://godbolt.org/z/hz7Yqq1P5
|
||||
using enum_type = decltype(last_member);
|
||||
|
||||
// {:{}} is used to indent by formatting an empty string with a variable width
|
||||
if (make_switch)
|
||||
{
|
||||
out.Write("{:{}}switch ({}) {{\n", "", indent, variable);
|
||||
for (u32 i = 0; i <= static_cast<u32>(last_member); i++)
|
||||
// Generate a tree of if statements recursively
|
||||
// std::function must be used because auto won't capture before initialization and thus can't be
|
||||
// used recursively
|
||||
std::function<void(u32, u32, u32)> BuildTree = [&](u32 cur_indent, u32 low, u32 high) {
|
||||
// Each generated statement is for low <= x < high
|
||||
if (high == low + 1)
|
||||
{
|
||||
const enum_type key = static_cast<enum_type>(i);
|
||||
|
||||
// Assumes existence of an EnumFormatter
|
||||
out.Write("{:{}}case {:s}:\n", "", indent, key);
|
||||
// Down to 1 case (low <= x < low + 1 means x == low)
|
||||
const enum_type key = static_cast<enum_type>(low);
|
||||
// Note that this indentation behaves poorly for multi-line code
|
||||
if (!values[key].empty())
|
||||
out.Write("{:{}} {}\n", "", indent, values[key]);
|
||||
if (break_)
|
||||
out.Write("{:{}} break;\n", "", indent);
|
||||
out.Write("{:{}}{} // {}\n", "", cur_indent, values[key], key);
|
||||
}
|
||||
out.Write("{:{}}}}\n", "", indent);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generate a tree of if statements recursively
|
||||
// std::function must be used because auto won't capture before initialization and thus can't be
|
||||
// used recursively
|
||||
std::function<void(u32, u32, u32)> BuildTree = [&](u32 cur_indent, u32 low, u32 high) {
|
||||
// Each generated statement is for low <= x < high
|
||||
if (high == low + 1)
|
||||
{
|
||||
// Down to 1 case (low <= x < low + 1 means x == low)
|
||||
const enum_type key = static_cast<enum_type>(low);
|
||||
// Note that this indentation behaves poorly for multi-line code
|
||||
out.Write("{:{}}{} // {}\n", "", cur_indent, values[key], key);
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 mid = low + ((high - low) / 2);
|
||||
out.Write("{:{}}if ({} < {}u) {{\n", "", cur_indent, variable, mid);
|
||||
BuildTree(cur_indent + 2, low, mid);
|
||||
out.Write("{:{}}}} else {{\n", "", cur_indent);
|
||||
BuildTree(cur_indent + 2, mid, high);
|
||||
out.Write("{:{}}}}\n", "", cur_indent);
|
||||
}
|
||||
};
|
||||
BuildTree(indent, 0, static_cast<u32>(last_member) + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 mid = low + ((high - low) / 2);
|
||||
out.Write("{:{}}if ({} < {}u) {{\n", "", cur_indent, variable, mid);
|
||||
BuildTree(cur_indent + 2, low, mid);
|
||||
out.Write("{:{}}}} else {{\n", "", cur_indent);
|
||||
BuildTree(cur_indent + 2, mid, high);
|
||||
out.Write("{:{}}}}\n", "", cur_indent);
|
||||
}
|
||||
};
|
||||
BuildTree(indent, 0, static_cast<u32>(last_member) + 1);
|
||||
}
|
||||
|
||||
// Constant variable names
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
// Copyright 2022 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "VideoCommon/Spirv.h"
|
||||
|
||||
// glslang includes
|
||||
#include "GlslangToSpv.h"
|
||||
#include "ResourceLimits.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 "VideoCommon/VideoBackendBase.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
std::optional<SPIRV::CodeVector>
|
||||
CompileShaderToSPV(EShLanguage stage, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version, const char* stage_filename,
|
||||
std::string_view source)
|
||||
{
|
||||
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);
|
||||
if (api_type == APIType::Vulkan)
|
||||
messages = static_cast<EShMessages>(messages | EShMsgVulkanRules);
|
||||
int default_version = 450;
|
||||
|
||||
const char* pass_source_code = source.data();
|
||||
int pass_source_code_length = static_cast<int>(source.size());
|
||||
|
||||
shader->setEnvTarget(glslang::EShTargetSpv, language_version);
|
||||
|
||||
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 << source << 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;
|
||||
}
|
||||
|
||||
SPIRV::CodeVector 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;
|
||||
}
|
||||
else
|
||||
{
|
||||
options.disableOptimizer = false;
|
||||
options.stripDebugInfo = 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 << source << 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;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace SPIRV
|
||||
{
|
||||
std::optional<CodeVector> CompileVertexShader(std::string_view source_code, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version)
|
||||
{
|
||||
return CompileShaderToSPV(EShLangVertex, api_type, language_version, "vs", source_code);
|
||||
}
|
||||
|
||||
std::optional<CodeVector> CompileGeometryShader(std::string_view source_code, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version)
|
||||
{
|
||||
return CompileShaderToSPV(EShLangGeometry, api_type, language_version, "gs", source_code);
|
||||
}
|
||||
|
||||
std::optional<CodeVector> CompileFragmentShader(std::string_view source_code, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version)
|
||||
{
|
||||
return CompileShaderToSPV(EShLangFragment, api_type, language_version, "ps", source_code);
|
||||
}
|
||||
|
||||
std::optional<CodeVector> CompileComputeShader(std::string_view source_code, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version)
|
||||
{
|
||||
return CompileShaderToSPV(EShLangCompute, api_type, language_version, "cs", source_code);
|
||||
}
|
||||
} // namespace SPIRV
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright 2022 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "ShaderLang.h"
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
||||
namespace SPIRV
|
||||
{
|
||||
// SPIR-V compiled code type
|
||||
using CodeType = u32;
|
||||
using CodeVector = std::vector<CodeType>;
|
||||
|
||||
// Compile a vertex shader to SPIR-V.
|
||||
std::optional<CodeVector> CompileVertexShader(std::string_view source_code, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version);
|
||||
|
||||
// Compile a geometry shader to SPIR-V.
|
||||
std::optional<CodeVector> CompileGeometryShader(std::string_view source_code, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version);
|
||||
|
||||
// Compile a fragment shader to SPIR-V.
|
||||
std::optional<CodeVector> CompileFragmentShader(std::string_view source_code, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version);
|
||||
|
||||
// Compile a compute shader to SPIR-V.
|
||||
std::optional<CodeVector> CompileComputeShader(std::string_view source_code, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version);
|
||||
} // namespace SPIRV
|
|
@ -56,48 +56,27 @@ u16 GetEncodedSampleCount(EFBCopyFormat format)
|
|||
|
||||
static void WriteHeader(ShaderCode& code, APIType api_type)
|
||||
{
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
// left, top, of source rectangle within source texture
|
||||
// width of the destination rectangle, scale_factor (1 or 2)
|
||||
code.Write("UBO_BINDING(std140, 1) uniform PSBlock {{\n"
|
||||
" int4 position;\n"
|
||||
" float y_scale;\n"
|
||||
" float gamma_rcp;\n"
|
||||
" float2 clamp_tb;\n"
|
||||
" float3 filter_coefficients;\n"
|
||||
"}};\n");
|
||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
// left, top, of source rectangle within source texture
|
||||
// width of the destination rectangle, scale_factor (1 or 2)
|
||||
code.Write("UBO_BINDING(std140, 1) uniform PSBlock {{\n"
|
||||
" int4 position;\n"
|
||||
" float y_scale;\n"
|
||||
" float gamma_rcp;\n"
|
||||
" float2 clamp_tb;\n"
|
||||
" float3 filter_coefficients;\n"
|
||||
code.Write("VARYING_LOCATION(0) in VertexData {{\n"
|
||||
" float3 v_tex0;\n"
|
||||
"}};\n");
|
||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
code.Write("VARYING_LOCATION(0) in VertexData {{\n"
|
||||
" float3 v_tex0;\n"
|
||||
"}};\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
code.Write("VARYING_LOCATION(0) in float3 v_tex0;\n");
|
||||
}
|
||||
code.Write("SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n"
|
||||
"FRAGMENT_OUTPUT_LOCATION(0) out float4 ocol0;\n");
|
||||
}
|
||||
else // D3D
|
||||
else
|
||||
{
|
||||
code.Write("cbuffer PSBlock : register(b0) {{\n"
|
||||
" int4 position;\n"
|
||||
" float y_scale;\n"
|
||||
" float gamma_rcp;\n"
|
||||
" float2 clamp_tb;\n"
|
||||
" float3 filter_coefficients;\n"
|
||||
"}};\n"
|
||||
"sampler samp0 : register(s0);\n"
|
||||
"Texture2DArray Tex0 : register(t0);\n");
|
||||
code.Write("VARYING_LOCATION(0) in float3 v_tex0;\n");
|
||||
}
|
||||
|
||||
// D3D does not have roundEven(), only round(), which is specified "to the nearest integer".
|
||||
// This differs from the roundEven() behavior, but to get consistency across drivers in OpenGL
|
||||
// we need to use roundEven().
|
||||
if (api_type == APIType::D3D)
|
||||
code.Write("#define roundEven(x) round(x)\n");
|
||||
code.Write("SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n"
|
||||
"FRAGMENT_OUTPUT_LOCATION(0) out float4 ocol0;\n");
|
||||
|
||||
// Alpha channel in the copy is set to 1 the EFB format does not have an alpha channel.
|
||||
code.Write("float4 RGBA8ToRGB8(float4 src)\n"
|
||||
|
@ -149,10 +128,7 @@ static void WriteSampleFunction(ShaderCode& code, const EFBCopyParams& params, A
|
|||
code.Write("(");
|
||||
}
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
code.Write("texture(samp0, float3(");
|
||||
else
|
||||
code.Write("Tex0.Sample(samp0, float3(");
|
||||
code.Write("texture(samp0, float3(");
|
||||
|
||||
code.Write("uv.x + float(xoffset) * pixel_size.x, ");
|
||||
|
||||
|
@ -211,23 +187,10 @@ static void WriteSwizzler(ShaderCode& code, const EFBCopyParams& params, EFBCopy
|
|||
WriteHeader(code, api_type);
|
||||
WriteSampleFunction(code, params, api_type);
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
{
|
||||
code.Write("void main()\n"
|
||||
"{{\n"
|
||||
" int2 sampleUv;\n"
|
||||
" int2 uv1 = int2(gl_FragCoord.xy);\n");
|
||||
}
|
||||
else // D3D
|
||||
{
|
||||
code.Write("void main(\n"
|
||||
" in float3 v_tex0 : TEXCOORD0,\n"
|
||||
" in float4 rawpos : SV_Position,\n"
|
||||
" out float4 ocol0 : SV_Target)\n"
|
||||
"{{\n"
|
||||
" int2 sampleUv;\n"
|
||||
" int2 uv1 = int2(rawpos.xy);\n");
|
||||
}
|
||||
code.Write("void main()\n"
|
||||
"{{\n"
|
||||
" int2 sampleUv;\n"
|
||||
" int2 uv1 = int2(gl_FragCoord.xy);\n");
|
||||
|
||||
const int blkW = TexDecoder_GetEFBCopyBlockWidthInTexels(format);
|
||||
const int blkH = TexDecoder_GetEFBCopyBlockHeightInTexels(format);
|
||||
|
@ -853,11 +816,7 @@ static const char decoding_shader_header[] = R"(
|
|||
#define HAS_PALETTE 1
|
||||
#endif
|
||||
|
||||
#ifdef API_D3D
|
||||
cbuffer UBO : register(b0) {
|
||||
#else
|
||||
UBO_BINDING(std140, 1) uniform UBO {
|
||||
#endif
|
||||
uint2 u_dst_size;
|
||||
uint2 u_src_size;
|
||||
uint u_src_offset;
|
||||
|
@ -865,37 +824,6 @@ UBO_BINDING(std140, 1) uniform UBO {
|
|||
uint u_palette_offset;
|
||||
};
|
||||
|
||||
#ifdef API_D3D
|
||||
|
||||
Buffer<uint4> s_input_buffer : register(t0);
|
||||
#ifdef HAS_PALETTE
|
||||
Buffer<uint4> s_palette_buffer : register(t1);
|
||||
#endif
|
||||
|
||||
RWTexture2DArray<unorm float4> output_image : register(u0);
|
||||
|
||||
// Helpers for reading/writing.
|
||||
#define texelFetch(buffer, pos) buffer.Load(pos)
|
||||
#define imageStore(image, coords, value) image[coords] = value
|
||||
#define GROUP_MEMORY_BARRIER_WITH_SYNC GroupMemoryBarrierWithGroupSync();
|
||||
#define GROUP_SHARED groupshared
|
||||
|
||||
#define DEFINE_MAIN(lx, ly) \
|
||||
[numthreads(lx, ly, 1)] \
|
||||
void main(uint3 gl_WorkGroupID : SV_GroupId, \
|
||||
uint3 gl_LocalInvocationID : SV_GroupThreadID, \
|
||||
uint3 gl_GlobalInvocationID : SV_DispatchThreadID)
|
||||
|
||||
uint bitfieldExtract(uint val, int off, int size)
|
||||
{
|
||||
// This built-in function is only support in OpenGL 4.0+ and ES 3.1+\n"
|
||||
// Microsoft's HLSL compiler automatically optimises this to a bitfield extract instruction.
|
||||
uint mask = uint((1 << size) - 1);
|
||||
return uint(val >> off) & mask;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
TEXEL_BUFFER_BINDING(0) uniform usamplerBuffer s_input_buffer;
|
||||
#ifdef HAS_PALETTE
|
||||
TEXEL_BUFFER_BINDING(1) uniform usamplerBuffer s_palette_buffer;
|
||||
|
@ -909,8 +837,6 @@ IMAGE_BINDING(rgba8, 0) uniform writeonly image2DArray output_image;
|
|||
layout(local_size_x = lx, local_size_y = ly) in; \
|
||||
void main()
|
||||
|
||||
#endif
|
||||
|
||||
uint Swap16(uint v)
|
||||
{
|
||||
// Convert BE to LE.
|
||||
|
@ -1498,48 +1424,29 @@ float4 DecodePixel(int val)
|
|||
|
||||
ss << "\n";
|
||||
|
||||
if (api_type == APIType::D3D)
|
||||
{
|
||||
ss << "Buffer<uint> tex0 : register(t0);\n";
|
||||
ss << "Texture2DArray tex1 : register(t1);\n";
|
||||
ss << "SamplerState samp1 : register(s1);\n";
|
||||
ss << "cbuffer PSBlock : register(b0) {\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << "TEXEL_BUFFER_BINDING(0) uniform usamplerBuffer samp0;\n";
|
||||
ss << "SAMPLER_BINDING(1) uniform sampler2DArray samp1;\n";
|
||||
ss << "UBO_BINDING(std140, 1) uniform PSBlock {\n";
|
||||
}
|
||||
ss << "TEXEL_BUFFER_BINDING(0) uniform usamplerBuffer samp0;\n";
|
||||
ss << "SAMPLER_BINDING(1) uniform sampler2DArray samp1;\n";
|
||||
ss << "UBO_BINDING(std140, 1) uniform PSBlock {\n";
|
||||
|
||||
ss << " float multiplier;\n";
|
||||
ss << " int texel_buffer_offset;\n";
|
||||
ss << "};\n";
|
||||
|
||||
if (api_type == APIType::D3D)
|
||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
ss << "void main(in float3 v_tex0 : TEXCOORD0, out float4 ocol0 : SV_Target) {\n";
|
||||
ss << " int src = int(round(tex1.Sample(samp1, v_tex0).r * multiplier));\n";
|
||||
ss << " src = int(tex0.Load(src + texel_buffer_offset).r);\n";
|
||||
ss << "VARYING_LOCATION(0) in VertexData {\n";
|
||||
ss << " float3 v_tex0;\n";
|
||||
ss << "};\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
ss << "VARYING_LOCATION(0) in VertexData {\n";
|
||||
ss << " float3 v_tex0;\n";
|
||||
ss << "};\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << "VARYING_LOCATION(0) in float3 v_tex0;\n";
|
||||
}
|
||||
ss << "FRAGMENT_OUTPUT_LOCATION(0) out float4 ocol0;\n";
|
||||
ss << "void main() {\n";
|
||||
ss << " float3 coords = v_tex0;\n";
|
||||
ss << " int src = int(round(texture(samp1, coords).r * multiplier));\n";
|
||||
ss << " src = int(texelFetch(samp0, src + texel_buffer_offset).r);\n";
|
||||
ss << "VARYING_LOCATION(0) in float3 v_tex0;\n";
|
||||
}
|
||||
ss << "FRAGMENT_OUTPUT_LOCATION(0) out float4 ocol0;\n";
|
||||
ss << "void main() {\n";
|
||||
ss << " float3 coords = v_tex0;\n";
|
||||
ss << " int src = int(round(texture(samp1, coords).r * multiplier));\n";
|
||||
ss << " src = int(texelFetch(samp0, src + texel_buffer_offset).r);\n";
|
||||
|
||||
ss << " src = ((src << 8) & 0xFF00) | (src >> 8);\n";
|
||||
ss << " ocol0 = DecodePixel(src);\n";
|
||||
|
|
|
@ -29,26 +29,13 @@ TCShaderUid GetShaderUid(EFBCopyFormat dst_format, bool is_depth_copy, bool is_i
|
|||
|
||||
static void WriteHeader(APIType api_type, ShaderCode& out)
|
||||
{
|
||||
if (api_type == APIType::D3D)
|
||||
{
|
||||
out.Write("cbuffer PSBlock : register(b0) {{\n"
|
||||
" float2 src_offset, src_size;\n"
|
||||
" float3 filter_coefficients;\n"
|
||||
" float gamma_rcp;\n"
|
||||
" float2 clamp_tb;\n"
|
||||
" float pixel_height;\n"
|
||||
"}};\n\n");
|
||||
}
|
||||
else if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
{
|
||||
out.Write("UBO_BINDING(std140, 1) uniform PSBlock {{\n"
|
||||
" float2 src_offset, src_size;\n"
|
||||
" float3 filter_coefficients;\n"
|
||||
" float gamma_rcp;\n"
|
||||
" float2 clamp_tb;\n"
|
||||
" float pixel_height;\n"
|
||||
"}};\n");
|
||||
}
|
||||
out.Write("UBO_BINDING(std140, 1) uniform PSBlock {{\n"
|
||||
" float2 src_offset, src_size;\n"
|
||||
" float3 filter_coefficients;\n"
|
||||
" float gamma_rcp;\n"
|
||||
" float2 clamp_tb;\n"
|
||||
" float pixel_height;\n"
|
||||
"}};\n");
|
||||
}
|
||||
|
||||
ShaderCode GenerateVertexShader(APIType api_type)
|
||||
|
@ -56,27 +43,19 @@ ShaderCode GenerateVertexShader(APIType api_type)
|
|||
ShaderCode out;
|
||||
WriteHeader(api_type, out);
|
||||
|
||||
if (api_type == APIType::D3D)
|
||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
out.Write("void main(in uint id : SV_VertexID, out float3 v_tex0 : TEXCOORD0,\n"
|
||||
" out float4 opos : SV_Position) {{\n");
|
||||
out.Write("VARYING_LOCATION(0) out VertexData {{\n"
|
||||
" float3 v_tex0;\n"
|
||||
"}};\n");
|
||||
}
|
||||
else if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
else
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
out.Write("VARYING_LOCATION(0) out VertexData {{\n"
|
||||
" float3 v_tex0;\n"
|
||||
"}};\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write("VARYING_LOCATION(0) out float3 v_tex0;\n");
|
||||
}
|
||||
out.Write("#define id gl_VertexID\n"
|
||||
"#define opos gl_Position\n"
|
||||
"void main() {{\n");
|
||||
out.Write("VARYING_LOCATION(0) out float3 v_tex0;\n");
|
||||
}
|
||||
out.Write("#define id gl_VertexID\n"
|
||||
"#define opos gl_Position\n"
|
||||
"void main() {{\n");
|
||||
out.Write(" v_tex0 = float3(float((id << 1) & 2), float(id & 2), 0.0f);\n");
|
||||
out.Write(
|
||||
" opos = float4(v_tex0.xy * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n");
|
||||
|
@ -98,38 +77,24 @@ ShaderCode GeneratePixelShader(APIType api_type, const UidData* uid_data)
|
|||
ShaderCode out;
|
||||
WriteHeader(api_type, out);
|
||||
|
||||
if (api_type == APIType::D3D)
|
||||
out.Write("SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n");
|
||||
out.Write("float4 SampleEFB(float3 uv, float y_offset) {{\n"
|
||||
" return texture(samp0, float3(uv.x, clamp(uv.y + (y_offset * pixel_height), "
|
||||
"clamp_tb.x, clamp_tb.y), {}));\n"
|
||||
"}}\n",
|
||||
mono_depth ? "0.0" : "uv.z");
|
||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
out.Write("Texture2DArray tex0 : register(t0);\n"
|
||||
"SamplerState samp0 : register(s0);\n"
|
||||
"float4 SampleEFB(float3 uv, float y_offset) {{\n"
|
||||
" return tex0.Sample(samp0, float3(uv.x, clamp(uv.y + (y_offset * pixel_height), "
|
||||
"clamp_tb.x, clamp_tb.y), {}));\n"
|
||||
"}}\n\n",
|
||||
mono_depth ? "0.0" : "uv.z");
|
||||
out.Write("void main(in float3 v_tex0 : TEXCOORD0, out float4 ocol0 : SV_Target)\n{{\n");
|
||||
out.Write("VARYING_LOCATION(0) in VertexData {{\n"
|
||||
" float3 v_tex0;\n"
|
||||
"}};\n");
|
||||
}
|
||||
else if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
else
|
||||
{
|
||||
out.Write("SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n");
|
||||
out.Write("float4 SampleEFB(float3 uv, float y_offset) {{\n"
|
||||
" return texture(samp0, float3(uv.x, clamp(uv.y + (y_offset * pixel_height), "
|
||||
"clamp_tb.x, clamp_tb.y), {}));\n"
|
||||
"}}\n",
|
||||
mono_depth ? "0.0" : "uv.z");
|
||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
out.Write("VARYING_LOCATION(0) in VertexData {{\n"
|
||||
" float3 v_tex0;\n"
|
||||
"}};\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write("VARYING_LOCATION(0) in vec3 v_tex0;\n");
|
||||
}
|
||||
out.Write("FRAGMENT_OUTPUT_LOCATION(0) out vec4 ocol0;\n"
|
||||
"void main()\n{{\n");
|
||||
out.Write("VARYING_LOCATION(0) in vec3 v_tex0;\n");
|
||||
}
|
||||
out.Write("FRAGMENT_OUTPUT_LOCATION(0) out vec4 ocol0;\n"
|
||||
"void main()\n{{\n");
|
||||
|
||||
// The copy filter applies to both color and depth copies. This has been verified on hardware.
|
||||
// The filter is only applied to the RGB channels, the alpha channel is left intact.
|
||||
|
|
|
@ -77,8 +77,7 @@ void WriteVertexLighting(ShaderCode& out, APIType api_type, std::string_view wor
|
|||
std::string_view out_color_1_var)
|
||||
{
|
||||
out.Write("// Lighting\n");
|
||||
out.Write("{}for (uint chan = 0u; chan < {}u; chan++) {{\n",
|
||||
api_type == APIType::D3D ? "[loop] " : "", NUM_XF_COLOR_CHANNELS);
|
||||
out.Write("for (uint chan = 0u; chan < {}u; chan++) {{\n", NUM_XF_COLOR_CHANNELS);
|
||||
out.Write(" uint colorreg = xfmem_color(chan);\n"
|
||||
" uint alphareg = xfmem_alpha(chan);\n"
|
||||
" int4 mat = " I_MATERIALS "[chan + 2u]; \n"
|
||||
|
|
|
@ -72,93 +72,88 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
|||
if (per_pixel_lighting)
|
||||
WriteLightingFunction(out);
|
||||
|
||||
// Shader inputs/outputs in GLSL (HLSL is in main).
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
// Framebuffer fetch is only supported by Metal, so ensure that we're running Vulkan (MoltenVK)
|
||||
// if we want to use it.
|
||||
if (api_type == APIType::Vulkan)
|
||||
// Framebuffer fetch is only supported by Metal, so ensure that we're running Vulkan (MoltenVK)
|
||||
// if we want to use it.
|
||||
if (api_type == APIType::Vulkan)
|
||||
{
|
||||
if (use_dual_source)
|
||||
{
|
||||
if (use_dual_source)
|
||||
{
|
||||
out.Write("FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0) out vec4 {};\n"
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1) out vec4 ocol1;\n",
|
||||
use_framebuffer_fetch ? "real_ocol0" : "ocol0");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Metal doesn't support a single unified variable for both input and output,
|
||||
// so when using framebuffer fetch, we declare the input separately below.
|
||||
out.Write("FRAGMENT_OUTPUT_LOCATION(0) out vec4 {};\n",
|
||||
use_framebuffer_fetch ? "real_ocol0" : "ocol0");
|
||||
}
|
||||
|
||||
if (use_framebuffer_fetch)
|
||||
{
|
||||
// Subpass inputs will be converted to framebuffer fetch by SPIRV-Cross.
|
||||
out.Write("INPUT_ATTACHMENT_BINDING(0, 0, 0) uniform subpassInput in_ocol0;\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
bool has_broken_decoration =
|
||||
DriverDetails::HasBug(DriverDetails::BUG_BROKEN_FRAGMENT_SHADER_INDEX_DECORATION);
|
||||
|
||||
out.Write("{} {} vec4 {};\n",
|
||||
has_broken_decoration ? "FRAGMENT_OUTPUT_LOCATION(0)" :
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0)",
|
||||
use_framebuffer_fetch ? "FRAGMENT_INOUT" : "out",
|
||||
out.Write("FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0) out vec4 {};\n"
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1) out vec4 ocol1;\n",
|
||||
use_framebuffer_fetch ? "real_ocol0" : "ocol0");
|
||||
|
||||
if (use_dual_source)
|
||||
{
|
||||
out.Write("{} out vec4 ocol1;\n", has_broken_decoration ?
|
||||
"FRAGMENT_OUTPUT_LOCATION(1)" :
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1)");
|
||||
}
|
||||
}
|
||||
|
||||
if (per_pixel_depth)
|
||||
out.Write("#define depth gl_FragDepth\n");
|
||||
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
out.Write("VARYING_LOCATION(0) in VertexData {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, numTexgen, host_config,
|
||||
GetInterpolationQualifier(msaa, ssaa, true, true));
|
||||
|
||||
if (stereo)
|
||||
out.Write(" flat int layer;\n");
|
||||
|
||||
out.Write("}};\n\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let's set up attributes
|
||||
u32 counter = 0;
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 colors_0;\n", counter++,
|
||||
// Metal doesn't support a single unified variable for both input and output,
|
||||
// so when using framebuffer fetch, we declare the input separately below.
|
||||
out.Write("FRAGMENT_OUTPUT_LOCATION(0) out vec4 {};\n",
|
||||
use_framebuffer_fetch ? "real_ocol0" : "ocol0");
|
||||
}
|
||||
|
||||
if (use_framebuffer_fetch)
|
||||
{
|
||||
// Subpass inputs will be converted to framebuffer fetch by SPIRV-Cross.
|
||||
out.Write("INPUT_ATTACHMENT_BINDING(0, 0, 0) uniform subpassInput in_ocol0;\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
bool has_broken_decoration =
|
||||
DriverDetails::HasBug(DriverDetails::BUG_BROKEN_FRAGMENT_SHADER_INDEX_DECORATION);
|
||||
|
||||
out.Write("{} {} {} {};\n",
|
||||
has_broken_decoration ? "FRAGMENT_OUTPUT_LOCATION(0)" :
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0)",
|
||||
use_framebuffer_fetch ? "FRAGMENT_INOUT" : "out",
|
||||
uid_data->uint_output ? "uvec4" : "vec4",
|
||||
use_framebuffer_fetch ? "real_ocol0" : "ocol0");
|
||||
|
||||
if (use_dual_source)
|
||||
{
|
||||
out.Write("{} out {} ocol1;\n",
|
||||
has_broken_decoration ? "FRAGMENT_OUTPUT_LOCATION(1)" :
|
||||
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1)",
|
||||
uid_data->uint_output ? "uvec4" : "vec4");
|
||||
}
|
||||
}
|
||||
|
||||
if (per_pixel_depth)
|
||||
out.Write("#define depth gl_FragDepth\n");
|
||||
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
out.Write("VARYING_LOCATION(0) in VertexData {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, numTexgen, host_config,
|
||||
GetInterpolationQualifier(msaa, ssaa, true, true), ShaderStage::Pixel);
|
||||
|
||||
out.Write("}};\n\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let's set up attributes
|
||||
u32 counter = 0;
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 colors_0;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 colors_1;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
for (u32 i = 0; i < numTexgen; ++i)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 tex{};\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa), i);
|
||||
}
|
||||
if (!host_config.fast_depth_calc)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 clipPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 colors_1;\n", counter++,
|
||||
}
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 Normal;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 WorldPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
for (u32 i = 0; i < numTexgen; ++i)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 tex{};\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa), i);
|
||||
}
|
||||
if (!host_config.fast_depth_calc)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} in float4 clipPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
}
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 Normal;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} in float3 WorldPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,10 +238,7 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
|||
// Doesn't look like DirectX supports this. Oh well the code path is here just in case it
|
||||
// supports this in the future.
|
||||
out.Write("int4 sampleTextureWrapper(uint texmap, int2 uv, int layer) {{\n");
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
out.Write(" return sampleTexture(texmap, samp[texmap], uv, layer);\n");
|
||||
else if (api_type == APIType::D3D)
|
||||
out.Write(" return sampleTexture(texmap, tex[texmap], samp[texmap], uv, layer);\n");
|
||||
out.Write(" return sampleTexture(texmap, samp[texmap], uv, layer);\n");
|
||||
out.Write("}}\n\n");
|
||||
}
|
||||
else
|
||||
|
@ -259,15 +251,7 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
|||
" switch(sampler_num) {{\n");
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
{
|
||||
out.Write(" case {0}u: return sampleTexture({0}u, samp[{0}u], uv, layer);\n", i);
|
||||
}
|
||||
else if (api_type == APIType::D3D)
|
||||
{
|
||||
out.Write(" case {0}u: return sampleTexture({0}u, tex[{0}u], samp[{0}u], uv, layer);\n",
|
||||
i);
|
||||
}
|
||||
out.Write(" case {0}u: return sampleTexture({0}u, samp[{0}u], uv, layer);\n", i);
|
||||
}
|
||||
out.Write(" }}\n"
|
||||
"}}\n\n");
|
||||
|
@ -522,85 +506,44 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
|||
out.Write(")\n\n");
|
||||
}
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
if (early_depth && host_config.backend_early_z)
|
||||
out.Write("FORCE_EARLY_Z;\n");
|
||||
|
||||
out.Write("void main()\n{{\n");
|
||||
out.Write(" float4 rawpos = gl_FragCoord;\n");
|
||||
|
||||
if (use_framebuffer_fetch)
|
||||
{
|
||||
if (early_depth && host_config.backend_early_z)
|
||||
out.Write("FORCE_EARLY_Z;\n");
|
||||
// Store off a copy of the initial framebuffer value.
|
||||
//
|
||||
// If FB_FETCH_VALUE isn't defined (i.e. no special keyword for fetching from the
|
||||
// framebuffer), we read from real_ocol0.
|
||||
out.Write("#ifdef FB_FETCH_VALUE\n"
|
||||
" float4 initial_ocol0 = FB_FETCH_VALUE;\n"
|
||||
"#else\n"
|
||||
" float4 initial_ocol0 = real_ocol0;\n"
|
||||
"#endif\n");
|
||||
|
||||
out.Write("void main()\n{{\n");
|
||||
out.Write(" float4 rawpos = gl_FragCoord;\n");
|
||||
|
||||
if (use_framebuffer_fetch)
|
||||
{
|
||||
// Store off a copy of the initial framebuffer value.
|
||||
//
|
||||
// If FB_FETCH_VALUE isn't defined (i.e. no special keyword for fetching from the
|
||||
// framebuffer), we read from real_ocol0.
|
||||
out.Write("#ifdef FB_FETCH_VALUE\n"
|
||||
" float4 initial_ocol0 = FB_FETCH_VALUE;\n"
|
||||
"#else\n"
|
||||
" float4 initial_ocol0 = real_ocol0;\n"
|
||||
"#endif\n");
|
||||
|
||||
// QComm's Adreno driver doesn't seem to like using the framebuffer_fetch value as an
|
||||
// intermediate value with multiple reads & modifications, so we pull out the "real" output
|
||||
// value above and use a temporary for calculations, then set the output value once at the
|
||||
// end of the shader.
|
||||
out.Write(" float4 ocol0;\n");
|
||||
}
|
||||
|
||||
if (use_shader_blend)
|
||||
{
|
||||
out.Write(" float4 ocol1;\n");
|
||||
}
|
||||
// QComm's Adreno driver doesn't seem to like using the framebuffer_fetch value as an
|
||||
// intermediate value with multiple reads & modifications, so we pull out the "real" output
|
||||
// value above and use a temporary for calculations, then set the output value once at the
|
||||
// end of the shader.
|
||||
out.Write(" float4 ocol0;\n");
|
||||
}
|
||||
else // D3D
|
||||
|
||||
if (use_shader_blend)
|
||||
{
|
||||
if (early_depth && host_config.backend_early_z)
|
||||
out.Write("[earlydepthstencil]\n");
|
||||
|
||||
out.Write("void main(\n");
|
||||
if (uid_data->uint_output)
|
||||
{
|
||||
out.Write(" out uint4 ocol0 : SV_Target,\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write(" out float4 ocol0 : SV_Target0,\n"
|
||||
" out float4 ocol1 : SV_Target1,\n");
|
||||
}
|
||||
if (per_pixel_depth)
|
||||
out.Write(" out float depth : SV_Depth,\n");
|
||||
out.Write(" in float4 rawpos : SV_Position,\n");
|
||||
out.Write(" in {} float4 colors_0 : COLOR0,\n", GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write(" in {} float4 colors_1 : COLOR1", GetInterpolationQualifier(msaa, ssaa));
|
||||
|
||||
// compute window position if needed because binding semantic WPOS is not widely supported
|
||||
for (u32 i = 0; i < numTexgen; ++i)
|
||||
{
|
||||
out.Write(",\n in {} float3 tex{} : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa), i,
|
||||
i);
|
||||
}
|
||||
if (!host_config.fast_depth_calc)
|
||||
{
|
||||
out.Write("\n,\n in {} float4 clipPos : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa),
|
||||
numTexgen);
|
||||
}
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write(",\n in {} float3 Normal : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa),
|
||||
numTexgen + 1);
|
||||
out.Write(",\n in {} float3 WorldPos : TEXCOORD{}", GetInterpolationQualifier(msaa, ssaa),
|
||||
numTexgen + 2);
|
||||
}
|
||||
out.Write(",\n in float clipDist0 : SV_ClipDistance0\n"
|
||||
",\n in float clipDist1 : SV_ClipDistance1\n");
|
||||
if (stereo)
|
||||
out.Write(",\n in uint layer : SV_RenderTargetArrayIndex\n");
|
||||
out.Write("\n ) {{\n");
|
||||
out.Write(" float4 ocol1;\n");
|
||||
}
|
||||
|
||||
if (host_config.backend_geometry_shaders && stereo)
|
||||
{
|
||||
out.Write("\tint layer = gl_Layer;\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write("\tint layer = 0;\n");
|
||||
}
|
||||
if (!stereo)
|
||||
out.Write(" int layer = 0;\n");
|
||||
|
||||
out.Write(" int3 tevcoord = int3(0, 0, 0);\n"
|
||||
" State s;\n"
|
||||
|
@ -634,11 +577,6 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
|||
BitfieldExtract<&GenMode::numtevstages>("bpmem_genmode"));
|
||||
|
||||
out.Write(" // Main tev loop\n");
|
||||
if (api_type == APIType::D3D)
|
||||
{
|
||||
// Tell DirectX we don't want this loop unrolled (it crashes if it tries to)
|
||||
out.Write(" [loop]\n");
|
||||
}
|
||||
|
||||
out.Write(" for(uint stage = 0u; stage <= num_stages; stage++)\n"
|
||||
" {{\n"
|
||||
|
|
|
@ -38,85 +38,65 @@ ShaderCode GenVertexShader(APIType api_type, const ShaderHostConfig& host_config
|
|||
out.Write("{}", s_lighting_struct);
|
||||
|
||||
// uniforms
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
out.Write("UBO_BINDING(std140, 2) uniform VSBlock {{\n");
|
||||
else
|
||||
out.Write("cbuffer VSBlock {{\n");
|
||||
out.Write("UBO_BINDING(std140, 2) uniform VSBlock {{\n");
|
||||
out.Write("{}", s_shader_uniforms);
|
||||
out.Write("}};\n");
|
||||
|
||||
out.Write("struct VS_OUTPUT {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, num_texgen, host_config, "");
|
||||
GenerateVSOutputMembers(out, api_type, num_texgen, host_config, "", ShaderStage::Vertex);
|
||||
out.Write("}};\n\n");
|
||||
|
||||
WriteIsNanHeader(out, api_type);
|
||||
WriteBitfieldExtractHeader(out, api_type, host_config);
|
||||
WriteLightingFunction(out);
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float4 rawpos;\n", SHADER_POSITION_ATTRIB);
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in uint4 posmtx;\n", SHADER_POSMTX_ATTRIB);
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float3 rawnormal;\n", SHADER_NORMAL_ATTRIB);
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float3 rawtangent;\n", SHADER_TANGENT_ATTRIB);
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float3 rawbinormal;\n", SHADER_BINORMAL_ATTRIB);
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float4 rawcolor0;\n", SHADER_COLOR0_ATTRIB);
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float4 rawcolor1;\n", SHADER_COLOR1_ATTRIB);
|
||||
for (int i = 0; i < 8; ++i)
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float3 rawtex{};\n", SHADER_TEXTURE0_ATTRIB + i, i);
|
||||
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float4 rawpos;\n", SHADER_POSITION_ATTRIB);
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in uint4 posmtx;\n", SHADER_POSMTX_ATTRIB);
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float3 rawnormal;\n", SHADER_NORMAL_ATTRIB);
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float3 rawtangent;\n", SHADER_TANGENT_ATTRIB);
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float3 rawbinormal;\n", SHADER_BINORMAL_ATTRIB);
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float4 rawcolor0;\n", SHADER_COLOR0_ATTRIB);
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float4 rawcolor1;\n", SHADER_COLOR1_ATTRIB);
|
||||
for (int i = 0; i < 8; ++i)
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float3 rawtex{};\n", SHADER_TEXTURE0_ATTRIB + i, i);
|
||||
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
out.Write("VARYING_LOCATION(0) out VertexData {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, num_texgen, host_config,
|
||||
GetInterpolationQualifier(msaa, ssaa, true, false));
|
||||
out.Write("}} vs;\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let's set up attributes
|
||||
u32 counter = 0;
|
||||
out.Write("VARYING_LOCATION({}) {} out float4 colors_0;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} out float4 colors_1;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
for (u32 i = 0; i < num_texgen; ++i)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} out float3 tex{};\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa), i);
|
||||
}
|
||||
if (!host_config.fast_depth_calc)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} out float4 clipPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
}
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} out float3 Normal;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} out float3 WorldPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
}
|
||||
}
|
||||
|
||||
out.Write("void main()\n{{\n");
|
||||
out.Write("VARYING_LOCATION(0) out VertexData {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, num_texgen, host_config,
|
||||
GetInterpolationQualifier(msaa, ssaa, true, false),
|
||||
ShaderStage::Vertex);
|
||||
out.Write("}} vs;\n");
|
||||
}
|
||||
else // D3D
|
||||
else
|
||||
{
|
||||
out.Write("VS_OUTPUT main(\n");
|
||||
|
||||
// inputs
|
||||
out.Write(" float3 rawnormal : NORMAL,\n"
|
||||
" float3 rawtangent : TANGENT,\n"
|
||||
" float3 rawbinormal : BINORMAL,\n"
|
||||
" float4 rawcolor0 : COLOR0,\n"
|
||||
" float4 rawcolor1 : COLOR1,\n");
|
||||
for (int i = 0; i < 8; ++i)
|
||||
out.Write(" float3 rawtex{} : TEXCOORD{},\n", i, i);
|
||||
out.Write(" uint posmtx : BLENDINDICES,\n");
|
||||
out.Write(" float4 rawpos : POSITION) {{\n");
|
||||
// Let's set up attributes
|
||||
u32 counter = 0;
|
||||
out.Write("VARYING_LOCATION({}) {} out float4 colors_0;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} out float4 colors_1;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
for (u32 i = 0; i < num_texgen; ++i)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} out float3 tex{};\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa), i);
|
||||
}
|
||||
if (!host_config.fast_depth_calc)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} out float4 clipPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
}
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} out float3 Normal;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} out float3 WorldPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
}
|
||||
}
|
||||
|
||||
out.Write("void main()\n{{\n");
|
||||
|
||||
out.Write("VS_OUTPUT o;\n"
|
||||
"\n");
|
||||
|
||||
|
@ -335,45 +315,38 @@ ShaderCode GenVertexShader(APIType api_type, const ShaderHostConfig& host_config
|
|||
"}}\n");
|
||||
}
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
AssignVSOutputMembers(out, "vs", "o", num_texgen, host_config);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Pass interface blocks between shader stages even if geometry shaders
|
||||
// are not supported, however that will require at least OpenGL 3.2 support.
|
||||
for (u32 i = 0; i < num_texgen; ++i)
|
||||
out.Write("tex{}.xyz = o.tex{};\n", i, i);
|
||||
if (!host_config.fast_depth_calc)
|
||||
out.Write("clipPos = o.clipPos;\n");
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write("Normal = o.Normal;\n"
|
||||
"WorldPos = o.WorldPos;\n");
|
||||
}
|
||||
out.Write("colors_0 = o.colors_0;\n"
|
||||
"colors_1 = o.colors_1;\n");
|
||||
}
|
||||
|
||||
if (host_config.backend_depth_clamp)
|
||||
{
|
||||
out.Write("gl_ClipDistance[0] = clipDist0;\n"
|
||||
"gl_ClipDistance[1] = clipDist1;\n");
|
||||
}
|
||||
|
||||
// Vulkan NDC space has Y pointing down (right-handed NDC space).
|
||||
if (api_type == APIType::Vulkan)
|
||||
out.Write("gl_Position = float4(o.pos.x, -o.pos.y, o.pos.z, o.pos.w);\n");
|
||||
else
|
||||
out.Write("gl_Position = o.pos;\n");
|
||||
AssignVSOutputMembers(out, "vs", "o", num_texgen, host_config);
|
||||
}
|
||||
else // D3D
|
||||
else
|
||||
{
|
||||
out.Write("return o;\n");
|
||||
// TODO: Pass interface blocks between shader stages even if geometry shaders
|
||||
// are not supported, however that will require at least OpenGL 3.2 support.
|
||||
for (u32 i = 0; i < num_texgen; ++i)
|
||||
out.Write("tex{}.xyz = o.tex{};\n", i, i);
|
||||
if (!host_config.fast_depth_calc)
|
||||
out.Write("clipPos = o.clipPos;\n");
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write("Normal = o.Normal;\n"
|
||||
"WorldPos = o.WorldPos;\n");
|
||||
}
|
||||
out.Write("colors_0 = o.colors_0;\n"
|
||||
"colors_1 = o.colors_1;\n");
|
||||
}
|
||||
|
||||
if (host_config.backend_depth_clamp)
|
||||
{
|
||||
out.Write("gl_ClipDistance[0] = clipDist0;\n"
|
||||
"gl_ClipDistance[1] = clipDist1;\n");
|
||||
}
|
||||
|
||||
// Vulkan NDC space has Y pointing down (right-handed NDC space).
|
||||
if (api_type == APIType::Vulkan)
|
||||
out.Write("gl_Position = float4(o.pos.x, -o.pos.y, o.pos.z, o.pos.w);\n");
|
||||
else
|
||||
out.Write("gl_Position = o.pos;\n");
|
||||
out.Write("}}\n");
|
||||
|
||||
return out;
|
||||
|
@ -393,8 +366,7 @@ static void GenVertexShaderTexGens(APIType api_type, u32 num_texgen, ShaderCode&
|
|||
}
|
||||
else
|
||||
{
|
||||
out.Write("{}for (uint texgen = 0u; texgen < {}u; texgen++) {{\n",
|
||||
api_type == APIType::D3D ? "[loop] " : "", num_texgen);
|
||||
out.Write("for (uint texgen = 0u; texgen < {}u; texgen++) {{\n", num_texgen);
|
||||
}
|
||||
|
||||
out.Write(" // Texcoord transforms\n");
|
||||
|
|
|
@ -86,110 +86,80 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
|
|||
out.Write("{}", s_lighting_struct);
|
||||
|
||||
// uniforms
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
out.Write("UBO_BINDING(std140, 2) uniform VSBlock {{\n");
|
||||
else
|
||||
out.Write("cbuffer VSBlock {{\n");
|
||||
out.Write("UBO_BINDING(std140, 2) uniform VSBlock {{\n");
|
||||
|
||||
out.Write("{}", s_shader_uniforms);
|
||||
out.Write("}};\n");
|
||||
|
||||
out.Write("struct VS_OUTPUT {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, host_config, "");
|
||||
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, host_config, "",
|
||||
ShaderStage::Vertex);
|
||||
out.Write("}};\n\n");
|
||||
|
||||
WriteIsNanHeader(out, api_type);
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float4 rawpos;\n", SHADER_POSITION_ATTRIB);
|
||||
if ((uid_data->components & VB_HAS_POSMTXIDX) != 0)
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in uint4 posmtx;\n", SHADER_POSMTX_ATTRIB);
|
||||
if ((uid_data->components & VB_HAS_NORMAL) != 0)
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float3 rawnormal;\n", SHADER_NORMAL_ATTRIB);
|
||||
if ((uid_data->components & VB_HAS_TANGENT) != 0)
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float3 rawtangent;\n", SHADER_TANGENT_ATTRIB);
|
||||
if ((uid_data->components & VB_HAS_BINORMAL) != 0)
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float3 rawbinormal;\n", SHADER_BINORMAL_ATTRIB);
|
||||
|
||||
if ((uid_data->components & VB_HAS_COL0) != 0)
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float4 rawcolor0;\n", SHADER_COLOR0_ATTRIB);
|
||||
if ((uid_data->components & VB_HAS_COL1) != 0)
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float4 rawcolor1;\n", SHADER_COLOR1_ATTRIB);
|
||||
|
||||
for (u32 i = 0; i < 8; ++i)
|
||||
{
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float4 rawpos;\n", SHADER_POSITION_ATTRIB);
|
||||
if ((uid_data->components & VB_HAS_POSMTXIDX) != 0)
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in uint4 posmtx;\n", SHADER_POSMTX_ATTRIB);
|
||||
if ((uid_data->components & VB_HAS_NORMAL) != 0)
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float3 rawnormal;\n", SHADER_NORMAL_ATTRIB);
|
||||
if ((uid_data->components & VB_HAS_TANGENT) != 0)
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float3 rawtangent;\n", SHADER_TANGENT_ATTRIB);
|
||||
if ((uid_data->components & VB_HAS_BINORMAL) != 0)
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float3 rawbinormal;\n", SHADER_BINORMAL_ATTRIB);
|
||||
const u32 has_texmtx = (uid_data->components & (VB_HAS_TEXMTXIDX0 << i));
|
||||
|
||||
if ((uid_data->components & VB_HAS_COL0) != 0)
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float4 rawcolor0;\n", SHADER_COLOR0_ATTRIB);
|
||||
if ((uid_data->components & VB_HAS_COL1) != 0)
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float4 rawcolor1;\n", SHADER_COLOR1_ATTRIB);
|
||||
|
||||
for (u32 i = 0; i < 8; ++i)
|
||||
if ((uid_data->components & (VB_HAS_UV0 << i)) != 0 || has_texmtx != 0)
|
||||
{
|
||||
const u32 has_texmtx = (uid_data->components & (VB_HAS_TEXMTXIDX0 << i));
|
||||
|
||||
if ((uid_data->components & (VB_HAS_UV0 << i)) != 0 || has_texmtx != 0)
|
||||
{
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float{} rawtex{};\n", SHADER_TEXTURE0_ATTRIB + i,
|
||||
has_texmtx != 0 ? 3 : 2, i);
|
||||
}
|
||||
out.Write("ATTRIBUTE_LOCATION({}) in float{} rawtex{};\n", SHADER_TEXTURE0_ATTRIB + i,
|
||||
has_texmtx != 0 ? 3 : 2, i);
|
||||
}
|
||||
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
out.Write("VARYING_LOCATION(0) out VertexData {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, host_config,
|
||||
GetInterpolationQualifier(msaa, ssaa, true, false));
|
||||
out.Write("}} vs;\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let's set up attributes
|
||||
u32 counter = 0;
|
||||
out.Write("VARYING_LOCATION({}) {} out float4 colors_0;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} out float4 colors_1;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
for (u32 i = 0; i < uid_data->numTexGens; ++i)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} out float3 tex{};\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa), i);
|
||||
}
|
||||
if (!host_config.fast_depth_calc)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} out float4 clipPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
}
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} out float3 Normal;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} out float3 WorldPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
}
|
||||
}
|
||||
|
||||
out.Write("void main()\n{{\n");
|
||||
}
|
||||
else // D3D
|
||||
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
out.Write("VS_OUTPUT main(\n");
|
||||
|
||||
// inputs
|
||||
if ((uid_data->components & VB_HAS_NORMAL) != 0)
|
||||
out.Write(" float3 rawnormal : NORMAL,\n");
|
||||
if ((uid_data->components & VB_HAS_TANGENT) != 0)
|
||||
out.Write(" float3 rawtangent : TANGENT,\n");
|
||||
if ((uid_data->components & VB_HAS_BINORMAL) != 0)
|
||||
out.Write(" float3 rawbinormal : BINORMAL,\n");
|
||||
if ((uid_data->components & VB_HAS_COL0) != 0)
|
||||
out.Write(" float4 rawcolor0 : COLOR0,\n");
|
||||
if ((uid_data->components & VB_HAS_COL1) != 0)
|
||||
out.Write(" float4 rawcolor1 : COLOR1,\n");
|
||||
for (u32 i = 0; i < 8; ++i)
|
||||
{
|
||||
const u32 has_texmtx = (uid_data->components & (VB_HAS_TEXMTXIDX0 << i));
|
||||
|
||||
if ((uid_data->components & (VB_HAS_UV0 << i)) != 0 || has_texmtx != 0)
|
||||
out.Write(" float{} rawtex{} : TEXCOORD{},\n", has_texmtx ? 3 : 2, i, i);
|
||||
}
|
||||
if ((uid_data->components & VB_HAS_POSMTXIDX) != 0)
|
||||
out.Write(" uint4 posmtx : BLENDINDICES,\n");
|
||||
out.Write(" float4 rawpos : POSITION) {{\n");
|
||||
out.Write("VARYING_LOCATION(0) out VertexData {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, host_config,
|
||||
GetInterpolationQualifier(msaa, ssaa, true, false),
|
||||
ShaderStage::Vertex);
|
||||
out.Write("}} vs;\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let's set up attributes
|
||||
u32 counter = 0;
|
||||
out.Write("VARYING_LOCATION({}) {} out float4 colors_0;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} out float4 colors_1;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
for (u32 i = 0; i < uid_data->numTexGens; ++i)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} out float3 tex{};\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa), i);
|
||||
}
|
||||
if (!host_config.fast_depth_calc)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} out float4 clipPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
}
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write("VARYING_LOCATION({}) {} out float3 Normal;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
out.Write("VARYING_LOCATION({}) {} out float3 WorldPos;\n", counter++,
|
||||
GetInterpolationQualifier(msaa, ssaa));
|
||||
}
|
||||
}
|
||||
|
||||
out.Write("void main()\n{{\n");
|
||||
|
||||
out.Write("VS_OUTPUT o;\n");
|
||||
|
||||
|
@ -548,45 +518,38 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
|
|||
"}}\n");
|
||||
}
|
||||
|
||||
if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
AssignVSOutputMembers(out, "vs", "o", uid_data->numTexGens, host_config);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Pass interface blocks between shader stages even if geometry shaders
|
||||
// are not supported, however that will require at least OpenGL 3.2 support.
|
||||
for (u32 i = 0; i < uid_data->numTexGens; ++i)
|
||||
out.Write("tex{}.xyz = o.tex{};\n", i, i);
|
||||
if (!host_config.fast_depth_calc)
|
||||
out.Write("clipPos = o.clipPos;\n");
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write("Normal = o.Normal;\n"
|
||||
"WorldPos = o.WorldPos;\n");
|
||||
}
|
||||
out.Write("colors_0 = o.colors_0;\n"
|
||||
"colors_1 = o.colors_1;\n");
|
||||
}
|
||||
|
||||
if (host_config.backend_depth_clamp)
|
||||
{
|
||||
out.Write("gl_ClipDistance[0] = clipDist0;\n"
|
||||
"gl_ClipDistance[1] = clipDist1;\n");
|
||||
}
|
||||
|
||||
// Vulkan NDC space has Y pointing down (right-handed NDC space).
|
||||
if (api_type == APIType::Vulkan)
|
||||
out.Write("gl_Position = float4(o.pos.x, -o.pos.y, o.pos.z, o.pos.w);\n");
|
||||
else
|
||||
out.Write("gl_Position = o.pos;\n");
|
||||
AssignVSOutputMembers(out, "vs", "o", uid_data->numTexGens, host_config);
|
||||
}
|
||||
else // D3D
|
||||
else
|
||||
{
|
||||
out.Write("return o;\n");
|
||||
// TODO: Pass interface blocks between shader stages even if geometry shaders
|
||||
// are not supported, however that will require at least OpenGL 3.2 support.
|
||||
for (u32 i = 0; i < uid_data->numTexGens; ++i)
|
||||
out.Write("tex{}.xyz = o.tex{};\n", i, i);
|
||||
if (!host_config.fast_depth_calc)
|
||||
out.Write("clipPos = o.clipPos;\n");
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write("Normal = o.Normal;\n"
|
||||
"WorldPos = o.WorldPos;\n");
|
||||
}
|
||||
out.Write("colors_0 = o.colors_0;\n"
|
||||
"colors_1 = o.colors_1;\n");
|
||||
}
|
||||
|
||||
if (host_config.backend_depth_clamp)
|
||||
{
|
||||
out.Write("gl_ClipDistance[0] = clipDist0;\n"
|
||||
"gl_ClipDistance[1] = clipDist1;\n");
|
||||
}
|
||||
|
||||
// Vulkan NDC space has Y pointing down (right-handed NDC space).
|
||||
if (api_type == APIType::Vulkan)
|
||||
out.Write("gl_Position = float4(o.pos.x, -o.pos.y, o.pos.z, o.pos.w);\n");
|
||||
else
|
||||
out.Write("gl_Position = o.pos;\n");
|
||||
out.Write("}}\n");
|
||||
|
||||
return out;
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
<AdditionalIncludeDirectories>$(ExternalsDir)fmt\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ExternalsDir)GL;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ExternalsDir)glslang;$(ExternalsDir)glslang\StandAlone;$(ExternalsDir)glslang\glslang\Public;$(ExternalsDir)glslang\SPIRV;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ExternalsDir)spirv_cross\SPIRV-Cross;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ExternalsDir)imgui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ExternalsDir)liblzma\api;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ExternalsDir)libpng;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
|
@ -89,6 +90,7 @@
|
|||
<PreprocessorDefinitions>HAS_VULKAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>HAS_LIBMGBA;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>AUTOUPDATE=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<!--
|
||||
Make sure we include a clean version of windows.h.
|
||||
-->
|
||||
|
|
|
@ -79,6 +79,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mgba", "..\Externals\mGBA\m
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "..\Externals\fmt\fmt.vcxproj", "{4BC5A148-0AB3-440F-A980-A29B4B999190}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spirv_cross", "..\Externals\spirv_cross\spirv_cross.vcxproj", "{3d780617-ec8c-4721-b9fd-dfc9bb658c7c}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
|
@ -379,6 +381,14 @@ Global
|
|||
{4BC5A148-0AB3-440F-A980-A29B4B999190}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{4BC5A148-0AB3-440F-A980-A29B4B999190}.Release|x64.ActiveCfg = Release|x64
|
||||
{4BC5A148-0AB3-440F-A980-A29B4B999190}.Release|x64.Build.0 = Release|x64
|
||||
{3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Debug|x64.Build.0 = Debug|x64
|
||||
{3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Release|x64.ActiveCfg = Release|x64
|
||||
{3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -411,6 +421,7 @@ Global
|
|||
{1BEA10F3-80CE-4BC4-9331-5769372CDF99} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
||||
{864C4C8E-296D-3DBC-AD83-F1D5CB6E8EC6} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
||||
{4BC5A148-0AB3-440F-A980-A29B4B999190} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
||||
{3D780617-EC8C-4721-B9FD-DFC9BB658C7C} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {64B0A343-3B94-4522-9C24-6937FE5EFB22}
|
||||
|
|
Loading…
Reference in New Issue