Skip to content
Permalink
Browse files
Merge pull request #10890 from tellowkrinkle/VertexLineExpand
VideoCommon: Add vertex shader point/line expansion
  • Loading branch information
JMC47 committed Oct 23, 2022
2 parents 06bd0a9 + 1e9b6f8 commit cdcbe51
Show file tree
Hide file tree
Showing 36 changed files with 696 additions and 121 deletions.
@@ -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 @@ class AdvancedWidget final : public GraphicsWidget
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(&params[param_count], 1, D3D12_SHADER_VISIBILITY_VERTEX);
param_count++;
SetRootParamCBV(&params[param_count], 0, D3D12_SHADER_VISIBILITY_GEOMETRY);
if (g_ActiveConfig.UseVSForLinePointExpand())
SetRootParamCBV(&params[param_count], 2, D3D12_SHADER_VISIBILITY_VERTEX);
else
SetRootParamCBV(&params[param_count], 0, D3D12_SHADER_VISIBILITY_GEOMETRY);
param_count++;
SetRootParamTable(&params[param_count], &ranges[param_count], D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 3,
1, D3D12_SHADER_VISIBILITY_VERTEX);
param_count++;
SetRootParamConstant(&params[param_count], 2, 1, D3D12_SHADER_VISIBILITY_VERTEX);
SetRootParamConstant(&params[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 @@ class StateTracker
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 @@ class StateTracker
{
// 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 @@ explicit Backref(StateTracker* state_tracker) : state_tracker(state_tracker) {}
}
}

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 @@ static NSRange RangeOfBits(u32 value)
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 @@
// 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 @@ fragment float4 fbfetch_test(float4 in [[color(0), raster_order_group(0)]]) {
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::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++)

0 comments on commit cdcbe51

Please sign in to comment.