Merge pull request #10890 from tellowkrinkle/VertexLineExpand
VideoCommon: Add vertex shader point/line expansion
This commit is contained in:
commit
cdcbe51b2a
|
@ -84,6 +84,8 @@ const Info<int> GFX_SHADER_PRECOMPILER_THREADS{
|
|||
{System::GFX, "Settings", "ShaderPrecompilerThreads"}, -1};
|
||||
const Info<bool> GFX_SAVE_TEXTURE_CACHE_TO_STATE{
|
||||
{System::GFX, "Settings", "SaveTextureCacheToState"}, true};
|
||||
const Info<bool> GFX_PREFER_VS_FOR_LINE_POINT_EXPANSION{
|
||||
{System::GFX, "Settings", "PreferVSForLinePointExpansion"}, false};
|
||||
|
||||
const Info<bool> GFX_SW_DUMP_OBJECTS{{System::GFX, "Settings", "SWDumpObjects"}, false};
|
||||
const Info<bool> GFX_SW_DUMP_TEV_STAGES{{System::GFX, "Settings", "SWDumpTevStages"}, false};
|
||||
|
|
|
@ -73,6 +73,7 @@ extern const Info<ShaderCompilationMode> GFX_SHADER_COMPILATION_MODE;
|
|||
extern const Info<int> GFX_SHADER_COMPILER_THREADS;
|
||||
extern const Info<int> GFX_SHADER_PRECOMPILER_THREADS;
|
||||
extern const Info<bool> GFX_SAVE_TEXTURE_CACHE_TO_STATE;
|
||||
extern const Info<bool> GFX_PREFER_VS_FOR_LINE_POINT_EXPANSION;
|
||||
|
||||
extern const Info<bool> GFX_SW_DUMP_OBJECTS;
|
||||
extern const Info<bool> GFX_SW_DUMP_TEV_STAGES;
|
||||
|
|
|
@ -94,7 +94,7 @@ static size_t s_state_writes_in_queue;
|
|||
static std::condition_variable s_state_write_queue_is_empty;
|
||||
|
||||
// Don't forget to increase this after doing changes on the savestate system
|
||||
constexpr u32 STATE_VERSION = 154; // Last changed in PR 11177
|
||||
constexpr u32 STATE_VERSION = 155; // Last changed in PR 10890
|
||||
|
||||
// Maps savestate versions to Dolphin versions.
|
||||
// Versions after 42 don't need to be added to this list,
|
||||
|
|
|
@ -128,15 +128,18 @@ void AdvancedWidget::CreateWidgets()
|
|||
m_enable_prog_scan = new ToolTipCheckBox(tr("Enable Progressive Scan"));
|
||||
m_backend_multithreading =
|
||||
new GraphicsBool(tr("Backend Multithreading"), Config::GFX_BACKEND_MULTITHREADING);
|
||||
m_prefer_vs_for_point_line_expansion = new GraphicsBool(
|
||||
tr("Prefer VS for Point/Line Expansion"), Config::GFX_PREFER_VS_FOR_LINE_POINT_EXPANSION);
|
||||
|
||||
misc_layout->addWidget(m_enable_cropping, 0, 0);
|
||||
misc_layout->addWidget(m_enable_prog_scan, 0, 1);
|
||||
misc_layout->addWidget(m_backend_multithreading, 1, 0);
|
||||
misc_layout->addWidget(m_prefer_vs_for_point_line_expansion, 1, 1);
|
||||
#ifdef _WIN32
|
||||
m_borderless_fullscreen =
|
||||
new GraphicsBool(tr("Borderless Fullscreen"), Config::GFX_BORDERLESS_FULLSCREEN);
|
||||
|
||||
misc_layout->addWidget(m_borderless_fullscreen, 1, 1);
|
||||
misc_layout->addWidget(m_borderless_fullscreen, 2, 0);
|
||||
#endif
|
||||
|
||||
// Experimental.
|
||||
|
@ -198,6 +201,10 @@ void AdvancedWidget::SaveSettings()
|
|||
void AdvancedWidget::OnBackendChanged()
|
||||
{
|
||||
m_backend_multithreading->setEnabled(g_Config.backend_info.bSupportsMultithreading);
|
||||
m_prefer_vs_for_point_line_expansion->setEnabled(
|
||||
g_Config.backend_info.bSupportsGeometryShaders &&
|
||||
g_Config.backend_info.bSupportsVSLinePointExpand);
|
||||
AddDescriptions();
|
||||
}
|
||||
|
||||
void AdvancedWidget::OnEmulationStateChanged(bool running)
|
||||
|
@ -289,6 +296,11 @@ void AdvancedWidget::AddDescriptions()
|
|||
"this option may result in a performance improvement on systems with more than "
|
||||
"two CPU cores. Currently, this is limited to the Vulkan backend.<br><br>"
|
||||
"<dolphin_emphasis>If unsure, leave this checked.</dolphin_emphasis>");
|
||||
static const char TR_PREFER_VS_FOR_POINT_LINE_EXPANSION_DESCRIPTION[] =
|
||||
QT_TR_NOOP("On backends that support both using the geometry shader and the vertex shader "
|
||||
"for expanding points and lines, selects the vertex shader for the job. May "
|
||||
"affect performance."
|
||||
"<br><br>%1");
|
||||
static const char TR_DEFER_EFB_ACCESS_INVALIDATION_DESCRIPTION[] = QT_TR_NOOP(
|
||||
"Defers invalidation of the EFB access cache until a GPU synchronization command "
|
||||
"is executed. If disabled, the cache will be invalidated with every draw call. "
|
||||
|
@ -316,6 +328,9 @@ void AdvancedWidget::AddDescriptions()
|
|||
"unchecked.</dolphin_emphasis>");
|
||||
#endif
|
||||
|
||||
static const char IF_UNSURE_UNCHECKED[] =
|
||||
QT_TR_NOOP("<dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>");
|
||||
|
||||
m_enable_wireframe->SetDescription(tr(TR_WIREFRAME_DESCRIPTION));
|
||||
m_show_statistics->SetDescription(tr(TR_SHOW_STATS_DESCRIPTION));
|
||||
m_enable_format_overlay->SetDescription(tr(TR_TEXTURE_FORMAT_DESCRIPTION));
|
||||
|
@ -337,6 +352,17 @@ void AdvancedWidget::AddDescriptions()
|
|||
m_enable_cropping->SetDescription(tr(TR_CROPPING_DESCRIPTION));
|
||||
m_enable_prog_scan->SetDescription(tr(TR_PROGRESSIVE_SCAN_DESCRIPTION));
|
||||
m_backend_multithreading->SetDescription(tr(TR_BACKEND_MULTITHREADING_DESCRIPTION));
|
||||
QString vsexpand_extra;
|
||||
if (!g_Config.backend_info.bSupportsGeometryShaders)
|
||||
vsexpand_extra = tr("Forced on because %1 doesn't support geometry shaders.")
|
||||
.arg(tr(g_Config.backend_info.DisplayName.c_str()));
|
||||
else if (!g_Config.backend_info.bSupportsVSLinePointExpand)
|
||||
vsexpand_extra = tr("Forced off because %1 doesn't support VS expansion.")
|
||||
.arg(tr(g_Config.backend_info.DisplayName.c_str()));
|
||||
else
|
||||
vsexpand_extra = tr(IF_UNSURE_UNCHECKED);
|
||||
m_prefer_vs_for_point_line_expansion->SetDescription(
|
||||
tr(TR_PREFER_VS_FOR_POINT_LINE_EXPANSION_DESCRIPTION).arg(vsexpand_extra));
|
||||
#ifdef _WIN32
|
||||
m_borderless_fullscreen->SetDescription(tr(TR_BORDERLESS_FULLSCREEN_DESCRIPTION));
|
||||
#endif
|
||||
|
|
|
@ -59,6 +59,7 @@ private:
|
|||
GraphicsBool* m_enable_cropping;
|
||||
ToolTipCheckBox* m_enable_prog_scan;
|
||||
GraphicsBool* m_backend_multithreading;
|
||||
GraphicsBool* m_prefer_vs_for_point_line_expansion;
|
||||
GraphicsBool* m_borderless_fullscreen;
|
||||
|
||||
// Experimental
|
||||
|
|
|
@ -19,6 +19,14 @@
|
|||
|
||||
namespace DX12
|
||||
{
|
||||
static bool UsesDynamicVertexLoader(const AbstractPipeline* pipeline)
|
||||
{
|
||||
const AbstractPipelineUsage usage = static_cast<const DXPipeline*>(pipeline)->GetUsage();
|
||||
return (g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader &&
|
||||
usage == AbstractPipelineUsage::GXUber) ||
|
||||
(g_ActiveConfig.UseVSForLinePointExpand() && usage != AbstractPipelineUsage::Utility);
|
||||
}
|
||||
|
||||
Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale)
|
||||
: ::Renderer(swap_chain ? swap_chain->GetWidth() : 0, swap_chain ? swap_chain->GetHeight() : 0,
|
||||
backbuffer_scale,
|
||||
|
@ -364,8 +372,7 @@ void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
|
|||
return;
|
||||
|
||||
// DX12 is great and doesn't include the base vertex in SV_VertexID
|
||||
if (static_cast<const DXPipeline*>(m_current_pipeline)->GetUsage() ==
|
||||
AbstractPipelineUsage::GXUber)
|
||||
if (UsesDynamicVertexLoader(m_current_pipeline))
|
||||
g_dx_context->GetCommandList()->SetGraphicsRoot32BitConstant(
|
||||
ROOT_PARAMETER_BASE_VERTEX_CONSTANT, base_vertex, 0);
|
||||
g_dx_context->GetCommandList()->DrawIndexedInstanced(num_indices, 1, base_index, base_vertex, 0);
|
||||
|
@ -601,8 +608,7 @@ bool Renderer::ApplyState()
|
|||
}
|
||||
}
|
||||
|
||||
if (dirty_bits & DirtyState_VS_SRV_Descriptor &&
|
||||
pipeline->GetUsage() == AbstractPipelineUsage::GXUber)
|
||||
if (dirty_bits & DirtyState_VS_SRV_Descriptor && UsesDynamicVertexLoader(pipeline))
|
||||
{
|
||||
cmdlist->SetGraphicsRootDescriptorTable(ROOT_PARAMETER_VS_SRV,
|
||||
m_state.vertex_srv_descriptor_base);
|
||||
|
@ -724,9 +730,7 @@ bool Renderer::UpdateUAVDescriptorTable()
|
|||
|
||||
bool Renderer::UpdateVSSRVDescriptorTable()
|
||||
{
|
||||
if (!g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader ||
|
||||
static_cast<const DXPipeline*>(m_current_pipeline)->GetUsage() !=
|
||||
AbstractPipelineUsage::GXUber)
|
||||
if (!UsesDynamicVertexLoader(m_current_pipeline))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -353,12 +353,15 @@ bool DXContext::CreateGXRootSignature()
|
|||
param_count++;
|
||||
SetRootParamCBV(¶ms[param_count], 1, D3D12_SHADER_VISIBILITY_VERTEX);
|
||||
param_count++;
|
||||
SetRootParamCBV(¶ms[param_count], 0, D3D12_SHADER_VISIBILITY_GEOMETRY);
|
||||
if (g_ActiveConfig.UseVSForLinePointExpand())
|
||||
SetRootParamCBV(¶ms[param_count], 2, D3D12_SHADER_VISIBILITY_VERTEX);
|
||||
else
|
||||
SetRootParamCBV(¶ms[param_count], 0, D3D12_SHADER_VISIBILITY_GEOMETRY);
|
||||
param_count++;
|
||||
SetRootParamTable(¶ms[param_count], &ranges[param_count], D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 3,
|
||||
1, D3D12_SHADER_VISIBILITY_VERTEX);
|
||||
param_count++;
|
||||
SetRootParamConstant(¶ms[param_count], 2, 1, D3D12_SHADER_VISIBILITY_VERTEX);
|
||||
SetRootParamConstant(¶ms[param_count], 3, 1, D3D12_SHADER_VISIBILITY_VERTEX);
|
||||
param_count++;
|
||||
|
||||
// Since these must be contiguous, pixel lighting goes to bbox if not enabled.
|
||||
|
|
|
@ -88,6 +88,7 @@ void VideoBackend::FillBackendInfo()
|
|||
g_Config.backend_info.bSupportsSettingObjectNames = true;
|
||||
g_Config.backend_info.bSupportsPartialMultisampleResolve = true;
|
||||
g_Config.backend_info.bSupportsDynamicVertexLoader = true;
|
||||
g_Config.backend_info.bSupportsVSLinePointExpand = true;
|
||||
|
||||
// We can only check texture support once we have a device.
|
||||
if (g_dx_context)
|
||||
|
|
|
@ -83,7 +83,7 @@ public:
|
|||
void SetTexture(u32 idx, id<MTLTexture> texture);
|
||||
void SetSampler(u32 idx, const SamplerState& sampler);
|
||||
void SetComputeTexture(const Texture* texture);
|
||||
void InvalidateUniforms(bool vertex, bool fragment);
|
||||
void InvalidateUniforms(bool vertex, bool geometry, bool fragment);
|
||||
void SetUtilityUniform(const void* buffer, size_t size);
|
||||
void SetTexelBuffer(id<MTLBuffer> buffer, u32 offset0, u32 offset1);
|
||||
void SetVerticesAndIndices(id<MTLBuffer> vertices, id<MTLBuffer> indices);
|
||||
|
@ -180,6 +180,7 @@ private:
|
|||
{
|
||||
// clang-format off
|
||||
bool has_gx_vs_uniform : 1;
|
||||
bool has_gx_gs_uniform : 1;
|
||||
bool has_gx_ps_uniform : 1;
|
||||
bool has_utility_vs_uniform : 1;
|
||||
bool has_utility_ps_uniform : 1;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "VideoBackends/Metal/MTLTexture.h"
|
||||
#include "VideoBackends/Metal/MTLUtil.h"
|
||||
|
||||
#include "VideoCommon/GeometryShaderManager.h"
|
||||
#include "VideoCommon/PixelShaderManager.h"
|
||||
#include "VideoCommon/Statistics.h"
|
||||
#include "VideoCommon/VertexShaderManager.h"
|
||||
|
@ -462,9 +463,10 @@ void Metal::StateTracker::UnbindTexture(id<MTLTexture> texture)
|
|||
}
|
||||
}
|
||||
|
||||
void Metal::StateTracker::InvalidateUniforms(bool vertex, bool fragment)
|
||||
void Metal::StateTracker::InvalidateUniforms(bool vertex, bool geometry, bool fragment)
|
||||
{
|
||||
m_flags.has_gx_vs_uniform &= !vertex;
|
||||
m_flags.has_gx_gs_uniform &= !geometry;
|
||||
m_flags.has_gx_ps_uniform &= !fragment;
|
||||
}
|
||||
|
||||
|
@ -722,6 +724,14 @@ void Metal::StateTracker::PrepareRender()
|
|||
ADDSTAT(g_stats.this_frame.bytes_uniform_streamed,
|
||||
Align(sizeof(VertexShaderConstants), AlignMask::Uniform));
|
||||
}
|
||||
if (!m_flags.has_gx_gs_uniform && pipe->UsesVertexBuffer(2))
|
||||
{
|
||||
m_flags.has_gx_gs_uniform = true;
|
||||
[m_current_render_encoder setVertexBytes:&GeometryShaderManager::constants
|
||||
length:sizeof(GeometryShaderConstants)
|
||||
atIndex:2];
|
||||
ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, sizeof(GeometryShaderConstants));
|
||||
}
|
||||
if (!m_flags.has_gx_ps_uniform)
|
||||
{
|
||||
m_flags.has_gx_ps_uniform = true;
|
||||
|
|
|
@ -75,6 +75,7 @@ void Metal::Util::PopulateBackendInfo(VideoConfig* config)
|
|||
// Metal requires multisample resolve to be done on a render pass
|
||||
config->backend_info.bSupportsPartialMultisampleResolve = false;
|
||||
config->backend_info.bSupportsDynamicVertexLoader = true;
|
||||
config->backend_info.bSupportsVSLinePointExpand = true;
|
||||
}
|
||||
|
||||
void Metal::Util::PopulateBackendInfoAdapters(VideoConfig* config,
|
||||
|
@ -427,6 +428,7 @@ std::optional<std::string> Metal::Util::TranslateShaderToMSL(ShaderStage stage,
|
|||
static const spirv_cross::MSLResourceBinding resource_bindings[] = {
|
||||
MakeResourceBinding(spv::ExecutionModelVertex, 0, 0, 1, 0, 0), // vs/ubo
|
||||
MakeResourceBinding(spv::ExecutionModelVertex, 0, 1, 1, 0, 0), // vs/ubo
|
||||
MakeResourceBinding(spv::ExecutionModelVertex, 0, 2, 2, 0, 0), // vs/ubo
|
||||
MakeResourceBinding(spv::ExecutionModelVertex, 2, 1, 0, 0, 0), // vs/ssbo
|
||||
MakeResourceBinding(spv::ExecutionModelFragment, 0, 0, 0, 0, 0), // vs/ubo
|
||||
MakeResourceBinding(spv::ExecutionModelFragment, 0, 1, 1, 0, 0), // vs/ubo
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "VideoBackends/Metal/MTLStateTracker.h"
|
||||
|
||||
#include "VideoCommon/GeometryShaderManager.h"
|
||||
#include "VideoCommon/PixelShaderManager.h"
|
||||
#include "VideoCommon/Statistics.h"
|
||||
#include "VideoCommon/VertexShaderManager.h"
|
||||
|
@ -88,7 +89,9 @@ void Metal::VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32
|
|||
|
||||
void Metal::VertexManager::UploadUniforms()
|
||||
{
|
||||
g_state_tracker->InvalidateUniforms(VertexShaderManager::dirty, PixelShaderManager::dirty);
|
||||
g_state_tracker->InvalidateUniforms(VertexShaderManager::dirty, GeometryShaderManager::dirty,
|
||||
PixelShaderManager::dirty);
|
||||
VertexShaderManager::dirty = false;
|
||||
GeometryShaderManager::dirty = false;
|
||||
PixelShaderManager::dirty = false;
|
||||
}
|
||||
|
|
|
@ -423,6 +423,8 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
|
|||
((GLExtensions::Version() >= 310) || GLExtensions::Supports("GL_NV_primitive_restart"));
|
||||
g_Config.backend_info.bSupportsFragmentStoresAndAtomics =
|
||||
GLExtensions::Supports("GL_ARB_shader_storage_buffer_object");
|
||||
g_Config.backend_info.bSupportsVSLinePointExpand =
|
||||
GLExtensions::Supports("GL_ARB_shader_storage_buffer_object");
|
||||
g_Config.backend_info.bSupportsGSInstancing = GLExtensions::Supports("GL_ARB_gpu_shader5");
|
||||
g_Config.backend_info.bSupportsSSAA = GLExtensions::Supports("GL_ARB_gpu_shader5") &&
|
||||
GLExtensions::Supports("GL_ARB_sample_shading");
|
||||
|
|
|
@ -58,6 +58,11 @@ bool VertexManager::Initialize()
|
|||
|
||||
m_vertex_buffer = StreamBuffer::Create(GL_ARRAY_BUFFER, VERTEX_STREAM_BUFFER_SIZE);
|
||||
m_index_buffer = StreamBuffer::Create(GL_ELEMENT_ARRAY_BUFFER, INDEX_STREAM_BUFFER_SIZE);
|
||||
if (g_ActiveConfig.UseVSForLinePointExpand() ||
|
||||
g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader)
|
||||
{
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_vertex_buffer->GetGLBufferId());
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
|
||||
{
|
||||
|
|
|
@ -156,9 +156,11 @@ bool ObjectCache::CreateDescriptorSetLayouts()
|
|||
{5, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT},
|
||||
}};
|
||||
|
||||
std::array<VkDescriptorSetLayoutBinding, 3> ubo_bindings = standard_ubo_bindings;
|
||||
|
||||
std::array<VkDescriptorSetLayoutCreateInfo, NUM_DESCRIPTOR_SET_LAYOUTS> create_infos{{
|
||||
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(standard_ubo_bindings.size()), standard_ubo_bindings.data()},
|
||||
static_cast<u32>(ubo_bindings.size()), ubo_bindings.data()},
|
||||
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(standard_sampler_bindings.size()), standard_sampler_bindings.data()},
|
||||
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
|
@ -172,8 +174,17 @@ bool ObjectCache::CreateDescriptorSetLayouts()
|
|||
}};
|
||||
|
||||
// Don't set the GS bit if geometry shaders aren't available.
|
||||
if (!g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
if (g_ActiveConfig.UseVSForLinePointExpand())
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
ubo_bindings[UBO_DESCRIPTOR_SET_BINDING_GS].stageFlags |= VK_SHADER_STAGE_VERTEX_BIT;
|
||||
else
|
||||
ubo_bindings[UBO_DESCRIPTOR_SET_BINDING_GS].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
}
|
||||
else if (!g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
create_infos[DESCRIPTOR_SET_LAYOUT_STANDARD_UNIFORM_BUFFERS].bindingCount--;
|
||||
}
|
||||
|
||||
// Remove the dynamic vertex loader's buffer if it'll never be needed
|
||||
if (!g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader)
|
||||
|
@ -244,12 +255,14 @@ bool ObjectCache::CreatePipelineLayouts()
|
|||
static_cast<u32>(compute_sets.size()), compute_sets.data(), 0, nullptr},
|
||||
}};
|
||||
|
||||
const bool ssbos_in_standard =
|
||||
g_ActiveConfig.backend_info.bSupportsBBox || g_ActiveConfig.UseVSForLinePointExpand();
|
||||
|
||||
// If bounding box is unsupported, don't bother with the SSBO descriptor set.
|
||||
if (!g_ActiveConfig.backend_info.bSupportsBBox)
|
||||
if (!ssbos_in_standard)
|
||||
pipeline_layout_info[PIPELINE_LAYOUT_STANDARD].setLayoutCount--;
|
||||
// If neither SSBO-using feature is supported, skip in ubershaders too
|
||||
if (!g_ActiveConfig.backend_info.bSupportsBBox &&
|
||||
!g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader)
|
||||
if (!ssbos_in_standard && !g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader)
|
||||
pipeline_layout_info[PIPELINE_LAYOUT_UBER].setLayoutCount--;
|
||||
|
||||
for (size_t i = 0; i < pipeline_layout_info.size(); i++)
|
||||
|
|
|
@ -458,6 +458,9 @@ void StateTracker::UpdateGXDescriptorSet()
|
|||
std::array<VkWriteDescriptorSet, MAX_DESCRIPTOR_WRITES> writes;
|
||||
u32 num_writes = 0;
|
||||
|
||||
const bool needs_gs_ubo = g_ActiveConfig.backend_info.bSupportsGeometryShaders ||
|
||||
g_ActiveConfig.UseVSForLinePointExpand();
|
||||
|
||||
if (m_dirty_flags & DIRTY_FLAG_GX_UBOS || m_gx_descriptor_sets[0] == VK_NULL_HANDLE)
|
||||
{
|
||||
m_gx_descriptor_sets[0] = g_command_buffer_mgr->AllocateDescriptorSet(
|
||||
|
@ -465,8 +468,7 @@ void StateTracker::UpdateGXDescriptorSet()
|
|||
|
||||
for (size_t i = 0; i < NUM_UBO_DESCRIPTOR_SET_BINDINGS; i++)
|
||||
{
|
||||
if (i == UBO_DESCRIPTOR_SET_BINDING_GS &&
|
||||
!g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
if (i == UBO_DESCRIPTOR_SET_BINDING_GS && !needs_gs_ubo)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -505,8 +507,9 @@ void StateTracker::UpdateGXDescriptorSet()
|
|||
}
|
||||
|
||||
const bool needs_bbox_ssbo = g_ActiveConfig.backend_info.bSupportsBBox;
|
||||
const bool needs_vertex_ssbo = g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader &&
|
||||
m_pipeline->GetUsage() == AbstractPipelineUsage::GXUber;
|
||||
const bool needs_vertex_ssbo = (g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader &&
|
||||
m_pipeline->GetUsage() == AbstractPipelineUsage::GXUber) ||
|
||||
g_ActiveConfig.UseVSForLinePointExpand();
|
||||
const bool needs_ssbo = needs_bbox_ssbo || needs_vertex_ssbo;
|
||||
|
||||
if (needs_ssbo &&
|
||||
|
@ -520,7 +523,8 @@ void StateTracker::UpdateGXDescriptorSet()
|
|||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, m_gx_descriptor_sets[2], 0, 0, 1,
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nullptr, &m_bindings.ssbo, nullptr};
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader)
|
||||
if (g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader ||
|
||||
g_ActiveConfig.UseVSForLinePointExpand())
|
||||
{
|
||||
writes[num_writes++] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
nullptr,
|
||||
|
@ -546,21 +550,18 @@ void StateTracker::UpdateGXDescriptorSet()
|
|||
VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline->GetVkPipelineLayout(), 0,
|
||||
needs_ssbo ? NUM_GX_DESCRIPTOR_SETS : (NUM_GX_DESCRIPTOR_SETS - 1),
|
||||
m_gx_descriptor_sets.data(),
|
||||
g_ActiveConfig.backend_info.bSupportsGeometryShaders ?
|
||||
NUM_UBO_DESCRIPTOR_SET_BINDINGS :
|
||||
(NUM_UBO_DESCRIPTOR_SET_BINDINGS - 1),
|
||||
needs_gs_ubo ? NUM_UBO_DESCRIPTOR_SET_BINDINGS :
|
||||
(NUM_UBO_DESCRIPTOR_SET_BINDINGS - 1),
|
||||
m_bindings.gx_ubo_offsets.data());
|
||||
m_dirty_flags &= ~(DIRTY_FLAG_DESCRIPTOR_SETS | DIRTY_FLAG_GX_UBO_OFFSETS);
|
||||
}
|
||||
else if (m_dirty_flags & DIRTY_FLAG_GX_UBO_OFFSETS)
|
||||
{
|
||||
vkCmdBindDescriptorSets(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline->GetVkPipelineLayout(), 0,
|
||||
1, m_gx_descriptor_sets.data(),
|
||||
g_ActiveConfig.backend_info.bSupportsGeometryShaders ?
|
||||
NUM_UBO_DESCRIPTOR_SET_BINDINGS :
|
||||
(NUM_UBO_DESCRIPTOR_SET_BINDINGS - 1),
|
||||
m_bindings.gx_ubo_offsets.data());
|
||||
vkCmdBindDescriptorSets(
|
||||
g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
m_pipeline->GetVkPipelineLayout(), 0, 1, m_gx_descriptor_sets.data(),
|
||||
needs_gs_ubo ? NUM_UBO_DESCRIPTOR_SET_BINDINGS : (NUM_UBO_DESCRIPTOR_SET_BINDINGS - 1),
|
||||
m_bindings.gx_ubo_offsets.data());
|
||||
m_dirty_flags &= ~DIRTY_FLAG_GX_UBO_OFFSETS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -304,6 +304,7 @@ void VulkanContext::PopulateBackendInfo(VideoConfig* config)
|
|||
config->backend_info.bSupportsSettingObjectNames = false; // Dependent on features.
|
||||
config->backend_info.bSupportsPartialMultisampleResolve = true; // Assumed support.
|
||||
config->backend_info.bSupportsDynamicVertexLoader = true; // Assumed support.
|
||||
config->backend_info.bSupportsVSLinePointExpand = true; // Assumed support.
|
||||
}
|
||||
|
||||
void VulkanContext::PopulateBackendInfoAdapters(VideoConfig* config, const GPUList& gpu_list)
|
||||
|
|
|
@ -102,9 +102,18 @@ struct VertexShaderConstants
|
|||
std::array<u32, 8> vertex_offset_texcoords;
|
||||
};
|
||||
|
||||
enum class VSExpand : u32
|
||||
{
|
||||
None = 0,
|
||||
Point,
|
||||
Line,
|
||||
};
|
||||
|
||||
struct GeometryShaderConstants
|
||||
{
|
||||
float4 stereoparams;
|
||||
float4 lineptparams;
|
||||
int4 texoffset;
|
||||
VSExpand vs_expand; // Used by VS point/line expansion in ubershaders
|
||||
u32 pad[3];
|
||||
};
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace VideoCommon
|
|||
// As pipelines encompass both shader UIDs and render states, changes to either of these should
|
||||
// also increment the pipeline UID version. Incrementing the UID version will cause all UID
|
||||
// caches to be invalidated.
|
||||
constexpr u32 GX_PIPELINE_UID_VERSION = 5; // Last changed in PR 10747
|
||||
constexpr u32 GX_PIPELINE_UID_VERSION = 6; // Last changed in PR 10890
|
||||
|
||||
struct GXPipelineUid
|
||||
{
|
||||
|
|
|
@ -97,10 +97,8 @@ ShaderCode GenerateGeometryShaderCode(APIType api_type, const ShaderHostConfig&
|
|||
else
|
||||
out.Write("cbuffer GSBlock {{\n");
|
||||
|
||||
out.Write("\tfloat4 " I_STEREOPARAMS ";\n"
|
||||
"\tfloat4 " I_LINEPTPARAMS ";\n"
|
||||
"\tint4 " I_TEXOFFSET ";\n"
|
||||
"}};\n");
|
||||
out.Write("{}", s_geometry_shader_uniforms);
|
||||
out.Write("}};\n");
|
||||
|
||||
out.Write("struct VS_OUTPUT {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, host_config, "",
|
||||
|
@ -171,22 +169,7 @@ ShaderCode GenerateGeometryShaderCode(APIType api_type, const ShaderHostConfig&
|
|||
"\tVS_OUTPUT end = o[1];\n");
|
||||
}
|
||||
|
||||
// GameCube/Wii's line drawing algorithm is a little quirky. It does not
|
||||
// use the correct line caps. Instead, the line caps are vertical or
|
||||
// horizontal depending the slope of the line.
|
||||
out.Write("\tfloat2 offset;\n"
|
||||
"\tfloat2 to = abs(end.pos.xy / end.pos.w - start.pos.xy / start.pos.w);\n"
|
||||
// FIXME: What does real hardware do when line is at a 45-degree angle?
|
||||
// FIXME: Lines aren't drawn at the correct width. See Twilight Princess map.
|
||||
"\tif (" I_LINEPTPARAMS ".y * to.y > " I_LINEPTPARAMS ".x * to.x) {{\n"
|
||||
// Line is more tall. Extend geometry left and right.
|
||||
// Lerp LineWidth/2 from [0..VpWidth] to [-1..1]
|
||||
"\t\toffset = float2(" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".x, 0);\n"
|
||||
"\t}} else {{\n"
|
||||
// Line is more wide. Extend geometry up and down.
|
||||
// Lerp LineWidth/2 from [0..VpHeight] to [1..-1]
|
||||
"\t\toffset = float2(0, -" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".y);\n"
|
||||
"\t}}\n");
|
||||
GenerateLineOffset(out, "\t", "\t\t", "end.pos", "start.pos", "");
|
||||
}
|
||||
else if (primitive_type == PrimitiveType::Points)
|
||||
{
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "Common/ChunkFile.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/RenderState.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
#include "VideoCommon/XFMemory.h"
|
||||
|
||||
|
@ -36,10 +37,22 @@ void GeometryShaderManager::Dirty()
|
|||
// Any constants that can changed based on settings should be re-calculated
|
||||
s_projection_changed = true;
|
||||
|
||||
// Uses EFB scale config
|
||||
SetLinePtWidthChanged();
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void GeometryShaderManager::SetConstants()
|
||||
static void SetVSExpand(VSExpand expand)
|
||||
{
|
||||
if (GeometryShaderManager::constants.vs_expand != expand)
|
||||
{
|
||||
GeometryShaderManager::constants.vs_expand = expand;
|
||||
GeometryShaderManager::dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryShaderManager::SetConstants(PrimitiveType prim)
|
||||
{
|
||||
if (s_projection_changed && g_ActiveConfig.stereo_mode != StereoMode::Off)
|
||||
{
|
||||
|
@ -63,6 +76,16 @@ void GeometryShaderManager::SetConstants()
|
|||
dirty = true;
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.UseVSForLinePointExpand())
|
||||
{
|
||||
if (prim == PrimitiveType::Points)
|
||||
SetVSExpand(VSExpand::Point);
|
||||
else if (prim == PrimitiveType::Lines)
|
||||
SetVSExpand(VSExpand::Line);
|
||||
else
|
||||
SetVSExpand(VSExpand::None);
|
||||
}
|
||||
|
||||
if (s_viewport_changed)
|
||||
{
|
||||
s_viewport_changed = false;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "VideoCommon/ConstantManager.h"
|
||||
|
||||
class PointerWrap;
|
||||
enum class PrimitiveType : u32;
|
||||
|
||||
// The non-API dependent parts.
|
||||
class GeometryShaderManager
|
||||
|
@ -16,7 +17,7 @@ public:
|
|||
static void Dirty();
|
||||
static void DoState(PointerWrap& p);
|
||||
|
||||
static void SetConstants();
|
||||
static void SetConstants(PrimitiveType prim);
|
||||
static void SetViewportChanged();
|
||||
static void SetProjectionChanged();
|
||||
static void SetLinePtWidthChanged();
|
||||
|
|
|
@ -190,6 +190,39 @@ u16* AddLineStrip(u16* index_ptr, u32 num_verts, u32 index)
|
|||
return index_ptr;
|
||||
}
|
||||
|
||||
template <bool pr, bool linestrip>
|
||||
u16* AddLines_VSExpand(u16* index_ptr, u32 num_verts, u32 index)
|
||||
{
|
||||
// VS Expand uses (index >> 2) as the base vertex
|
||||
// Bit 0 indicates which side of the line (left/right for a vertical line)
|
||||
// Bit 1 indicates which point of the line (top/bottom for a vertical line)
|
||||
// VS Expand assumes the two points will be adjacent vertices
|
||||
constexpr u32 advance = linestrip ? 1 : 2;
|
||||
for (u32 i = 1; i < num_verts; i += advance)
|
||||
{
|
||||
u32 p0 = (index + i - 1) << 2;
|
||||
u32 p1 = (index + i - 0) << 2;
|
||||
if constexpr (pr)
|
||||
{
|
||||
*index_ptr++ = p0 + 0;
|
||||
*index_ptr++ = p0 + 1;
|
||||
*index_ptr++ = p1 + 2;
|
||||
*index_ptr++ = p1 + 3;
|
||||
*index_ptr++ = s_primitive_restart;
|
||||
}
|
||||
else
|
||||
{
|
||||
*index_ptr++ = p0 + 0;
|
||||
*index_ptr++ = p0 + 1;
|
||||
*index_ptr++ = p1 + 2;
|
||||
*index_ptr++ = p0 + 1;
|
||||
*index_ptr++ = p1 + 2;
|
||||
*index_ptr++ = p1 + 3;
|
||||
}
|
||||
}
|
||||
return index_ptr;
|
||||
}
|
||||
|
||||
u16* AddPoints(u16* index_ptr, u32 num_verts, u32 index)
|
||||
{
|
||||
for (u32 i = 0; i != num_verts; ++i)
|
||||
|
@ -198,6 +231,35 @@ u16* AddPoints(u16* index_ptr, u32 num_verts, u32 index)
|
|||
}
|
||||
return index_ptr;
|
||||
}
|
||||
|
||||
template <bool pr>
|
||||
u16* AddPoints_VSExpand(u16* index_ptr, u32 num_verts, u32 index)
|
||||
{
|
||||
// VS Expand uses (index >> 2) as the base vertex
|
||||
// Bottom two bits indicate which of (TL, TR, BL, BR) this is
|
||||
for (u32 i = 0; i < num_verts; ++i)
|
||||
{
|
||||
u32 base = (index + i) << 2;
|
||||
if constexpr (pr)
|
||||
{
|
||||
*index_ptr++ = base + 0;
|
||||
*index_ptr++ = base + 1;
|
||||
*index_ptr++ = base + 2;
|
||||
*index_ptr++ = base + 3;
|
||||
*index_ptr++ = s_primitive_restart;
|
||||
}
|
||||
else
|
||||
{
|
||||
*index_ptr++ = base + 0;
|
||||
*index_ptr++ = base + 1;
|
||||
*index_ptr++ = base + 2;
|
||||
*index_ptr++ = base + 1;
|
||||
*index_ptr++ = base + 2;
|
||||
*index_ptr++ = base + 3;
|
||||
}
|
||||
}
|
||||
return index_ptr;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void IndexGenerator::Init()
|
||||
|
@ -220,9 +282,27 @@ void IndexGenerator::Init()
|
|||
m_primitive_table[Primitive::GX_DRAW_TRIANGLE_STRIP] = AddStrip<false>;
|
||||
m_primitive_table[Primitive::GX_DRAW_TRIANGLE_FAN] = AddFan<false>;
|
||||
}
|
||||
m_primitive_table[Primitive::GX_DRAW_LINES] = AddLineList;
|
||||
m_primitive_table[Primitive::GX_DRAW_LINE_STRIP] = AddLineStrip;
|
||||
m_primitive_table[Primitive::GX_DRAW_POINTS] = AddPoints;
|
||||
if (g_Config.UseVSForLinePointExpand())
|
||||
{
|
||||
if (g_Config.backend_info.bSupportsPrimitiveRestart)
|
||||
{
|
||||
m_primitive_table[Primitive::GX_DRAW_LINES] = AddLines_VSExpand<true, false>;
|
||||
m_primitive_table[Primitive::GX_DRAW_LINE_STRIP] = AddLines_VSExpand<true, true>;
|
||||
m_primitive_table[Primitive::GX_DRAW_POINTS] = AddPoints_VSExpand<true>;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_primitive_table[Primitive::GX_DRAW_LINES] = AddLines_VSExpand<false, false>;
|
||||
m_primitive_table[Primitive::GX_DRAW_LINE_STRIP] = AddLines_VSExpand<false, true>;
|
||||
m_primitive_table[Primitive::GX_DRAW_POINTS] = AddPoints_VSExpand<false>;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_primitive_table[Primitive::GX_DRAW_LINES] = AddLineList;
|
||||
m_primitive_table[Primitive::GX_DRAW_LINE_STRIP] = AddLineStrip;
|
||||
m_primitive_table[Primitive::GX_DRAW_POINTS] = AddPoints;
|
||||
}
|
||||
}
|
||||
|
||||
void IndexGenerator::Start(u16* index_ptr)
|
||||
|
@ -246,10 +326,14 @@ void IndexGenerator::AddExternalIndices(const u16* indices, u32 num_indices, u32
|
|||
m_base_index += num_vertices;
|
||||
}
|
||||
|
||||
u32 IndexGenerator::GetRemainingIndices() const
|
||||
u32 IndexGenerator::GetRemainingIndices(OpcodeDecoder::Primitive primitive) const
|
||||
{
|
||||
// -1 is reserved for primitive restart (OGL + DX11)
|
||||
constexpr u32 max_index = 65534;
|
||||
u32 max_index = USHRT_MAX;
|
||||
|
||||
return max_index - m_base_index;
|
||||
if (g_Config.UseVSForLinePointExpand() && primitive >= OpcodeDecoder::Primitive::GX_DRAW_LINES)
|
||||
max_index >>= 2;
|
||||
|
||||
// -1 is reserved for primitive restart
|
||||
|
||||
return max_index - m_base_index - 1;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
// returns numprimitives
|
||||
u32 GetNumVerts() const { return m_base_index; }
|
||||
u32 GetIndexLen() const { return static_cast<u32>(m_index_buffer_current - m_base_index_ptr); }
|
||||
u32 GetRemainingIndices() const;
|
||||
u32 GetRemainingIndices(OpcodeDecoder::Primitive primitive) const;
|
||||
|
||||
private:
|
||||
u16* m_index_buffer_current = nullptr;
|
||||
|
|
|
@ -488,6 +488,7 @@ void Renderer::CheckForConfigChanges()
|
|||
|
||||
UpdateActiveConfig();
|
||||
FreeLook::UpdateActiveConfig();
|
||||
g_vertex_manager->OnConfigChange();
|
||||
|
||||
g_freelook_camera.SetControlType(FreeLook::GetActiveConfig().camera_config.control_type);
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "Common/MsgHandler.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
|
||||
#include "VideoCommon/ConstantManager.h"
|
||||
#include "VideoCommon/DriverDetails.h"
|
||||
#include "VideoCommon/FramebufferManager.h"
|
||||
#include "VideoCommon/FramebufferShaderGen.h"
|
||||
|
@ -695,6 +696,35 @@ static GXPipelineUid ApplyDriverBugs(const GXPipelineUid& in)
|
|||
ps->ztest = EmulatedZ::EarlyWithZComplocHack;
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.UseVSForLinePointExpand() &&
|
||||
(out.rasterization_state.primitive == PrimitiveType::Points ||
|
||||
out.rasterization_state.primitive == PrimitiveType::Lines))
|
||||
{
|
||||
// All primitives are expanded to triangles in the vertex shader
|
||||
vertex_shader_uid_data* vs = out.vs_uid.GetUidData();
|
||||
const PortableVertexDeclaration& decl = out.vertex_format->GetVertexDeclaration();
|
||||
vs->position_has_3_elems = decl.position.components >= 3;
|
||||
vs->texcoord_elem_count = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (decl.texcoords[i].enable)
|
||||
{
|
||||
ASSERT(decl.texcoords[i].components <= 3);
|
||||
vs->texcoord_elem_count |= decl.texcoords[i].components << (i * 2);
|
||||
}
|
||||
}
|
||||
out.vertex_format = nullptr;
|
||||
if (out.rasterization_state.primitive == PrimitiveType::Points)
|
||||
vs->vs_expand = VSExpand::Point;
|
||||
else
|
||||
vs->vs_expand = VSExpand::Line;
|
||||
PrimitiveType prim = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ?
|
||||
PrimitiveType::TriangleStrip :
|
||||
PrimitiveType::Triangles;
|
||||
out.rasterization_state.primitive = prim;
|
||||
out.gs_uid.GetUidData()->primitive_type = static_cast<u32>(prim);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -760,6 +790,17 @@ static GXUberPipelineUid ApplyDriverBugs(const GXUberPipelineUid& in)
|
|||
out.blending_state.usedualsrc = false;
|
||||
out.ps_uid.GetUidData()->no_dual_src = true;
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.UseVSForLinePointExpand())
|
||||
{
|
||||
// All primitives are expanded to triangles in the vertex shader
|
||||
PrimitiveType prim = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ?
|
||||
PrimitiveType::TriangleStrip :
|
||||
PrimitiveType::Triangles;
|
||||
out.rasterization_state.primitive = prim;
|
||||
out.gs_uid.GetUidData()->primitive_type = static_cast<u32>(prim);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
@ -44,6 +45,7 @@ ShaderHostConfig ShaderHostConfig::GetCurrent()
|
|||
g_ActiveConfig.ManualTextureSamplingWithHiResTextures();
|
||||
bits.backend_sampler_lod_bias = g_ActiveConfig.backend_info.bSupportsLodBiasInSampler;
|
||||
bits.backend_dynamic_vertex_loader = g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader;
|
||||
bits.backend_vs_point_line_expand = g_ActiveConfig.UseVSForLinePointExpand();
|
||||
return bits;
|
||||
}
|
||||
|
||||
|
@ -252,6 +254,78 @@ void AssignVSOutputMembers(ShaderCode& object, std::string_view a, std::string_v
|
|||
}
|
||||
}
|
||||
|
||||
void GenerateLineOffset(ShaderCode& object, std::string_view indent0, std::string_view indent1,
|
||||
std::string_view pos_a, std::string_view pos_b, std::string_view sign)
|
||||
{
|
||||
// GameCube/Wii's line drawing algorithm is a little quirky. It does not
|
||||
// use the correct line caps. Instead, the line caps are vertical or
|
||||
// horizontal depending the slope of the line.
|
||||
object.Write("{indent0}float2 offset;\n"
|
||||
"{indent0}float2 to = abs({pos_a}.xy / {pos_a}.w - {pos_b}.xy / {pos_b}.w);\n"
|
||||
// FIXME: What does real hardware do when line is at a 45-degree angle?
|
||||
// FIXME: Lines aren't drawn at the correct width. See Twilight Princess map.
|
||||
"{indent0}if (" I_LINEPTPARAMS ".y * to.y > " I_LINEPTPARAMS ".x * to.x) {{\n"
|
||||
// Line is more tall. Extend geometry left and right.
|
||||
// Lerp LineWidth/2 from [0..VpWidth] to [-1..1]
|
||||
"{indent1}offset = float2({sign}" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".x, 0);\n"
|
||||
"{indent0}}} else {{\n"
|
||||
// Line is more wide. Extend geometry up and down.
|
||||
// Lerp LineWidth/2 from [0..VpHeight] to [1..-1]
|
||||
"{indent1}offset = float2(0, {sign}-" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".y);\n"
|
||||
"{indent0}}}\n",
|
||||
fmt::arg("indent0", indent0), fmt::arg("indent1", indent1), //
|
||||
fmt::arg("pos_a", pos_a), fmt::arg("pos_b", pos_b), fmt::arg("sign", sign));
|
||||
}
|
||||
|
||||
void GenerateVSLineExpansion(ShaderCode& object, std::string_view indent, u32 texgens)
|
||||
{
|
||||
std::string indent1 = std::string(indent) + " ";
|
||||
object.Write("{0}other_pos = float4(dot(" I_PROJECTION "[0], other_pos), dot(" I_PROJECTION
|
||||
"[1], other_pos), dot(" I_PROJECTION "[2], other_pos), dot(" I_PROJECTION
|
||||
"[3], other_pos));\n"
|
||||
"\n"
|
||||
"{0}float expand_sign = is_right ? 1.0f : -1.0f;\n",
|
||||
indent);
|
||||
GenerateLineOffset(object, indent, indent1, "o.pos", "other_pos", "expand_sign * ");
|
||||
object.Write("\n"
|
||||
"{}o.pos.xy += offset * o.pos.w;\n",
|
||||
indent);
|
||||
if (texgens > 0)
|
||||
{
|
||||
object.Write("{}if ((" I_TEXOFFSET "[2] != 0) && is_right) {{\n", indent);
|
||||
object.Write("{} float texOffset = 1.0 / float(" I_TEXOFFSET "[2]);\n", indent);
|
||||
for (u32 i = 0; i < texgens; i++)
|
||||
{
|
||||
object.Write("{} if (((" I_TEXOFFSET "[0] >> {}) & 0x1) != 0)\n", indent, i);
|
||||
object.Write("{} o.tex{}.x += texOffset;\n", indent, i);
|
||||
}
|
||||
object.Write("{}}}\n", indent);
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateVSPointExpansion(ShaderCode& object, std::string_view indent, u32 texgens)
|
||||
{
|
||||
object.Write(
|
||||
"{0}float2 expand_sign = float2(is_right ? 1.0f : -1.0f, is_bottom ? -1.0f : 1.0f);\n"
|
||||
"{0}float2 offset = expand_sign * " I_LINEPTPARAMS ".ww / " I_LINEPTPARAMS ".xy;\n"
|
||||
"{0}o.pos.xy += offset * o.pos.w;\n",
|
||||
indent);
|
||||
if (texgens > 0)
|
||||
{
|
||||
object.Write("{0}if (" I_TEXOFFSET "[3] != 0) {{\n"
|
||||
"{0} float texOffsetMagnitude = 1.0f / float(" I_TEXOFFSET "[3]);\n"
|
||||
"{0} float2 texOffset = float2(is_right ? texOffsetMagnitude : 0.0f, "
|
||||
"is_bottom ? texOffsetMagnitude : 0.0f);",
|
||||
indent);
|
||||
for (u32 i = 0; i < texgens; i++)
|
||||
{
|
||||
object.Write("{} if (((" I_TEXOFFSET "[1] >> {}) & 0x1) != 0)\n", indent, i);
|
||||
object.Write("{} o.tex{}.xy += texOffset;\n", indent, i);
|
||||
}
|
||||
object.Write("{}}}\n", indent);
|
||||
}
|
||||
}
|
||||
|
||||
const char* GetInterpolationQualifier(bool msaa, bool ssaa, bool in_glsl_interface_block, bool in)
|
||||
{
|
||||
if (!msaa)
|
||||
|
|
|
@ -178,6 +178,7 @@ union ShaderHostConfig
|
|||
BitField<25, 1, bool, u32> manual_texture_sampling_custom_texture_sizes;
|
||||
BitField<26, 1, bool, u32> backend_sampler_lod_bias;
|
||||
BitField<27, 1, bool, u32> backend_dynamic_vertex_loader;
|
||||
BitField<28, 1, bool, u32> backend_vs_point_line_expand;
|
||||
|
||||
static ShaderHostConfig GetCurrent();
|
||||
};
|
||||
|
@ -197,6 +198,13 @@ void GenerateVSOutputMembers(ShaderCode& object, APIType api_type, u32 texgens,
|
|||
void AssignVSOutputMembers(ShaderCode& object, std::string_view a, std::string_view b, u32 texgens,
|
||||
const ShaderHostConfig& host_config);
|
||||
|
||||
void GenerateLineOffset(ShaderCode& object, std::string_view indent0, std::string_view indent1,
|
||||
std::string_view pos_a, std::string_view pos_b, std::string_view sign);
|
||||
|
||||
void GenerateVSLineExpansion(ShaderCode& object, std::string_view indent, u32 texgens);
|
||||
|
||||
void GenerateVSPointExpansion(ShaderCode& object, std::string_view indent, u32 texgens);
|
||||
|
||||
// We use the flag "centroid" to fix some MSAA rendering bugs. With MSAA, the
|
||||
// pixel shader will be executed for each pixel which has at least one passed sample.
|
||||
// So there may be rendered pixels where the center of the pixel isn't in the primitive.
|
||||
|
@ -316,3 +324,8 @@ static const char s_shader_uniforms[] = "\tuint components;\n"
|
|||
"\t#define xfmem_postMtxInfo(i) (xfmem_pack1[(i)].y)\n"
|
||||
"\t#define xfmem_color(i) (xfmem_pack1[(i)].z)\n"
|
||||
"\t#define xfmem_alpha(i) (xfmem_pack1[(i)].w)\n";
|
||||
|
||||
static const char s_geometry_shader_uniforms[] = "\tfloat4 " I_STEREOPARAMS ";\n"
|
||||
"\tfloat4 " I_LINEPTPARAMS ";\n"
|
||||
"\tint4 " I_TEXOFFSET ";\n"
|
||||
"\tuint vs_expand;\n";
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "VideoCommon/UberShaderVertex.h"
|
||||
|
||||
#include "VideoCommon/ConstantManager.h"
|
||||
#include "VideoCommon/DriverDetails.h"
|
||||
#include "VideoCommon/NativeVertexFormat.h"
|
||||
#include "VideoCommon/UberShaderCommon.h"
|
||||
|
@ -35,6 +36,8 @@ ShaderCode GenVertexShader(APIType api_type, const ShaderHostConfig& host_config
|
|||
const bool ssaa = host_config.ssaa;
|
||||
const bool per_pixel_lighting = host_config.per_pixel_lighting;
|
||||
const bool vertex_rounding = host_config.vertex_rounding;
|
||||
const bool vertex_loader =
|
||||
host_config.backend_dynamic_vertex_loader || host_config.backend_vs_point_line_expand;
|
||||
const u32 num_texgen = uid_data->num_texgens;
|
||||
ShaderCode out;
|
||||
|
||||
|
@ -46,6 +49,13 @@ ShaderCode GenVertexShader(APIType api_type, const ShaderHostConfig& host_config
|
|||
out.Write("{}", s_shader_uniforms);
|
||||
out.Write("}};\n");
|
||||
|
||||
if (vertex_loader)
|
||||
{
|
||||
out.Write("UBO_BINDING(std140, 3) uniform GSBlock {{\n");
|
||||
out.Write("{}", s_geometry_shader_uniforms);
|
||||
out.Write("}};\n");
|
||||
}
|
||||
|
||||
out.Write("struct VS_OUTPUT {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, num_texgen, host_config, "", ShaderStage::Vertex);
|
||||
out.Write("}};\n\n");
|
||||
|
@ -54,7 +64,7 @@ ShaderCode GenVertexShader(APIType api_type, const ShaderHostConfig& host_config
|
|||
WriteBitfieldExtractHeader(out, api_type, host_config);
|
||||
WriteLightingFunction(out);
|
||||
|
||||
if (host_config.backend_dynamic_vertex_loader)
|
||||
if (vertex_loader)
|
||||
{
|
||||
out.Write(R"(
|
||||
SSBO_BINDING(1) readonly restrict buffer Vertices {{
|
||||
|
@ -73,17 +83,17 @@ SSBO_BINDING(1) readonly restrict buffer Vertices {{
|
|||
// D3D12 uses a root constant for this uniform, since it changes with every draw.
|
||||
// D3D11 doesn't currently support dynamic vertex loader, and we'll have to figure something
|
||||
// out for it if we want to support it in the future.
|
||||
out.Write("UBO_BINDING(std140, 3) uniform DX_Constants {{\n"
|
||||
out.Write("UBO_BINDING(std140, 4) uniform DX_Constants {{\n"
|
||||
" uint base_vertex;\n"
|
||||
"}};\n\n"
|
||||
"uint GetVertexBaseOffset() {{\n"
|
||||
" return (gl_VertexID + base_vertex) * vertex_stride;\n"
|
||||
"uint GetVertexBaseOffset(uint vertex_id) {{\n"
|
||||
" return (vertex_id + base_vertex) * vertex_stride;\n"
|
||||
"}}\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write("uint GetVertexBaseOffset() {{\n"
|
||||
" return gl_VertexID * vertex_stride;\n"
|
||||
out.Write("uint GetVertexBaseOffset(uint vertex_id) {{\n"
|
||||
" return vertex_id * vertex_stride;\n"
|
||||
"}}\n");
|
||||
}
|
||||
|
||||
|
@ -187,9 +197,17 @@ float3 load_input_float3_rawtex(uint vtx_offset, uint attr_offset) {{
|
|||
|
||||
out.Write("VS_OUTPUT o;\n"
|
||||
"\n");
|
||||
if (host_config.backend_dynamic_vertex_loader)
|
||||
if (host_config.backend_vs_point_line_expand)
|
||||
{
|
||||
out.Write("uint vertex_base_offset = GetVertexBaseOffset();\n");
|
||||
out.Write("uint vertex_id = gl_VertexID;\n"
|
||||
"if (vs_expand != 0u) {{\n"
|
||||
" vertex_id = vertex_id >> 2;\n"
|
||||
"}}\n"
|
||||
"uint vertex_base_offset = GetVertexBaseOffset(vertex_id);\n");
|
||||
}
|
||||
else if (host_config.backend_dynamic_vertex_loader)
|
||||
{
|
||||
out.Write("uint vertex_base_offset = GetVertexBaseOffset(gl_VertexID);\n");
|
||||
}
|
||||
// rawpos is always needed
|
||||
LoadVertexAttribute(out, host_config, 0, "rawpos", "float4", "rawpos");
|
||||
|
@ -320,6 +338,40 @@ float3 load_input_float3_rawtex(uint vtx_offset, uint attr_offset) {{
|
|||
if (num_texgen > 0)
|
||||
GenVertexShaderTexGens(api_type, host_config, num_texgen, out);
|
||||
|
||||
if (host_config.backend_vs_point_line_expand)
|
||||
{
|
||||
out.Write("if (vs_expand == {}u) {{ // Line\n", static_cast<u32>(VSExpand::Line));
|
||||
out.Write(" bool is_bottom = (gl_VertexID & 2) != 0;\n"
|
||||
" bool is_right = (gl_VertexID & 1) != 0;\n"
|
||||
" uint other_base_offset = vertex_base_offset;\n"
|
||||
" if (is_bottom) {{\n"
|
||||
" other_base_offset -= vertex_stride;\n"
|
||||
" }} else {{\n"
|
||||
" other_base_offset += vertex_stride;\n"
|
||||
" }}\n"
|
||||
" float4 other_rawpos = load_input_float4_rawpos(other_base_offset, "
|
||||
"vertex_offset_rawpos);\n"
|
||||
" float4 other_p0 = P0;\n"
|
||||
" float4 other_p1 = P1;\n"
|
||||
" float4 other_p2 = P2;\n"
|
||||
" if ((components & {}u) != 0u) {{ // VB_HAS_POSMTXIDX\n",
|
||||
VB_HAS_POSMTXIDX);
|
||||
out.Write(" uint other_posidx = load_input_uint4_ubyte4(other_base_offset, "
|
||||
"vertex_offset_posmtx).r;\n"
|
||||
" other_p0 = " I_TRANSFORMMATRICES "[other_posidx];\n"
|
||||
" other_p1 = " I_TRANSFORMMATRICES "[other_posidx+1];\n"
|
||||
" other_p2 = " I_TRANSFORMMATRICES "[other_posidx+2];\n"
|
||||
" }}\n"
|
||||
" float4 other_pos = float4(dot(other_p0, other_rawpos), "
|
||||
"dot(other_p1, other_rawpos), dot(other_p2, other_rawpos), 1.0);\n");
|
||||
GenerateVSLineExpansion(out, " ", num_texgen);
|
||||
out.Write("}} else if (vs_expand == {}u) {{ // Point\n", static_cast<u32>(VSExpand::Point));
|
||||
out.Write(" bool is_bottom = (gl_VertexID & 2) != 0;\n"
|
||||
" bool is_right = (gl_VertexID & 1) != 0;\n");
|
||||
GenerateVSPointExpansion(out, " ", num_texgen);
|
||||
out.Write("}}\n");
|
||||
}
|
||||
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
out.Write("// When per-pixel lighting is enabled, the vertex colors are passed through\n"
|
||||
|
@ -574,7 +626,7 @@ static void GenVertexShaderTexGens(APIType api_type, const ShaderHostConfig& hos
|
|||
" {{\n");
|
||||
out.Write(" if ((components & ({}u /* VB_HAS_TEXMTXIDX0 */ << texgen)) != 0u) {{\n",
|
||||
VB_HAS_TEXMTXIDX0);
|
||||
if (host_config.backend_dynamic_vertex_loader)
|
||||
if (host_config.backend_dynamic_vertex_loader || host_config.backend_vs_point_line_expand)
|
||||
{
|
||||
out.Write(" int tmp = int(load_input_float3_rawtex(vertex_base_offset, "
|
||||
"vertex_offset_rawtex[texgen / 4][texgen % 4]).z);\n"
|
||||
|
@ -655,7 +707,7 @@ static void LoadVertexAttribute(ShaderCode& code, const ShaderHostConfig& host_c
|
|||
std::string_view name, std::string_view shader_type,
|
||||
std::string_view stored_type, std::string_view offset_name)
|
||||
{
|
||||
if (host_config.backend_dynamic_vertex_loader)
|
||||
if (host_config.backend_dynamic_vertex_loader || host_config.backend_vs_point_line_expand)
|
||||
{
|
||||
code.Write("{:{}}{} {} = load_input_{}_{}(vertex_base_offset, vertex_offset_{});\n", "", indent,
|
||||
shader_type, name, shader_type, stored_type,
|
||||
|
|
|
@ -140,12 +140,12 @@ DataReader VertexManagerBase::PrepareForAdditionalData(OpcodeDecoder::Primitive
|
|||
|
||||
// Check for size in buffer, if the buffer gets full, call Flush()
|
||||
if (!m_is_flushed &&
|
||||
(count > m_index_generator.GetRemainingIndices() || count > GetRemainingIndices(primitive) ||
|
||||
needed_vertex_bytes > GetRemainingSize()))
|
||||
(count > m_index_generator.GetRemainingIndices(primitive) ||
|
||||
count > GetRemainingIndices(primitive) || needed_vertex_bytes > GetRemainingSize()))
|
||||
{
|
||||
Flush();
|
||||
|
||||
if (count > m_index_generator.GetRemainingIndices())
|
||||
if (count > m_index_generator.GetRemainingIndices(primitive))
|
||||
{
|
||||
ERROR_LOG_FMT(VIDEO, "Too little remaining index values. Use 32-bit or reset them on flush.");
|
||||
}
|
||||
|
@ -193,7 +193,55 @@ u32 VertexManagerBase::GetRemainingIndices(OpcodeDecoder::Primitive primitive) c
|
|||
{
|
||||
const u32 index_len = MAXIBUFFERSIZE - m_index_generator.GetIndexLen();
|
||||
|
||||
if (g_Config.backend_info.bSupportsPrimitiveRestart)
|
||||
if (primitive >= Primitive::GX_DRAW_LINES)
|
||||
{
|
||||
if (g_Config.UseVSForLinePointExpand())
|
||||
{
|
||||
if (g_Config.backend_info.bSupportsPrimitiveRestart)
|
||||
{
|
||||
switch (primitive)
|
||||
{
|
||||
case Primitive::GX_DRAW_LINES:
|
||||
return index_len / 5 * 2;
|
||||
case Primitive::GX_DRAW_LINE_STRIP:
|
||||
return index_len / 5 + 1;
|
||||
case Primitive::GX_DRAW_POINTS:
|
||||
return index_len / 5;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (primitive)
|
||||
{
|
||||
case Primitive::GX_DRAW_LINES:
|
||||
return index_len / 6 * 2;
|
||||
case Primitive::GX_DRAW_LINE_STRIP:
|
||||
return index_len / 6 + 1;
|
||||
case Primitive::GX_DRAW_POINTS:
|
||||
return index_len / 6;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (primitive)
|
||||
{
|
||||
case Primitive::GX_DRAW_LINES:
|
||||
return index_len;
|
||||
case Primitive::GX_DRAW_LINE_STRIP:
|
||||
return index_len / 2 + 1;
|
||||
case Primitive::GX_DRAW_POINTS:
|
||||
return index_len;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (g_Config.backend_info.bSupportsPrimitiveRestart)
|
||||
{
|
||||
switch (primitive)
|
||||
{
|
||||
|
@ -206,15 +254,6 @@ u32 VertexManagerBase::GetRemainingIndices(OpcodeDecoder::Primitive primitive) c
|
|||
return index_len / 1 - 1;
|
||||
case Primitive::GX_DRAW_TRIANGLE_FAN:
|
||||
return index_len / 6 * 4 + 1;
|
||||
|
||||
case Primitive::GX_DRAW_LINES:
|
||||
return index_len;
|
||||
case Primitive::GX_DRAW_LINE_STRIP:
|
||||
return index_len / 2 + 1;
|
||||
|
||||
case Primitive::GX_DRAW_POINTS:
|
||||
return index_len;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -232,15 +271,6 @@ u32 VertexManagerBase::GetRemainingIndices(OpcodeDecoder::Primitive primitive) c
|
|||
return index_len / 3 + 2;
|
||||
case Primitive::GX_DRAW_TRIANGLE_FAN:
|
||||
return index_len / 3 + 2;
|
||||
|
||||
case Primitive::GX_DRAW_LINES:
|
||||
return index_len;
|
||||
case Primitive::GX_DRAW_LINE_STRIP:
|
||||
return index_len / 2 + 1;
|
||||
|
||||
case Primitive::GX_DRAW_POINTS:
|
||||
return index_len;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -511,13 +541,24 @@ void VertexManagerBase::Flush()
|
|||
VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride(), num_indices,
|
||||
&base_vertex, &base_index);
|
||||
|
||||
if (g_ActiveConfig.backend_info.api_type != APIType::D3D &&
|
||||
g_ActiveConfig.UseVSForLinePointExpand() &&
|
||||
(m_current_primitive_type == PrimitiveType::Points ||
|
||||
m_current_primitive_type == PrimitiveType::Lines))
|
||||
{
|
||||
// VS point/line expansion puts the vertex id at gl_VertexID << 2
|
||||
// That means the base vertex has to be adjusted to match
|
||||
// (The shader adds this after shifting right on D3D, so no need to do this)
|
||||
base_vertex <<= 2;
|
||||
}
|
||||
|
||||
// Texture loading can cause palettes to be applied (-> uniforms -> draws).
|
||||
// Palette application does not use vertices, only a full-screen quad, so this is okay.
|
||||
// Same with GPU texture decoding, which uses compute shaders.
|
||||
g_texture_cache->BindTextures(used_textures);
|
||||
|
||||
// Now we can upload uniforms, as nothing else will override them.
|
||||
GeometryShaderManager::SetConstants();
|
||||
GeometryShaderManager::SetConstants(m_current_primitive_type);
|
||||
PixelShaderManager::SetConstants();
|
||||
UploadUniforms();
|
||||
|
||||
|
@ -785,6 +826,12 @@ void VertexManagerBase::UpdatePipelineObject()
|
|||
}
|
||||
}
|
||||
|
||||
void VertexManagerBase::OnConfigChange()
|
||||
{
|
||||
// Reload index generator function tables in case VS expand config changed
|
||||
m_index_generator.Init();
|
||||
}
|
||||
|
||||
void VertexManagerBase::OnDraw()
|
||||
{
|
||||
m_draw_counter++;
|
||||
|
|
|
@ -140,6 +140,9 @@ public:
|
|||
u32* out_offset, const void* palette_data, u32 palette_size,
|
||||
TexelBufferFormat palette_format, u32* out_palette_offset);
|
||||
|
||||
// Call if active config changes
|
||||
void OnConfigChange();
|
||||
|
||||
// CPU access tracking - call after a draw call is made.
|
||||
void OnDraw();
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "Common/Assert.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/ConstantManager.h"
|
||||
#include "VideoCommon/LightingShaderGen.h"
|
||||
#include "VideoCommon/NativeVertexFormat.h"
|
||||
#include "VideoCommon/VertexLoaderManager.h"
|
||||
|
@ -83,6 +84,8 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
|
|||
const bool ssaa = host_config.ssaa;
|
||||
const bool vertex_rounding = host_config.vertex_rounding;
|
||||
|
||||
ShaderCode input_extract;
|
||||
|
||||
out.Write("{}", s_lighting_struct);
|
||||
|
||||
// uniforms
|
||||
|
@ -91,6 +94,21 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
|
|||
out.Write("{}", s_shader_uniforms);
|
||||
out.Write("}};\n");
|
||||
|
||||
if (uid_data->vs_expand != VSExpand::None)
|
||||
{
|
||||
out.Write("UBO_BINDING(std140, 3) uniform GSBlock {{\n");
|
||||
out.Write("{}", s_geometry_shader_uniforms);
|
||||
out.Write("}};\n");
|
||||
|
||||
if (api_type == APIType::D3D)
|
||||
{
|
||||
// D3D doesn't include the base vertex in SV_VertexID
|
||||
out.Write("UBO_BINDING(std140, 4) uniform DX_Constants {{\n"
|
||||
" uint base_vertex;\n"
|
||||
"}};\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
out.Write("struct VS_OUTPUT {{\n");
|
||||
GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, host_config, "",
|
||||
ShaderStage::Vertex);
|
||||
|
@ -98,31 +116,114 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
|
|||
|
||||
WriteIsNanHeader(out, api_type);
|
||||
|
||||
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)
|
||||
if (uid_data->vs_expand == VSExpand::None)
|
||||
{
|
||||
const u32 has_texmtx = (uid_data->components & (VB_HAS_TEXMTXIDX0 << 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);
|
||||
|
||||
if ((uid_data->components & (VB_HAS_UV0 << i)) != 0 || has_texmtx != 0)
|
||||
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 float{} rawtex{};\n", SHADER_TEXTURE0_ATTRIB + i,
|
||||
has_texmtx != 0 ? 3 : 2, 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("ATTRIBUTE_LOCATION({}) in float{} rawtex{};\n", SHADER_TEXTURE0_ATTRIB + i,
|
||||
has_texmtx != 0 ? 3 : 2, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Can't use float3, etc because we want 4-byte alignment
|
||||
out.Write(
|
||||
"uint4 unpack_ubyte4(uint value) {{\n"
|
||||
" return uint4(value & 0xff, (value >> 8) & 0xff, (value >> 16) & 0xff, value >> 24);\n"
|
||||
"}}\n\n"
|
||||
"struct InputData {{\n");
|
||||
if (uid_data->components & VB_HAS_POSMTXIDX)
|
||||
{
|
||||
out.Write(" uint posmtx;\n");
|
||||
input_extract.Write("uint4 posmtx = unpack_ubyte4(i.posmtx);\n");
|
||||
}
|
||||
if (uid_data->position_has_3_elems)
|
||||
{
|
||||
out.Write(" float pos0;\n"
|
||||
" float pos1;\n"
|
||||
" float pos2;\n");
|
||||
input_extract.Write("float4 rawpos = float4(i.pos0, i.pos1, i.pos2, 1.0f);\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write(" float pos0;\n"
|
||||
" float pos1;\n");
|
||||
input_extract.Write("float4 rawpos = float4(i.pos0, i.pos1, 0.0f, 1.0f);\n");
|
||||
}
|
||||
std::array<std::string_view, 3> names = {"normal", "binormal", "tangent"};
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (uid_data->components & (VB_HAS_NORMAL << i))
|
||||
{
|
||||
out.Write(" float {0}0;\n"
|
||||
" float {0}1;\n"
|
||||
" float {0}2;\n",
|
||||
names[i]);
|
||||
input_extract.Write("float3 raw{0} = float3(i.{0}0, i.{0}1, i.{0}2);\n", names[i]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (uid_data->components & (VB_HAS_COL0 << i))
|
||||
{
|
||||
out.Write(" uint color{};\n", i);
|
||||
input_extract.Write("float4 rawcolor{0} = float4(unpack_ubyte4(i.color{0})) / 255.0f;\n",
|
||||
i);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (uid_data->components & (VB_HAS_UV0 << i))
|
||||
{
|
||||
u32 ncomponents = (uid_data->texcoord_elem_count >> (2 * i)) & 3;
|
||||
if (ncomponents < 2)
|
||||
{
|
||||
out.Write(" float tex{};\n", i);
|
||||
input_extract.Write("float3 rawtex{0} = float3(i.tex{0}, 0.0f, 0.0f);\n", i);
|
||||
}
|
||||
else if (ncomponents == 2)
|
||||
{
|
||||
out.Write(" float tex{0}_0;\n"
|
||||
" float tex{0}_1;\n",
|
||||
i);
|
||||
input_extract.Write("float3 rawtex{0} = float3(i.tex{0}_0, i.tex{0}_1, 0.0f);\n", i);
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write(" float tex{0}_0;\n"
|
||||
" float tex{0}_1;\n"
|
||||
" float tex{0}_2;\n",
|
||||
i);
|
||||
input_extract.Write("float3 rawtex{0} = float3(i.tex{0}_0, i.tex{0}_1, i.tex{0}_2);\n",
|
||||
i);
|
||||
}
|
||||
}
|
||||
}
|
||||
out.Write("}};\n\n"
|
||||
"SSBO_BINDING(1) readonly restrict buffer InputBuffer {{\n"
|
||||
" InputData input_buffer[];\n"
|
||||
"}};\n\n");
|
||||
}
|
||||
|
||||
if (host_config.backend_geometry_shaders)
|
||||
{
|
||||
|
@ -161,6 +262,21 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
|
|||
|
||||
out.Write("void main()\n{{\n");
|
||||
|
||||
if (uid_data->vs_expand != VSExpand::None)
|
||||
{
|
||||
out.Write("bool is_bottom = (gl_VertexID & 2) != 0;\n"
|
||||
"bool is_right = (gl_VertexID & 1) != 0;\n");
|
||||
// D3D doesn't include the base vertex in SV_VertexID
|
||||
// See comment in UberShaderVertex for details
|
||||
if (api_type == APIType::D3D)
|
||||
out.Write("uint vertex_id = (gl_VertexID >> 2) + base_vertex;\n");
|
||||
else
|
||||
out.Write("uint vertex_id = gl_VertexID >> 2;\n");
|
||||
out.Write("InputData i = input_buffer[vertex_id];\n"
|
||||
"{}",
|
||||
input_extract.GetBuffer());
|
||||
}
|
||||
|
||||
out.Write("VS_OUTPUT o;\n");
|
||||
|
||||
// xfmem.numColorChans controls the number of color channels available to TEV, but we still need
|
||||
|
@ -403,6 +519,42 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
|
|||
out.Write("}}\n");
|
||||
}
|
||||
|
||||
if (uid_data->vs_expand == VSExpand::Line)
|
||||
{
|
||||
out.Write("// Line expansion\n"
|
||||
"uint other_id = vertex_id;\n"
|
||||
"if (is_bottom) {{\n"
|
||||
" other_id -= 1;\n"
|
||||
"}} else {{\n"
|
||||
" other_id += 1;\n"
|
||||
"}}\n"
|
||||
"InputData other = input_buffer[other_id];\n");
|
||||
if (uid_data->position_has_3_elems)
|
||||
out.Write("float4 other_pos = float4(other.pos0, other.pos1, other.pos2, 1.0f);\n");
|
||||
else
|
||||
out.Write("float4 other_pos = float4(other.pos0, other.pos1, 0.0f, 1.0f);\n");
|
||||
if (uid_data->components & VB_HAS_POSMTXIDX)
|
||||
{
|
||||
out.Write("uint other_posidx = other.posmtx & 0xff;\n"
|
||||
"float4 other_p0 = " I_TRANSFORMMATRICES "[other_posidx];\n"
|
||||
"float4 other_p1 = " I_TRANSFORMMATRICES "[other_posidx + 1];\n"
|
||||
"float4 other_p2 = " I_TRANSFORMMATRICES "[other_posidx + 2];\n"
|
||||
"other_pos = float4(dot(other_p0, other_pos), dot(other_p1, other_pos), "
|
||||
"dot(other_p2, other_pos), 1.0f);\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write("other_pos = float4(dot(P0, other_pos), dot(P1, other_pos), dot(P2, other_pos), "
|
||||
"1.0f);\n");
|
||||
}
|
||||
GenerateVSLineExpansion(out, "", uid_data->numTexGens);
|
||||
}
|
||||
else if (uid_data->vs_expand == VSExpand::Point)
|
||||
{
|
||||
out.Write("// Point expansion\n");
|
||||
GenerateVSPointExpansion(out, "", uid_data->numTexGens);
|
||||
}
|
||||
|
||||
if (per_pixel_lighting)
|
||||
{
|
||||
// When per-pixel lighting is enabled, the vertex colors are passed through
|
||||
|
|
|
@ -11,6 +11,7 @@ enum class APIType;
|
|||
enum class TexInputForm : u32;
|
||||
enum class TexGenType : u32;
|
||||
enum class SourceRow : u32;
|
||||
enum class VSExpand : u32;
|
||||
|
||||
// TODO should be reordered
|
||||
enum : int
|
||||
|
@ -42,10 +43,12 @@ struct vertex_shader_uid_data
|
|||
u32 numTexGens : 4;
|
||||
u32 numColorChans : 2;
|
||||
u32 dualTexTrans_enabled : 1;
|
||||
VSExpand vs_expand : 2;
|
||||
u32 position_has_3_elems : 1;
|
||||
|
||||
u32 texMtxInfo_n_projection : 16; // Stored separately to guarantee that the texMtxInfo struct is
|
||||
// 8 bits wide
|
||||
u32 pad : 18;
|
||||
u16 texcoord_elem_count; // 2 bits per texcoord input
|
||||
u16 texMtxInfo_n_projection; // Stored separately to guarantee that the texMtxInfo struct is
|
||||
// 8 bits wide
|
||||
|
||||
struct
|
||||
{
|
||||
|
|
|
@ -274,6 +274,7 @@ void VideoBackendBase::PopulateBackendInfo()
|
|||
// a value from the previously used renderer
|
||||
g_Config.backend_info = {};
|
||||
ActivateBackend(Config::Get(Config::MAIN_GFX_BACKEND));
|
||||
g_Config.backend_info.DisplayName = g_video_backend->GetDisplayName();
|
||||
g_video_backend->InitBackendInfo();
|
||||
// We validate the config after initializing the backend info, as system-specific settings
|
||||
// such as anti-aliasing, or the selected adapter may be invalid, and should be checked.
|
||||
|
|
|
@ -85,6 +85,7 @@ void VideoConfig::Refresh()
|
|||
iBitrateKbps = Config::Get(Config::GFX_BITRATE_KBPS);
|
||||
bInternalResolutionFrameDumps = Config::Get(Config::GFX_INTERNAL_RESOLUTION_FRAME_DUMPS);
|
||||
bEnableGPUTextureDecoding = Config::Get(Config::GFX_ENABLE_GPU_TEXTURE_DECODING);
|
||||
bPreferVSForLinePointExpansion = Config::Get(Config::GFX_PREFER_VS_FOR_LINE_POINT_EXPANSION);
|
||||
bEnablePixelLighting = Config::Get(Config::GFX_ENABLE_PIXEL_LIGHTING);
|
||||
bFastDepthCalc = Config::Get(Config::GFX_FAST_DEPTH_CALC);
|
||||
iMultisamples = Config::Get(Config::GFX_MSAA);
|
||||
|
|
|
@ -106,6 +106,7 @@ struct VideoConfig final
|
|||
bool bInternalResolutionFrameDumps = false;
|
||||
bool bBorderlessFullscreen = false;
|
||||
bool bEnableGPUTextureDecoding = false;
|
||||
bool bPreferVSForLinePointExpansion = false;
|
||||
int iBitrateKbps = 0;
|
||||
bool bGraphicMods = false;
|
||||
std::optional<GraphicsModGroupConfig> graphics_mod_config;
|
||||
|
@ -173,6 +174,7 @@ struct VideoConfig final
|
|||
struct
|
||||
{
|
||||
APIType api_type = APIType::Nothing;
|
||||
std::string DisplayName;
|
||||
|
||||
std::vector<std::string> Adapters; // for D3D
|
||||
std::vector<u32> AAModes;
|
||||
|
@ -222,9 +224,18 @@ struct VideoConfig final
|
|||
bool bSupportsSettingObjectNames = false;
|
||||
bool bSupportsPartialMultisampleResolve = false;
|
||||
bool bSupportsDynamicVertexLoader = false;
|
||||
bool bSupportsVSLinePointExpand = false;
|
||||
} backend_info;
|
||||
|
||||
// Utility
|
||||
bool UseVSForLinePointExpand() const
|
||||
{
|
||||
if (!backend_info.bSupportsVSLinePointExpand)
|
||||
return false;
|
||||
if (!backend_info.bSupportsGeometryShaders)
|
||||
return true;
|
||||
return bPreferVSForLinePointExpansion;
|
||||
}
|
||||
bool MultisamplingEnabled() const { return iMultisamples > 1; }
|
||||
bool ExclusiveFullscreenEnabled() const
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue