Merge pull request #12535 from iwubcode/vertexmanager_draw_refactor
VideoCommon: refactor drawing into its own function
This commit is contained in:
commit
c9715e7e7d
|
@ -615,8 +615,6 @@ void VertexManagerBase::Flush()
|
||||||
}
|
}
|
||||||
custom_pixel_shader = std::nullopt;
|
custom_pixel_shader = std::nullopt;
|
||||||
}
|
}
|
||||||
if (skip == true)
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now the vertices can be flushed to the GPU. Everything following the CommitBuffer() call
|
// Now the vertices can be flushed to the GPU. Everything following the CommitBuffer() call
|
||||||
|
@ -624,116 +622,47 @@ void VertexManagerBase::Flush()
|
||||||
const u32 num_indices = m_index_generator.GetIndexLen();
|
const u32 num_indices = m_index_generator.GetIndexLen();
|
||||||
if (num_indices == 0)
|
if (num_indices == 0)
|
||||||
return;
|
return;
|
||||||
u32 base_vertex, base_index;
|
|
||||||
CommitBuffer(m_index_generator.GetNumVerts(),
|
|
||||||
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).
|
// 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.
|
// Palette application does not use vertices, only a full-screen quad, so this is okay.
|
||||||
// Same with GPU texture decoding, which uses compute shaders.
|
// Same with GPU texture decoding, which uses compute shaders.
|
||||||
g_texture_cache->BindTextures(used_textures);
|
g_texture_cache->BindTextures(used_textures);
|
||||||
|
|
||||||
// Now we can upload uniforms, as nothing else will override them.
|
if (PerfQueryBase::ShouldEmulate())
|
||||||
geometry_shader_manager.SetConstants(m_current_primitive_type);
|
g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
|
||||||
pixel_shader_manager.SetConstants();
|
|
||||||
if (!custom_pixel_shader_uniforms.empty() &&
|
|
||||||
pixel_shader_manager.custom_constants.data() != custom_pixel_shader_uniforms.data())
|
|
||||||
{
|
|
||||||
pixel_shader_manager.custom_constants_dirty = true;
|
|
||||||
}
|
|
||||||
pixel_shader_manager.custom_constants = custom_pixel_shader_uniforms;
|
|
||||||
UploadUniforms();
|
|
||||||
|
|
||||||
// Update the pipeline, or compile one if needed.
|
if (!skip)
|
||||||
UpdatePipelineConfig();
|
|
||||||
UpdatePipelineObject();
|
|
||||||
if (m_current_pipeline_object)
|
|
||||||
{
|
{
|
||||||
const AbstractPipeline* current_pipeline = m_current_pipeline_object;
|
UpdatePipelineConfig();
|
||||||
if (!custom_pixel_shader_contents.shaders.empty())
|
UpdatePipelineObject();
|
||||||
|
if (m_current_pipeline_object)
|
||||||
{
|
{
|
||||||
CustomShaderInstance custom_shaders;
|
const AbstractPipeline* pipeline_object = m_current_pipeline_object;
|
||||||
custom_shaders.pixel_contents = std::move(custom_pixel_shader_contents);
|
if (!custom_pixel_shader_contents.shaders.empty())
|
||||||
|
|
||||||
switch (g_ActiveConfig.iShaderCompilationMode)
|
|
||||||
{
|
{
|
||||||
case ShaderCompilationMode::Synchronous:
|
if (const auto custom_pipeline =
|
||||||
case ShaderCompilationMode::AsynchronousSkipRendering:
|
GetCustomPipeline(custom_pixel_shader_contents, m_current_pipeline_config,
|
||||||
{
|
m_current_uber_pipeline_config, m_current_pipeline_object))
|
||||||
if (auto pipeline = m_custom_shader_cache->GetPipelineAsync(
|
|
||||||
m_current_pipeline_config, custom_shaders, m_current_pipeline_object->m_config))
|
|
||||||
{
|
{
|
||||||
current_pipeline = *pipeline;
|
pipeline_object = custom_pipeline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
RenderDrawCall(pixel_shader_manager, geometry_shader_manager, custom_pixel_shader_contents,
|
||||||
case ShaderCompilationMode::SynchronousUberShaders:
|
custom_pixel_shader_uniforms, m_current_primitive_type, pipeline_object);
|
||||||
{
|
|
||||||
// D3D has issues compiling large custom ubershaders
|
|
||||||
// use specialized shaders instead
|
|
||||||
if (g_ActiveConfig.backend_info.api_type == APIType::D3D)
|
|
||||||
{
|
|
||||||
if (auto pipeline = m_custom_shader_cache->GetPipelineAsync(
|
|
||||||
m_current_pipeline_config, custom_shaders, m_current_pipeline_object->m_config))
|
|
||||||
{
|
|
||||||
current_pipeline = *pipeline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (auto pipeline = m_custom_shader_cache->GetPipelineAsync(
|
|
||||||
m_current_uber_pipeline_config, custom_shaders,
|
|
||||||
m_current_pipeline_object->m_config))
|
|
||||||
{
|
|
||||||
current_pipeline = *pipeline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ShaderCompilationMode::AsynchronousUberShaders:
|
|
||||||
{
|
|
||||||
if (auto pipeline = m_custom_shader_cache->GetPipelineAsync(
|
|
||||||
m_current_pipeline_config, custom_shaders, m_current_pipeline_object->m_config))
|
|
||||||
{
|
|
||||||
current_pipeline = *pipeline;
|
|
||||||
}
|
|
||||||
else if (auto uber_pipeline = m_custom_shader_cache->GetPipelineAsync(
|
|
||||||
m_current_uber_pipeline_config, custom_shaders,
|
|
||||||
m_current_pipeline_object->m_config))
|
|
||||||
{
|
|
||||||
current_pipeline = *uber_pipeline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
g_gfx->SetPipeline(current_pipeline);
|
|
||||||
if (PerfQueryBase::ShouldEmulate())
|
|
||||||
g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
|
|
||||||
|
|
||||||
DrawCurrentBatch(base_index, num_indices, base_vertex);
|
|
||||||
INCSTAT(g_stats.this_frame.num_draw_calls);
|
|
||||||
|
|
||||||
if (PerfQueryBase::ShouldEmulate())
|
|
||||||
g_perf_query->DisableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
|
|
||||||
|
|
||||||
OnDraw();
|
|
||||||
|
|
||||||
// The EFB cache is now potentially stale.
|
|
||||||
g_framebuffer_manager->FlagPeekCacheAsOutOfDate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track the total emulated state draws
|
||||||
|
INCSTAT(g_stats.this_frame.num_draw_calls);
|
||||||
|
|
||||||
|
// Even if we skip the draw, emulated state should still be impacted
|
||||||
|
OnDraw();
|
||||||
|
|
||||||
|
if (PerfQueryBase::ShouldEmulate())
|
||||||
|
g_perf_query->DisableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
|
||||||
|
|
||||||
|
// The EFB cache is now potentially stale.
|
||||||
|
g_framebuffer_manager->FlagPeekCacheAsOutOfDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xfmem.numTexGen.numTexGens != bpmem.genMode.numtexgens)
|
if (xfmem.numTexGen.numTexGens != bpmem.genMode.numtexgens)
|
||||||
|
@ -1122,3 +1051,107 @@ void VertexManagerBase::NotifyCustomShaderCacheOfHostChange(const ShaderHostConf
|
||||||
m_custom_shader_cache->SetHostConfig(host_config);
|
m_custom_shader_cache->SetHostConfig(host_config);
|
||||||
m_custom_shader_cache->Reload();
|
m_custom_shader_cache->Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VertexManagerBase::RenderDrawCall(
|
||||||
|
PixelShaderManager& pixel_shader_manager, GeometryShaderManager& geometry_shader_manager,
|
||||||
|
const CustomPixelShaderContents& custom_pixel_shader_contents,
|
||||||
|
std::span<u8> custom_pixel_shader_uniforms, PrimitiveType primitive_type,
|
||||||
|
const AbstractPipeline* current_pipeline)
|
||||||
|
{
|
||||||
|
// Now we can upload uniforms, as nothing else will override them.
|
||||||
|
geometry_shader_manager.SetConstants(primitive_type);
|
||||||
|
pixel_shader_manager.SetConstants();
|
||||||
|
if (!custom_pixel_shader_uniforms.empty() &&
|
||||||
|
pixel_shader_manager.custom_constants.data() != custom_pixel_shader_uniforms.data())
|
||||||
|
{
|
||||||
|
pixel_shader_manager.custom_constants_dirty = true;
|
||||||
|
}
|
||||||
|
pixel_shader_manager.custom_constants = custom_pixel_shader_uniforms;
|
||||||
|
UploadUniforms();
|
||||||
|
|
||||||
|
g_gfx->SetPipeline(current_pipeline);
|
||||||
|
|
||||||
|
u32 base_vertex, base_index;
|
||||||
|
CommitBuffer(m_index_generator.GetNumVerts(),
|
||||||
|
VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride(),
|
||||||
|
m_index_generator.GetIndexLen(), &base_vertex, &base_index);
|
||||||
|
|
||||||
|
if (g_ActiveConfig.backend_info.api_type != APIType::D3D &&
|
||||||
|
g_ActiveConfig.UseVSForLinePointExpand() &&
|
||||||
|
(primitive_type == PrimitiveType::Points || 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawCurrentBatch(base_index, m_index_generator.GetIndexLen(), base_vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
const AbstractPipeline* VertexManagerBase::GetCustomPipeline(
|
||||||
|
const CustomPixelShaderContents& custom_pixel_shader_contents,
|
||||||
|
const VideoCommon::GXPipelineUid& current_pipeline_config,
|
||||||
|
const VideoCommon::GXUberPipelineUid& current_uber_pipeline_config,
|
||||||
|
const AbstractPipeline* current_pipeline) const
|
||||||
|
{
|
||||||
|
if (current_pipeline)
|
||||||
|
{
|
||||||
|
if (!custom_pixel_shader_contents.shaders.empty())
|
||||||
|
{
|
||||||
|
CustomShaderInstance custom_shaders;
|
||||||
|
custom_shaders.pixel_contents = custom_pixel_shader_contents;
|
||||||
|
switch (g_ActiveConfig.iShaderCompilationMode)
|
||||||
|
{
|
||||||
|
case ShaderCompilationMode::Synchronous:
|
||||||
|
case ShaderCompilationMode::AsynchronousSkipRendering:
|
||||||
|
{
|
||||||
|
if (auto pipeline = m_custom_shader_cache->GetPipelineAsync(
|
||||||
|
current_pipeline_config, custom_shaders, current_pipeline->m_config))
|
||||||
|
{
|
||||||
|
return *pipeline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ShaderCompilationMode::SynchronousUberShaders:
|
||||||
|
{
|
||||||
|
// D3D has issues compiling large custom ubershaders
|
||||||
|
// use specialized shaders instead
|
||||||
|
if (g_ActiveConfig.backend_info.api_type == APIType::D3D)
|
||||||
|
{
|
||||||
|
if (auto pipeline = m_custom_shader_cache->GetPipelineAsync(
|
||||||
|
current_pipeline_config, custom_shaders, current_pipeline->m_config))
|
||||||
|
{
|
||||||
|
return *pipeline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (auto pipeline = m_custom_shader_cache->GetPipelineAsync(
|
||||||
|
current_uber_pipeline_config, custom_shaders, current_pipeline->m_config))
|
||||||
|
{
|
||||||
|
return *pipeline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ShaderCompilationMode::AsynchronousUberShaders:
|
||||||
|
{
|
||||||
|
if (auto pipeline = m_custom_shader_cache->GetPipelineAsync(
|
||||||
|
current_pipeline_config, custom_shaders, current_pipeline->m_config))
|
||||||
|
{
|
||||||
|
return *pipeline;
|
||||||
|
}
|
||||||
|
else if (auto uber_pipeline = m_custom_shader_cache->GetPipelineAsync(
|
||||||
|
current_uber_pipeline_config, custom_shaders, current_pipeline->m_config))
|
||||||
|
{
|
||||||
|
return *uber_pipeline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
|
@ -15,9 +15,12 @@
|
||||||
#include "VideoCommon/ShaderCache.h"
|
#include "VideoCommon/ShaderCache.h"
|
||||||
#include "VideoCommon/VideoEvents.h"
|
#include "VideoCommon/VideoEvents.h"
|
||||||
|
|
||||||
|
struct CustomPixelShaderContents;
|
||||||
class CustomShaderCache;
|
class CustomShaderCache;
|
||||||
class DataReader;
|
class DataReader;
|
||||||
|
class GeometryShaderManager;
|
||||||
class NativeVertexFormat;
|
class NativeVertexFormat;
|
||||||
|
class PixelShaderManager;
|
||||||
class PointerWrap;
|
class PointerWrap;
|
||||||
struct PortableVertexDeclaration;
|
struct PortableVertexDeclaration;
|
||||||
|
|
||||||
|
@ -218,9 +221,20 @@ private:
|
||||||
// Minimum number of draws per command buffer when attempting to preempt a readback operation.
|
// Minimum number of draws per command buffer when attempting to preempt a readback operation.
|
||||||
static constexpr u32 MINIMUM_DRAW_CALLS_PER_COMMAND_BUFFER_FOR_READBACK = 10;
|
static constexpr u32 MINIMUM_DRAW_CALLS_PER_COMMAND_BUFFER_FOR_READBACK = 10;
|
||||||
|
|
||||||
|
void RenderDrawCall(PixelShaderManager& pixel_shader_manager,
|
||||||
|
GeometryShaderManager& geometry_shader_manager,
|
||||||
|
const CustomPixelShaderContents& custom_pixel_shader_contents,
|
||||||
|
std::span<u8> custom_pixel_shader_uniforms, PrimitiveType primitive_type,
|
||||||
|
const AbstractPipeline* current_pipeline);
|
||||||
void UpdatePipelineConfig();
|
void UpdatePipelineConfig();
|
||||||
void UpdatePipelineObject();
|
void UpdatePipelineObject();
|
||||||
|
|
||||||
|
const AbstractPipeline*
|
||||||
|
GetCustomPipeline(const CustomPixelShaderContents& custom_pixel_shader_contents,
|
||||||
|
const VideoCommon::GXPipelineUid& current_pipeline_config,
|
||||||
|
const VideoCommon::GXUberPipelineUid& current_uber_pipeline_confi,
|
||||||
|
const AbstractPipeline* current_pipeline) const;
|
||||||
|
|
||||||
bool m_is_flushed = true;
|
bool m_is_flushed = true;
|
||||||
FlushStatistics m_flush_statistics = {};
|
FlushStatistics m_flush_statistics = {};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue