GPU/HW: Support using ROV for accurate blending
This commit is contained in:
parent
1006fa00da
commit
2a617c505a
|
@ -34,7 +34,7 @@ namespace GameDatabase {
|
|||
enum : u32
|
||||
{
|
||||
GAME_DATABASE_CACHE_SIGNATURE = 0x45434C48,
|
||||
GAME_DATABASE_CACHE_VERSION = 11,
|
||||
GAME_DATABASE_CACHE_VERSION = 12,
|
||||
};
|
||||
|
||||
static Entry* GetMutableEntry(std::string_view serial);
|
||||
|
@ -64,6 +64,7 @@ static constexpr const std::array<const char*, static_cast<u32>(GameDatabase::Tr
|
|||
"ForceSoftwareRenderer",
|
||||
"ForceSoftwareRendererForReadbacks",
|
||||
"ForceRoundTextureCoordinates",
|
||||
"ForceAccurateBlending",
|
||||
"ForceInterlacing",
|
||||
"DisableTrueColor",
|
||||
"DisableUpscaling",
|
||||
|
@ -492,6 +493,14 @@ void GameDatabase::Entry::ApplySettings(Settings& settings, bool display_osd_mes
|
|||
settings.gpu_force_round_texcoords = true;
|
||||
}
|
||||
|
||||
if (HasTrait(Trait::ForceAccurateBlending))
|
||||
{
|
||||
if (display_osd_messages && !settings.IsUsingSoftwareRenderer() && !settings.gpu_accurate_blending)
|
||||
APPEND_MESSAGE(ICON_FA_MAGIC, TRANSLATE_SV("GameDatabase", "Accurate blending enabled."));
|
||||
|
||||
settings.gpu_accurate_blending = true;
|
||||
}
|
||||
|
||||
if (HasTrait(Trait::ForceInterlacing))
|
||||
{
|
||||
if (display_osd_messages && settings.gpu_disable_interlacing)
|
||||
|
|
|
@ -32,6 +32,7 @@ enum class Trait : u32
|
|||
ForceSoftwareRenderer,
|
||||
ForceSoftwareRendererForReadbacks,
|
||||
ForceRoundUpscaledTextureCoordinates,
|
||||
ForceAccurateBlending,
|
||||
ForceInterlacing,
|
||||
DisableTrueColor,
|
||||
DisableUpscaling,
|
||||
|
|
|
@ -37,10 +37,29 @@ Log_SetChannel(GPU_HW);
|
|||
static constexpr GPUTexture::Format VRAM_RT_FORMAT = GPUTexture::Format::RGBA8;
|
||||
static constexpr GPUTexture::Format VRAM_DS_FORMAT = GPUTexture::Format::D16;
|
||||
static constexpr GPUTexture::Format VRAM_DS_DEPTH_FORMAT = GPUTexture::Format::D32F;
|
||||
static constexpr GPUTexture::Format VRAM_DS_EXTRACT_FORMAT = GPUTexture::Format::R32F;
|
||||
static constexpr GPUTexture::Format VRAM_DS_COLOR_FORMAT = GPUTexture::Format::R32F;
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
static u32 s_draw_number = 0;
|
||||
|
||||
static constexpr const std::array s_transparency_modes = {
|
||||
"HalfBackgroundPlusHalfForeground",
|
||||
"BackgroundPlusForeground",
|
||||
"BackgroundMinusForeground",
|
||||
"BackgroundPlusQuarterForeground",
|
||||
"Disabled",
|
||||
};
|
||||
|
||||
static constexpr const std::array s_batch_texture_modes = {
|
||||
"Palette4Bit", "Palette8Bit", "Direct16Bit", "Disabled",
|
||||
"SpritePalette4Bit", "SpritePalette8Bit", "SpriteDirect16Bit",
|
||||
};
|
||||
|
||||
static constexpr const std::array s_batch_render_modes = {
|
||||
"TransparencyDisabled", "TransparentAndOpaque", "OnlyOpaque", "OnlyTransparent", "ShaderBlend",
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/// Returns the distance between two rectangles.
|
||||
|
@ -370,9 +389,9 @@ void GPU_HW::UpdateSettings(const Settings& old_settings)
|
|||
const u8 resolution_scale = Truncate8(CalculateResolutionScale());
|
||||
const u8 multisamples = Truncate8(std::min<u32>(g_settings.gpu_multisamples, g_gpu_device->GetMaxMultisamples()));
|
||||
const bool clamp_uvs = ShouldClampUVs(m_texture_filtering) || ShouldClampUVs(m_sprite_texture_filtering);
|
||||
const bool framebuffer_changed =
|
||||
(m_resolution_scale != resolution_scale || m_multisamples != multisamples ||
|
||||
(static_cast<bool>(m_vram_depth_texture) != (g_settings.UsingPGXPDepthBuffer() || !m_supports_framebuffer_fetch)));
|
||||
const bool framebuffer_changed = (m_resolution_scale != resolution_scale || m_multisamples != multisamples ||
|
||||
g_settings.IsUsingAccurateBlending() != old_settings.IsUsingAccurateBlending() ||
|
||||
m_pgxp_depth_buffer != g_settings.UsingPGXPDepthBuffer());
|
||||
const bool shaders_changed =
|
||||
(m_resolution_scale != resolution_scale || m_multisamples != multisamples ||
|
||||
m_true_color != g_settings.gpu_true_color || g_settings.gpu_debanding != old_settings.gpu_debanding ||
|
||||
|
@ -380,6 +399,7 @@ void GPU_HW::UpdateSettings(const Settings& old_settings)
|
|||
(resolution_scale > 1 && g_settings.gpu_scaled_dithering != old_settings.gpu_scaled_dithering) ||
|
||||
(resolution_scale > 1 && g_settings.gpu_texture_filter == GPUTextureFilter::Nearest &&
|
||||
g_settings.gpu_force_round_texcoords != old_settings.gpu_force_round_texcoords) ||
|
||||
g_settings.IsUsingAccurateBlending() != old_settings.IsUsingAccurateBlending() ||
|
||||
m_texture_filtering != g_settings.gpu_texture_filter ||
|
||||
m_sprite_texture_filtering != g_settings.gpu_sprite_texture_filter || m_clamp_uvs != clamp_uvs ||
|
||||
(resolution_scale > 1 && (g_settings.gpu_downsample_mode != old_settings.gpu_downsample_mode ||
|
||||
|
@ -442,24 +462,16 @@ void GPU_HW::UpdateSettings(const Settings& old_settings)
|
|||
m_allow_sprite_mode = ShouldAllowSpriteMode(resolution_scale, m_texture_filtering, m_sprite_texture_filtering);
|
||||
m_batch.sprite_mode = (m_allow_sprite_mode && m_batch.sprite_mode);
|
||||
|
||||
CheckSettings();
|
||||
|
||||
if (m_pgxp_depth_buffer != g_settings.UsingPGXPDepthBuffer())
|
||||
const bool depth_buffer_changed = (m_pgxp_depth_buffer != g_settings.UsingPGXPDepthBuffer());
|
||||
if (depth_buffer_changed)
|
||||
{
|
||||
m_pgxp_depth_buffer = g_settings.UsingPGXPDepthBuffer();
|
||||
m_batch.use_depth_buffer = false;
|
||||
m_depth_was_copied = false;
|
||||
|
||||
// might be null when resizing
|
||||
if (m_vram_depth_texture)
|
||||
{
|
||||
if (m_pgxp_depth_buffer)
|
||||
ClearDepthBuffer();
|
||||
else
|
||||
UpdateDepthBufferFromMaskBit();
|
||||
}
|
||||
}
|
||||
|
||||
CheckSettings();
|
||||
|
||||
UpdateSoftwareRenderer(true);
|
||||
|
||||
PrintSettingsToLog();
|
||||
|
@ -489,9 +501,17 @@ void GPU_HW::UpdateSettings(const Settings& old_settings)
|
|||
UpdateDownsamplingLevels();
|
||||
RestoreDeviceContext();
|
||||
UpdateVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT, g_vram, false, false);
|
||||
UpdateDepthBufferFromMaskBit();
|
||||
if (m_write_mask_as_depth)
|
||||
UpdateDepthBufferFromMaskBit();
|
||||
UpdateDisplay();
|
||||
}
|
||||
else if (m_vram_depth_texture && depth_buffer_changed)
|
||||
{
|
||||
if (m_pgxp_depth_buffer)
|
||||
ClearDepthBuffer();
|
||||
else if (m_write_mask_as_depth)
|
||||
UpdateDepthBufferFromMaskBit();
|
||||
}
|
||||
|
||||
if (g_settings.gpu_downsample_mode != old_settings.gpu_downsample_mode ||
|
||||
(g_settings.gpu_downsample_mode == GPUDownsampleMode::Box &&
|
||||
|
@ -536,6 +556,37 @@ void GPU_HW::CheckSettings()
|
|||
m_allow_sprite_mode = ShouldAllowSpriteMode(m_resolution_scale, m_texture_filtering, m_sprite_texture_filtering);
|
||||
}
|
||||
|
||||
if (g_settings.IsUsingAccurateBlending() && !m_supports_framebuffer_fetch && !features.feedback_loops &&
|
||||
!features.raster_order_views)
|
||||
{
|
||||
// m_allow_shader_blend/m_prefer_shader_blend will be cleared in pipeline compile.
|
||||
Host::AddIconOSDMessage(
|
||||
"AccurateBlendingUnsupported", ICON_FA_PAINT_BRUSH,
|
||||
TRANSLATE_STR("GPU_HW", "Accurate blending is not supported by your current GPU.\nIt requires framebuffer fetch, "
|
||||
"feedback loops, or rasterizer order views."),
|
||||
Host::OSD_WARNING_DURATION);
|
||||
}
|
||||
else if (IsUsingMultisampling() && !features.framebuffer_fetch &&
|
||||
((g_settings.IsUsingAccurateBlending() && features.raster_order_views) ||
|
||||
(m_pgxp_depth_buffer && features.raster_order_views && !features.feedback_loops)))
|
||||
{
|
||||
Host::AddIconOSDMessage(
|
||||
"AccurateBlendingUnsupported", ICON_FA_PAINT_BRUSH,
|
||||
TRANSLATE_STR("GPU_HW", "Multisample anti-aliasing is not supported when using ROV blending."),
|
||||
Host::OSD_WARNING_DURATION);
|
||||
m_multisamples = 1;
|
||||
}
|
||||
|
||||
if (m_pgxp_depth_buffer && !features.feedback_loops && !features.framebuffer_fetch && !features.raster_order_views)
|
||||
{
|
||||
Host::AddIconOSDMessage(
|
||||
"AccurateBlendingUnsupported", ICON_FA_PAINT_BRUSH,
|
||||
TRANSLATE_STR("GPU_HW", "PGXP depth buffer is not supported by your current GPU or renderer.\nIt requires "
|
||||
"framebuffer fetch, feedback loops, or rasterizer order views."),
|
||||
Host::OSD_WARNING_DURATION);
|
||||
m_pgxp_depth_buffer = false;
|
||||
}
|
||||
|
||||
if (!features.noperspective_interpolation && !ShouldDisableColorPerspective())
|
||||
WARNING_LOG("Disable color perspective not supported, but should be used.");
|
||||
|
||||
|
@ -734,16 +785,11 @@ void GPU_HW::PrintSettingsToLog()
|
|||
INFO_LOG("Separate sprite shaders: {}", m_allow_sprite_mode ? "YES" : "NO");
|
||||
}
|
||||
|
||||
bool GPU_HW::NeedsDepthBuffer() const
|
||||
{
|
||||
// PGXP depth, or no fbfetch, which means we need depth for the mask bit.
|
||||
return (m_pgxp_depth_buffer || !m_supports_framebuffer_fetch);
|
||||
}
|
||||
|
||||
GPUTexture::Format GPU_HW::GetDepthBufferFormat() const
|
||||
{
|
||||
// Use 32-bit depth for PGXP depth buffer, otherwise 16-bit for mask bit.
|
||||
return m_pgxp_depth_buffer ? VRAM_DS_DEPTH_FORMAT : VRAM_DS_FORMAT;
|
||||
return m_pgxp_depth_buffer ? (m_use_rov_for_shader_blend ? VRAM_DS_COLOR_FORMAT : VRAM_DS_DEPTH_FORMAT) :
|
||||
VRAM_DS_FORMAT;
|
||||
}
|
||||
|
||||
bool GPU_HW::CreateBuffers()
|
||||
|
@ -754,22 +800,25 @@ bool GPU_HW::CreateBuffers()
|
|||
const u32 texture_width = VRAM_WIDTH * m_resolution_scale;
|
||||
const u32 texture_height = VRAM_HEIGHT * m_resolution_scale;
|
||||
const u8 samples = static_cast<u8>(m_multisamples);
|
||||
const bool needs_depth_buffer = NeedsDepthBuffer();
|
||||
DEV_LOG("Depth buffer is {}needed in {}", needs_depth_buffer ? "" : "NOT ",
|
||||
GPUTexture::GetFormatName(GetDepthBufferFormat()));
|
||||
const bool needs_depth_buffer = m_write_mask_as_depth || m_pgxp_depth_buffer;
|
||||
|
||||
// Needed for Metal resolve.
|
||||
const GPUTexture::Type read_texture_type = (g_gpu_device->GetRenderAPI() == RenderAPI::Metal && m_multisamples > 1) ?
|
||||
GPUTexture::Type::RWTexture :
|
||||
GPUTexture::Type::Texture;
|
||||
const GPUTexture::Type vram_texture_type =
|
||||
m_use_rov_for_shader_blend ? GPUTexture::Type::RWTexture : GPUTexture::Type::RenderTarget;
|
||||
const GPUTexture::Type depth_texture_type =
|
||||
m_use_rov_for_shader_blend ? GPUTexture::Type::RWTexture : GPUTexture::Type::DepthStencil;
|
||||
|
||||
if (!(m_vram_texture = g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, samples,
|
||||
GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)) ||
|
||||
if (!(m_vram_texture = g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, samples, vram_texture_type,
|
||||
VRAM_RT_FORMAT)) ||
|
||||
(needs_depth_buffer &&
|
||||
(!(m_vram_depth_texture = g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, samples,
|
||||
GPUTexture::Type::DepthStencil, GetDepthBufferFormat())) ||
|
||||
!(m_vram_depth_copy_texture = g_gpu_device->FetchTexture(
|
||||
texture_width, texture_height, 1, 1, samples, GPUTexture::Type::RenderTarget, VRAM_DS_EXTRACT_FORMAT)))) ||
|
||||
!(m_vram_depth_texture = g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, samples,
|
||||
depth_texture_type, GetDepthBufferFormat()))) ||
|
||||
(m_pgxp_depth_buffer && !(m_vram_depth_copy_texture =
|
||||
g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, samples,
|
||||
GPUTexture::Type::RenderTarget, VRAM_DS_COLOR_FORMAT))) ||
|
||||
!(m_vram_read_texture =
|
||||
g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, 1, read_texture_type, VRAM_RT_FORMAT)) ||
|
||||
!(m_vram_readback_texture = g_gpu_device->FetchTexture(VRAM_WIDTH / 2, VRAM_HEIGHT, 1, 1, 1,
|
||||
|
@ -826,15 +875,43 @@ void GPU_HW::ClearFramebuffer()
|
|||
{
|
||||
g_gpu_device->ClearRenderTarget(m_vram_texture.get(), 0);
|
||||
if (m_vram_depth_texture)
|
||||
g_gpu_device->ClearDepth(m_vram_depth_texture.get(), m_pgxp_depth_buffer ? 1.0f : 0.0f);
|
||||
{
|
||||
if (m_use_rov_for_shader_blend)
|
||||
g_gpu_device->ClearRenderTarget(m_vram_depth_texture.get(), 0xFF);
|
||||
else
|
||||
g_gpu_device->ClearDepth(m_vram_depth_texture.get(), m_pgxp_depth_buffer ? 1.0f : 0.0f);
|
||||
}
|
||||
ClearVRAMDirtyRectangle();
|
||||
m_last_depth_z = 1.0f;
|
||||
}
|
||||
|
||||
void GPU_HW::SetVRAMRenderTarget()
|
||||
{
|
||||
g_gpu_device->SetRenderTarget(m_vram_texture.get(), m_vram_depth_texture.get(),
|
||||
m_allow_shader_blend ? GPUPipeline::ColorFeedbackLoop : GPUPipeline::NoRenderPassFlags);
|
||||
if (m_use_rov_for_shader_blend)
|
||||
{
|
||||
GPUTexture* rts[2] = {m_vram_texture.get(), m_vram_depth_texture.get()};
|
||||
const u32 num_rts = m_pgxp_depth_buffer ? 2 : 1;
|
||||
g_gpu_device->SetRenderTargets(
|
||||
rts, num_rts, nullptr, m_rov_active ? GPUPipeline::BindRenderTargetsAsImages : GPUPipeline::NoRenderPassFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_gpu_device->SetRenderTarget(
|
||||
m_vram_texture.get(), m_vram_depth_texture.get(),
|
||||
((m_allow_shader_blend && !m_supports_framebuffer_fetch && !m_use_rov_for_shader_blend) ?
|
||||
GPUPipeline::ColorFeedbackLoop :
|
||||
GPUPipeline::NoRenderPassFlags));
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_HW::DeactivateROV()
|
||||
{
|
||||
if (!m_rov_active)
|
||||
return;
|
||||
|
||||
GL_INS("Deactivating ROV.");
|
||||
m_rov_active = false;
|
||||
SetVRAMRenderTarget();
|
||||
}
|
||||
|
||||
void GPU_HW::DestroyBuffers()
|
||||
|
@ -863,42 +940,73 @@ bool GPU_HW::CompilePipelines(Error* error)
|
|||
const bool per_sample_shading = g_settings.gpu_per_sample_shading && features.per_sample_shading;
|
||||
const bool force_round_texcoords = (m_resolution_scale > 1 && m_texture_filtering == GPUTextureFilter::Nearest &&
|
||||
g_settings.gpu_force_round_texcoords);
|
||||
const bool needs_depth_buffer = NeedsDepthBuffer();
|
||||
const bool write_mask_as_depth = (!m_pgxp_depth_buffer && needs_depth_buffer);
|
||||
|
||||
// Determine when to use shader blending.
|
||||
// FBFetch is free, we need it for filtering without DSB, or when accurate blending is forced.
|
||||
// But, don't bother with accurate blending if true colour is on. The result will be the same.
|
||||
// Prefer ROV over barriers/feedback loops without FBFetch, it'll be faster.
|
||||
// Abuse the depth buffer for the mask bit when it's free (FBFetch), or PGXP depth buffering is enabled.
|
||||
m_allow_shader_blend = (features.feedback_loops || features.raster_order_views || features.framebuffer_fetch) &&
|
||||
(m_pgxp_depth_buffer || g_settings.gpu_accurate_blending ||
|
||||
(!m_supports_dual_source_blend && (IsBlendedTextureFiltering(m_texture_filtering) ||
|
||||
IsBlendedTextureFiltering(m_sprite_texture_filtering))));
|
||||
m_prefer_shader_blend = (m_allow_shader_blend && g_settings.gpu_accurate_blending && !g_settings.gpu_true_color);
|
||||
m_use_rov_for_shader_blend = (m_allow_shader_blend && !features.framebuffer_fetch && features.raster_order_views &&
|
||||
(m_prefer_shader_blend || !features.feedback_loops));
|
||||
m_write_mask_as_depth = (!m_pgxp_depth_buffer && !features.framebuffer_fetch && !m_prefer_shader_blend);
|
||||
|
||||
// ROV doesn't support MSAA in DirectX.
|
||||
Assert(!m_use_rov_for_shader_blend || !IsUsingMultisampling());
|
||||
|
||||
const bool needs_depth_buffer = (m_pgxp_depth_buffer || m_write_mask_as_depth);
|
||||
const bool needs_rov_depth = (m_pgxp_depth_buffer && m_use_rov_for_shader_blend);
|
||||
const bool needs_real_depth_buffer = (needs_depth_buffer && !needs_rov_depth);
|
||||
const bool needs_feedback_loop = (m_allow_shader_blend && features.feedback_loops && !m_use_rov_for_shader_blend);
|
||||
const GPUTexture::Format depth_buffer_format =
|
||||
needs_depth_buffer ? GetDepthBufferFormat() : GPUTexture::Format::Unknown;
|
||||
m_allow_shader_blend = (features.feedback_loops && (m_pgxp_depth_buffer || !needs_depth_buffer));
|
||||
|
||||
// Logging in case something goes wrong.
|
||||
INFO_LOG("Shader blending allowed: {}", m_allow_shader_blend ? "YES" : "NO");
|
||||
INFO_LOG("Shader blending preferred: {}", m_prefer_shader_blend ? "YES" : "NO");
|
||||
INFO_LOG("Use ROV for shader blending: {}", m_use_rov_for_shader_blend ? "YES" : "NO");
|
||||
INFO_LOG("Write mask as depth: {}", m_write_mask_as_depth ? "YES" : "NO");
|
||||
INFO_LOG("Depth buffer is {}needed in {}.", needs_depth_buffer ? "" : "NOT ",
|
||||
GPUTexture::GetFormatName(GetDepthBufferFormat()));
|
||||
INFO_LOG("Using ROV depth: {}", needs_rov_depth ? "YES" : "NO");
|
||||
INFO_LOG("Using real depth buffer: {}", needs_real_depth_buffer ? "YES" : "NO");
|
||||
INFO_LOG("Using feedback loops: {}", needs_feedback_loop ? "YES" : "NO");
|
||||
|
||||
// Start generating shaders.
|
||||
GPU_HW_ShaderGen shadergen(g_gpu_device->GetRenderAPI(), m_resolution_scale, m_multisamples, per_sample_shading,
|
||||
m_true_color, (m_resolution_scale > 1 && g_settings.gpu_scaled_dithering),
|
||||
write_mask_as_depth, ShouldDisableColorPerspective(), m_supports_dual_source_blend,
|
||||
m_write_mask_as_depth, ShouldDisableColorPerspective(), m_supports_dual_source_blend,
|
||||
m_supports_framebuffer_fetch, g_settings.gpu_true_color && g_settings.gpu_debanding);
|
||||
|
||||
const u32 active_texture_modes =
|
||||
m_allow_sprite_mode ? NUM_TEXTURE_MODES :
|
||||
(NUM_TEXTURE_MODES - (NUM_TEXTURE_MODES - static_cast<u32>(BatchTextureMode::SpriteStart)));
|
||||
const u32 total_pipelines =
|
||||
(m_allow_sprite_mode ? 5 : 3) + // vertex shaders
|
||||
(active_texture_modes * 5 * 9 * 2 * 2 * 2) + // fragment shaders
|
||||
((m_pgxp_depth_buffer ? 2 : 1) * 5 * 5 * active_texture_modes * 2 * 2 * 2) + // batch pipelines
|
||||
((m_wireframe_mode != GPUWireframeMode::Disabled) ? 1 : 0) + // wireframe
|
||||
1 + // fullscreen quad VS
|
||||
(2 * 2) + // vram fill
|
||||
(1 + BoolToUInt32(write_mask_as_depth)) + // vram copy
|
||||
(1 + BoolToUInt32(write_mask_as_depth)) + // vram write
|
||||
1 + // vram write replacement
|
||||
(needs_depth_buffer ? 1 : 0) + // mask -> depth
|
||||
1 + // vram read
|
||||
2 + // extract/display
|
||||
((m_downsample_mode != GPUDownsampleMode::Disabled) ? 1 : 0); // downsample
|
||||
(m_allow_sprite_mode ? 5 : 3) + // vertex shaders
|
||||
(active_texture_modes * 5 * 9 * 2 * 2 * 2 * (1 + BoolToUInt32(needs_rov_depth))) + // fragment shaders
|
||||
((m_pgxp_depth_buffer ? 2 : 1) * 5 * 5 * active_texture_modes * 2 * 2 * 2) + // batch pipelines
|
||||
((m_wireframe_mode != GPUWireframeMode::Disabled) ? 1 : 0) + // wireframe
|
||||
1 + // fullscreen quad VS
|
||||
(2 * 2) + // vram fill
|
||||
(1 + BoolToUInt32(m_write_mask_as_depth)) + // vram copy
|
||||
(1 + BoolToUInt32(m_write_mask_as_depth)) + // vram write
|
||||
1 + // vram write replacement
|
||||
(m_write_mask_as_depth ? 1 : 0) + // mask -> depth
|
||||
1 + // vram read
|
||||
2 + // extract/display
|
||||
((m_downsample_mode != GPUDownsampleMode::Disabled) ? 1 : 0); // downsample
|
||||
|
||||
ShaderCompileProgressTracker progress("Compiling Pipelines", total_pipelines);
|
||||
|
||||
// vertex shaders - [textured/palette/sprite]
|
||||
// fragment shaders - [render_mode][transparency_mode][texture_mode][check_mask][dithering][interlacing]
|
||||
// fragment shaders - [depth_test][render_mode][transparency_mode][texture_mode][check_mask][dithering][interlacing]
|
||||
static constexpr auto destroy_shader = [](std::unique_ptr<GPUShader>& s) { s.reset(); };
|
||||
DimensionalArray<std::unique_ptr<GPUShader>, 2, 2, 2> batch_vertex_shaders{};
|
||||
DimensionalArray<std::unique_ptr<GPUShader>, 2, 2, 2, NUM_TEXTURE_MODES, 5, 5> batch_fragment_shaders{};
|
||||
DimensionalArray<std::unique_ptr<GPUShader>, 2, 2, 2, NUM_TEXTURE_MODES, 5, 5, 2> batch_fragment_shaders{};
|
||||
ScopedGuard batch_shader_guard([&batch_vertex_shaders, &batch_fragment_shaders]() {
|
||||
batch_vertex_shaders.enumerate(destroy_shader);
|
||||
batch_fragment_shaders.enumerate(destroy_shader);
|
||||
|
@ -924,56 +1032,71 @@ bool GPU_HW::CompilePipelines(Error* error)
|
|||
}
|
||||
}
|
||||
|
||||
for (u8 render_mode = 0; render_mode < 5; render_mode++)
|
||||
for (u8 depth_test = 0; depth_test < 2; depth_test++)
|
||||
{
|
||||
for (u8 transparency_mode = 0; transparency_mode < 5; transparency_mode++)
|
||||
if (depth_test && !needs_rov_depth)
|
||||
{
|
||||
if (
|
||||
// Can't generate shader blending.
|
||||
((render_mode == static_cast<u8>(BatchRenderMode::ShaderBlend) && !features.feedback_loops) ||
|
||||
(render_mode != static_cast<u8>(BatchRenderMode::ShaderBlend) &&
|
||||
transparency_mode != static_cast<u8>(GPUTransparencyMode::Disabled))) ||
|
||||
// Don't need multipass shaders.
|
||||
(m_supports_framebuffer_fetch && (render_mode == static_cast<u8>(BatchRenderMode::OnlyOpaque) ||
|
||||
render_mode == static_cast<u8>(BatchRenderMode::OnlyTransparent))))
|
||||
{
|
||||
progress.Increment(active_texture_modes * 2 * 2 * 2);
|
||||
continue;
|
||||
}
|
||||
// Don't need to do depth testing in the shader.
|
||||
continue;
|
||||
}
|
||||
|
||||
for (u8 texture_mode = 0; texture_mode < active_texture_modes; texture_mode++)
|
||||
for (u8 render_mode = 0; render_mode < 5; render_mode++)
|
||||
{
|
||||
for (u8 transparency_mode = 0; transparency_mode < 5; transparency_mode++)
|
||||
{
|
||||
for (u8 check_mask = 0; check_mask < 2; check_mask++)
|
||||
if (
|
||||
// Can't generate shader blending.
|
||||
((render_mode == static_cast<u8>(BatchRenderMode::ShaderBlend) && !m_allow_shader_blend) ||
|
||||
(render_mode != static_cast<u8>(BatchRenderMode::ShaderBlend) &&
|
||||
transparency_mode != static_cast<u8>(GPUTransparencyMode::Disabled))) ||
|
||||
// Don't need multipass shaders if we're preferring shader blend or have (free) FBFetch.
|
||||
((m_supports_framebuffer_fetch || m_prefer_shader_blend) &&
|
||||
(render_mode == static_cast<u8>(BatchRenderMode::OnlyOpaque) ||
|
||||
render_mode == static_cast<u8>(BatchRenderMode::OnlyTransparent))) ||
|
||||
// If using ROV depth, we only draw with shader blending.
|
||||
(needs_rov_depth && render_mode != static_cast<u8>(BatchRenderMode::ShaderBlend)))
|
||||
{
|
||||
if (check_mask && render_mode != static_cast<u8>(BatchRenderMode::ShaderBlend))
|
||||
{
|
||||
// mask bit testing is only valid with shader blending.
|
||||
progress.Increment(2 * 2);
|
||||
continue;
|
||||
}
|
||||
progress.Increment(active_texture_modes * 2 * 2 * 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (u8 dithering = 0; dithering < 2; dithering++)
|
||||
for (u8 texture_mode = 0; texture_mode < active_texture_modes; texture_mode++)
|
||||
{
|
||||
for (u8 check_mask = 0; check_mask < 2; check_mask++)
|
||||
{
|
||||
for (u8 interlacing = 0; interlacing < 2; interlacing++)
|
||||
if (check_mask && render_mode != static_cast<u8>(BatchRenderMode::ShaderBlend))
|
||||
{
|
||||
const bool sprite = (static_cast<BatchTextureMode>(texture_mode) >= BatchTextureMode::SpriteStart);
|
||||
const bool uv_limits = ShouldClampUVs(sprite ? m_sprite_texture_filtering : m_texture_filtering);
|
||||
const BatchTextureMode shader_texmode = static_cast<BatchTextureMode>(
|
||||
texture_mode - (sprite ? static_cast<u8>(BatchTextureMode::SpriteStart) : 0));
|
||||
const std::string fs = shadergen.GenerateBatchFragmentShader(
|
||||
static_cast<BatchRenderMode>(render_mode), static_cast<GPUTransparencyMode>(transparency_mode),
|
||||
shader_texmode, sprite ? m_sprite_texture_filtering : m_texture_filtering, uv_limits,
|
||||
!sprite && force_round_texcoords, ConvertToBoolUnchecked(dithering),
|
||||
ConvertToBoolUnchecked(interlacing), ConvertToBoolUnchecked(check_mask));
|
||||
// mask bit testing is only valid with shader blending.
|
||||
progress.Increment(2 * 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(batch_fragment_shaders[render_mode][transparency_mode][texture_mode][check_mask][dithering]
|
||||
[interlacing] = g_gpu_device->CreateShader(
|
||||
GPUShaderStage::Fragment, shadergen.GetLanguage(), fs, error)))
|
||||
for (u8 dithering = 0; dithering < 2; dithering++)
|
||||
{
|
||||
for (u8 interlacing = 0; interlacing < 2; interlacing++)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const bool sprite = (static_cast<BatchTextureMode>(texture_mode) >= BatchTextureMode::SpriteStart);
|
||||
const bool uv_limits = ShouldClampUVs(sprite ? m_sprite_texture_filtering : m_texture_filtering);
|
||||
const BatchTextureMode shader_texmode = static_cast<BatchTextureMode>(
|
||||
texture_mode - (sprite ? static_cast<u8>(BatchTextureMode::SpriteStart) : 0));
|
||||
const bool use_rov =
|
||||
(render_mode == static_cast<u8>(BatchRenderMode::ShaderBlend) && m_use_rov_for_shader_blend);
|
||||
const std::string fs = shadergen.GenerateBatchFragmentShader(
|
||||
static_cast<BatchRenderMode>(render_mode), static_cast<GPUTransparencyMode>(transparency_mode),
|
||||
shader_texmode, sprite ? m_sprite_texture_filtering : m_texture_filtering, uv_limits,
|
||||
!sprite && force_round_texcoords, ConvertToBoolUnchecked(dithering),
|
||||
ConvertToBoolUnchecked(interlacing), ConvertToBoolUnchecked(check_mask), use_rov, needs_rov_depth,
|
||||
(depth_test != 0));
|
||||
|
||||
progress.Increment();
|
||||
if (!(batch_fragment_shaders[depth_test][render_mode][transparency_mode][texture_mode][check_mask]
|
||||
[dithering][interlacing] = g_gpu_device->CreateShader(
|
||||
GPUShaderStage::Fragment, shadergen.GetLanguage(), fs, error)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
progress.Increment();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1003,10 +1126,8 @@ bool GPU_HW::CompilePipelines(Error* error)
|
|||
plconfig.rasterization = GPUPipeline::RasterizationState::GetNoCullState();
|
||||
plconfig.primitive = GPUPipeline::Primitive::Triangles;
|
||||
plconfig.geometry_shader = nullptr;
|
||||
plconfig.SetTargetFormats(VRAM_RT_FORMAT, depth_buffer_format);
|
||||
plconfig.samples = m_multisamples;
|
||||
plconfig.per_sample_shading = per_sample_shading;
|
||||
plconfig.render_pass_flags = m_allow_shader_blend ? GPUPipeline::ColorFeedbackLoop : GPUPipeline::NoRenderPassFlags;
|
||||
plconfig.depth = GPUPipeline::DepthState::GetNoTestsState();
|
||||
|
||||
// [depth_test][transparency_mode][render_mode][texture_mode][dithering][interlacing][check_mask]
|
||||
|
@ -1026,8 +1147,11 @@ bool GPU_HW::CompilePipelines(Error* error)
|
|||
// Can't generate shader blending.
|
||||
(render_mode == static_cast<u8>(BatchRenderMode::ShaderBlend) && !m_allow_shader_blend) ||
|
||||
// Don't need multipass shaders.
|
||||
(m_supports_framebuffer_fetch && (render_mode == static_cast<u8>(BatchRenderMode::OnlyOpaque) ||
|
||||
render_mode == static_cast<u8>(BatchRenderMode::OnlyTransparent))))
|
||||
((m_supports_framebuffer_fetch || m_prefer_shader_blend) &&
|
||||
(render_mode == static_cast<u8>(BatchRenderMode::OnlyOpaque) ||
|
||||
render_mode == static_cast<u8>(BatchRenderMode::OnlyTransparent))) ||
|
||||
// If using ROV depth, we only draw with shader blending.
|
||||
(needs_rov_depth && render_mode != static_cast<u8>(BatchRenderMode::ShaderBlend)))
|
||||
{
|
||||
progress.Increment(9 * 2 * 2 * 2);
|
||||
continue;
|
||||
|
@ -1049,12 +1173,12 @@ bool GPU_HW::CompilePipelines(Error* error)
|
|||
static_cast<BatchTextureMode>(texture_mode) == BatchTextureMode::SpritePalette8Bit);
|
||||
const bool sprite = (static_cast<BatchTextureMode>(texture_mode) >= BatchTextureMode::SpriteStart);
|
||||
const bool uv_limits = ShouldClampUVs(sprite ? m_sprite_texture_filtering : m_texture_filtering);
|
||||
const bool use_rov =
|
||||
(render_mode == static_cast<u8>(BatchRenderMode::ShaderBlend) && m_use_rov_for_shader_blend);
|
||||
const bool use_shader_blending =
|
||||
(render_mode == static_cast<u8>(BatchRenderMode::ShaderBlend) &&
|
||||
((textured &&
|
||||
NeedsShaderBlending(static_cast<GPUTransparencyMode>(transparency_mode), (check_mask != 0))) ||
|
||||
check_mask));
|
||||
|
||||
(use_rov || ((render_mode == static_cast<u8>(BatchRenderMode::ShaderBlend) &&
|
||||
NeedsShaderBlending(static_cast<GPUTransparencyMode>(transparency_mode),
|
||||
static_cast<BatchTextureMode>(texture_mode), (check_mask != 0)))));
|
||||
plconfig.input_layout.vertex_attributes =
|
||||
textured ?
|
||||
(uv_limits ? std::span<const GPUPipeline::VertexAttribute>(
|
||||
|
@ -1066,14 +1190,14 @@ bool GPU_HW::CompilePipelines(Error* error)
|
|||
plconfig.vertex_shader =
|
||||
batch_vertex_shaders[BoolToUInt8(textured)][BoolToUInt8(palette)][BoolToUInt8(sprite)].get();
|
||||
plconfig.fragment_shader =
|
||||
batch_fragment_shaders[render_mode]
|
||||
batch_fragment_shaders[BoolToUInt8(depth_test && needs_rov_depth)][render_mode]
|
||||
[use_shader_blending ? transparency_mode :
|
||||
static_cast<u8>(GPUTransparencyMode::Disabled)]
|
||||
[texture_mode][use_shader_blending ? check_mask : 0][dithering][interlacing]
|
||||
.get();
|
||||
Assert(plconfig.vertex_shader && plconfig.fragment_shader);
|
||||
|
||||
if (needs_depth_buffer)
|
||||
if (needs_real_depth_buffer)
|
||||
{
|
||||
plconfig.depth.depth_test =
|
||||
m_pgxp_depth_buffer ?
|
||||
|
@ -1086,14 +1210,25 @@ bool GPU_HW::CompilePipelines(Error* error)
|
|||
(depth_test && transparency_mode == static_cast<u8>(GPUTransparencyMode::Disabled));
|
||||
}
|
||||
|
||||
plconfig.SetTargetFormats(use_rov ? GPUTexture::Format::Unknown : VRAM_RT_FORMAT,
|
||||
needs_rov_depth ? GPUTexture::Format::Unknown : depth_buffer_format);
|
||||
plconfig.color_formats[1] = needs_rov_depth ? VRAM_DS_COLOR_FORMAT : GPUTexture::Format::Unknown;
|
||||
plconfig.render_pass_flags =
|
||||
use_rov ? GPUPipeline::BindRenderTargetsAsImages :
|
||||
(needs_feedback_loop ? GPUPipeline::ColorFeedbackLoop : GPUPipeline::NoRenderPassFlags);
|
||||
|
||||
plconfig.blend = GPUPipeline::BlendState::GetNoBlendingState();
|
||||
|
||||
if (!use_shader_blending &&
|
||||
((static_cast<GPUTransparencyMode>(transparency_mode) != GPUTransparencyMode::Disabled &&
|
||||
(static_cast<BatchRenderMode>(render_mode) != BatchRenderMode::TransparencyDisabled &&
|
||||
static_cast<BatchRenderMode>(render_mode) != BatchRenderMode::OnlyOpaque)) ||
|
||||
(textured &&
|
||||
IsBlendedTextureFiltering(sprite ? m_sprite_texture_filtering : m_texture_filtering))))
|
||||
if (use_rov)
|
||||
{
|
||||
plconfig.blend.write_mask = 0;
|
||||
}
|
||||
else if (!use_shader_blending &&
|
||||
((static_cast<GPUTransparencyMode>(transparency_mode) != GPUTransparencyMode::Disabled &&
|
||||
(static_cast<BatchRenderMode>(render_mode) != BatchRenderMode::TransparencyDisabled &&
|
||||
static_cast<BatchRenderMode>(render_mode) != BatchRenderMode::OnlyOpaque)) ||
|
||||
(textured &&
|
||||
IsBlendedTextureFiltering(sprite ? m_sprite_texture_filtering : m_texture_filtering))))
|
||||
{
|
||||
plconfig.blend.enable = true;
|
||||
plconfig.blend.src_alpha_blend = GPUPipeline::BlendFunc::One;
|
||||
|
@ -1151,6 +1286,9 @@ bool GPU_HW::CompilePipelines(Error* error)
|
|||
}
|
||||
}
|
||||
|
||||
plconfig.SetTargetFormats(VRAM_RT_FORMAT, needs_rov_depth ? GPUTexture::Format::Unknown : depth_buffer_format);
|
||||
plconfig.render_pass_flags = needs_feedback_loop ? GPUPipeline::ColorFeedbackLoop : GPUPipeline::NoRenderPassFlags;
|
||||
|
||||
if (m_wireframe_mode != GPUWireframeMode::Disabled)
|
||||
{
|
||||
std::unique_ptr<GPUShader> gs = g_gpu_device->CreateShader(GPUShaderStage::Geometry, shadergen.GetLanguage(),
|
||||
|
@ -1203,6 +1341,7 @@ bool GPU_HW::CompilePipelines(Error* error)
|
|||
plconfig.per_sample_shading = false;
|
||||
plconfig.blend = GPUPipeline::BlendState::GetNoBlendingState();
|
||||
plconfig.vertex_shader = fullscreen_quad_vertex_shader.get();
|
||||
plconfig.color_formats[1] = needs_rov_depth ? VRAM_DS_COLOR_FORMAT : GPUTexture::Format::Unknown;
|
||||
|
||||
// VRAM fill
|
||||
for (u8 wrapped = 0; wrapped < 2; wrapped++)
|
||||
|
@ -1217,8 +1356,8 @@ bool GPU_HW::CompilePipelines(Error* error)
|
|||
return false;
|
||||
|
||||
plconfig.fragment_shader = fs.get();
|
||||
plconfig.depth = needs_depth_buffer ? GPUPipeline::DepthState::GetAlwaysWriteState() :
|
||||
GPUPipeline::DepthState::GetNoTestsState();
|
||||
plconfig.depth = needs_real_depth_buffer ? GPUPipeline::DepthState::GetAlwaysWriteState() :
|
||||
GPUPipeline::DepthState::GetNoTestsState();
|
||||
|
||||
if (!(m_vram_fill_pipelines[wrapped][interlaced] = g_gpu_device->CreatePipeline(plconfig, error)))
|
||||
return false;
|
||||
|
@ -1237,10 +1376,10 @@ bool GPU_HW::CompilePipelines(Error* error)
|
|||
plconfig.fragment_shader = fs.get();
|
||||
for (u8 depth_test = 0; depth_test < 2; depth_test++)
|
||||
{
|
||||
if (depth_test && !write_mask_as_depth)
|
||||
if (depth_test && !m_write_mask_as_depth)
|
||||
continue;
|
||||
|
||||
plconfig.depth.depth_write = needs_depth_buffer;
|
||||
plconfig.depth.depth_write = needs_real_depth_buffer;
|
||||
plconfig.depth.depth_test =
|
||||
(depth_test != 0) ? GPUPipeline::DepthFunc::GreaterEqual : GPUPipeline::DepthFunc::Always;
|
||||
|
||||
|
@ -1268,10 +1407,10 @@ bool GPU_HW::CompilePipelines(Error* error)
|
|||
plconfig.fragment_shader = fs.get();
|
||||
for (u8 depth_test = 0; depth_test < 2; depth_test++)
|
||||
{
|
||||
if (depth_test && !write_mask_as_depth)
|
||||
if (depth_test && !m_write_mask_as_depth)
|
||||
continue;
|
||||
|
||||
plconfig.depth.depth_write = needs_depth_buffer;
|
||||
plconfig.depth.depth_write = needs_real_depth_buffer;
|
||||
plconfig.depth.depth_test =
|
||||
(depth_test != 0) ? GPUPipeline::DepthFunc::GreaterEqual : GPUPipeline::DepthFunc::Always;
|
||||
|
||||
|
@ -1301,10 +1440,8 @@ bool GPU_HW::CompilePipelines(Error* error)
|
|||
progress.Increment();
|
||||
}
|
||||
|
||||
plconfig.render_pass_flags = GPUPipeline::NoRenderPassFlags;
|
||||
|
||||
// VRAM update depth
|
||||
if (needs_depth_buffer)
|
||||
if (m_write_mask_as_depth)
|
||||
{
|
||||
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(
|
||||
GPUShaderStage::Fragment, shadergen.GetLanguage(), shadergen.GenerateVRAMUpdateDepthFragmentShader(), error);
|
||||
|
@ -1325,6 +1462,7 @@ bool GPU_HW::CompilePipelines(Error* error)
|
|||
}
|
||||
|
||||
plconfig.SetTargetFormats(VRAM_RT_FORMAT);
|
||||
plconfig.render_pass_flags = GPUPipeline::NoRenderPassFlags;
|
||||
plconfig.depth = GPUPipeline::DepthState::GetNoTestsState();
|
||||
plconfig.blend = GPUPipeline::BlendState::GetNoBlendingState();
|
||||
plconfig.samples = 1;
|
||||
|
@ -1366,7 +1504,7 @@ bool GPU_HW::CompilePipelines(Error* error)
|
|||
|
||||
plconfig.layout = depth_extract ? GPUPipeline::Layout::MultiTextureAndPushConstants :
|
||||
GPUPipeline::Layout::SingleTextureAndPushConstants;
|
||||
plconfig.color_formats[1] = depth_extract ? VRAM_DS_EXTRACT_FORMAT : GPUTexture::Format::Unknown;
|
||||
plconfig.color_formats[1] = depth_extract ? VRAM_DS_COLOR_FORMAT : GPUTexture::Format::Unknown;
|
||||
|
||||
if (!(m_vram_extract_pipeline[shader] = g_gpu_device->CreatePipeline(plconfig, error)))
|
||||
return false;
|
||||
|
@ -1385,7 +1523,7 @@ bool GPU_HW::CompilePipelines(Error* error)
|
|||
return false;
|
||||
|
||||
plconfig.fragment_shader = fs.get();
|
||||
plconfig.SetTargetFormats(VRAM_DS_EXTRACT_FORMAT);
|
||||
plconfig.SetTargetFormats(VRAM_DS_COLOR_FORMAT);
|
||||
if (!(m_copy_depth_pipeline = g_gpu_device->CreatePipeline(plconfig, error)))
|
||||
return false;
|
||||
}
|
||||
|
@ -1588,8 +1726,7 @@ void GPU_HW::UpdateVRAMReadTexture(bool drawn, bool written)
|
|||
|
||||
void GPU_HW::UpdateDepthBufferFromMaskBit()
|
||||
{
|
||||
if (m_pgxp_depth_buffer || !m_vram_depth_texture)
|
||||
return;
|
||||
DebugAssert(!m_pgxp_depth_buffer && m_vram_depth_texture && m_write_mask_as_depth);
|
||||
|
||||
// Viewport should already be set full, only need to fudge the scissor.
|
||||
g_gpu_device->SetScissor(m_vram_texture->GetRect());
|
||||
|
@ -1639,7 +1776,10 @@ void GPU_HW::ClearDepthBuffer()
|
|||
{
|
||||
GL_SCOPE("GPU_HW::ClearDepthBuffer()");
|
||||
DebugAssert(m_pgxp_depth_buffer);
|
||||
g_gpu_device->ClearDepth(m_vram_depth_texture.get(), 1.0f);
|
||||
if (m_use_rov_for_shader_blend)
|
||||
g_gpu_device->ClearRenderTarget(m_vram_depth_texture.get(), 0xFF);
|
||||
else
|
||||
g_gpu_device->ClearDepth(m_vram_depth_texture.get(), 1.0f);
|
||||
m_last_depth_z = 1.0f;
|
||||
}
|
||||
|
||||
|
@ -1690,10 +1830,41 @@ ALWAYS_INLINE_RELEASE void GPU_HW::DrawBatchVertices(BatchRenderMode render_mode
|
|||
render_mode)][texture_mode][BoolToUInt8(m_batch.dithering)][BoolToUInt8(m_batch.interlacing)][check_mask]
|
||||
.get());
|
||||
|
||||
if (render_mode != BatchRenderMode::ShaderBlend || m_supports_framebuffer_fetch)
|
||||
g_gpu_device->DrawIndexed(num_indices, base_index, base_vertex);
|
||||
GL_INS_FMT("Texture mode: {}", s_batch_texture_modes[texture_mode]);
|
||||
GL_INS_FMT("Transparency mode: {}", s_transparency_modes[static_cast<u8>(m_batch.transparency_mode)]);
|
||||
GL_INS_FMT("Render mode: {}", s_batch_render_modes[static_cast<u8>(render_mode)]);
|
||||
GL_INS_FMT("Mask bit test: {}", m_batch.check_mask_before_draw);
|
||||
GL_INS_FMT("Interlacing: {}", m_batch.check_mask_before_draw);
|
||||
|
||||
// Activating ROV?
|
||||
if (render_mode == BatchRenderMode::ShaderBlend)
|
||||
{
|
||||
if (m_use_rov_for_shader_blend)
|
||||
{
|
||||
if (!m_rov_active)
|
||||
{
|
||||
GL_INS("Activating ROV.");
|
||||
m_rov_active = true;
|
||||
SetVRAMRenderTarget();
|
||||
}
|
||||
|
||||
g_gpu_device->DrawIndexed(num_indices, base_index, base_vertex);
|
||||
}
|
||||
else if (m_supports_framebuffer_fetch)
|
||||
{
|
||||
// No barriers needed for FBFetch.
|
||||
g_gpu_device->DrawIndexed(num_indices, base_index, base_vertex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Barriers. Yucky.
|
||||
g_gpu_device->DrawIndexedWithBarrier(num_indices, base_index, base_vertex, GPUDevice::DrawBarrier::Full);
|
||||
}
|
||||
}
|
||||
else
|
||||
g_gpu_device->DrawIndexedWithBarrier(num_indices, base_index, base_vertex, GPUDevice::DrawBarrier::Full);
|
||||
{
|
||||
g_gpu_device->DrawIndexed(num_indices, base_index, base_vertex);
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE_RELEASE void GPU_HW::HandleFlippedQuadTextureCoordinates(BatchVertex* vertices)
|
||||
|
@ -2733,12 +2904,14 @@ ALWAYS_INLINE_RELEASE bool GPU_HW::NeedsTwoPassRendering() const
|
|||
(!m_supports_dual_source_blend && m_batch.transparency_mode != GPUTransparencyMode::Disabled)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE_RELEASE bool GPU_HW::NeedsShaderBlending(GPUTransparencyMode transparency, bool check_mask) const
|
||||
ALWAYS_INLINE_RELEASE bool GPU_HW::NeedsShaderBlending(GPUTransparencyMode transparency, BatchTextureMode texture_mode,
|
||||
bool check_mask) const
|
||||
{
|
||||
return (m_allow_shader_blend &&
|
||||
((check_mask && (m_pgxp_depth_buffer || !m_vram_depth_texture)) ||
|
||||
transparency == GPUTransparencyMode::BackgroundMinusForeground ||
|
||||
(!m_supports_dual_source_blend &&
|
||||
((check_mask && !m_write_mask_as_depth) ||
|
||||
(transparency != GPUTransparencyMode::Disabled && m_prefer_shader_blend) ||
|
||||
(transparency == GPUTransparencyMode::BackgroundMinusForeground) ||
|
||||
(!m_supports_dual_source_blend && texture_mode != BatchTextureMode::Disabled &&
|
||||
(transparency != GPUTransparencyMode::Disabled || IsBlendedTextureFiltering(m_texture_filtering) ||
|
||||
IsBlendedTextureFiltering(m_sprite_texture_filtering)))));
|
||||
}
|
||||
|
@ -2799,7 +2972,7 @@ void GPU_HW::ResetBatchVertexDepth()
|
|||
{
|
||||
DEV_LOG("Resetting batch vertex depth");
|
||||
|
||||
if (m_vram_depth_texture && !m_pgxp_depth_buffer)
|
||||
if (m_write_mask_as_depth)
|
||||
UpdateDepthBufferFromMaskBit();
|
||||
|
||||
m_current_depth = 1;
|
||||
|
@ -2874,6 +3047,7 @@ void GPU_HW::FillDrawCommand(GPUBackendDrawCommand* cmd, GPURenderCommand rc) co
|
|||
void GPU_HW::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
|
||||
{
|
||||
GL_SCOPE_FMT("FillVRAM({},{} => {},{} ({}x{}) with 0x{:08X}", x, y, x + width, y + height, width, height, color);
|
||||
DeactivateROV();
|
||||
|
||||
if (m_sw_renderer)
|
||||
{
|
||||
|
@ -3027,6 +3201,8 @@ void GPU_HW::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, b
|
|||
void GPU_HW::UpdateVRAMOnGPU(u32 x, u32 y, u32 width, u32 height, const void* data, u32 data_pitch, bool set_mask,
|
||||
bool check_mask, const GSVector4i bounds)
|
||||
{
|
||||
DeactivateROV();
|
||||
|
||||
std::unique_ptr<GPUTexture> upload_texture;
|
||||
u32 map_index;
|
||||
|
||||
|
@ -3070,8 +3246,7 @@ void GPU_HW::UpdateVRAMOnGPU(u32 x, u32 y, u32 width, u32 height, const void* da
|
|||
// the viewport should already be set to the full vram, so just adjust the scissor
|
||||
const GSVector4i scaled_bounds = bounds.mul32l(GSVector4i(m_resolution_scale));
|
||||
g_gpu_device->SetScissor(scaled_bounds.left, scaled_bounds.top, scaled_bounds.width(), scaled_bounds.height());
|
||||
g_gpu_device->SetPipeline(
|
||||
m_vram_write_pipelines[BoolToUInt8(check_mask && !m_pgxp_depth_buffer && NeedsDepthBuffer())].get());
|
||||
g_gpu_device->SetPipeline(m_vram_write_pipelines[BoolToUInt8(check_mask && m_write_mask_as_depth)].get());
|
||||
g_gpu_device->PushUniformBuffer(&uniforms, sizeof(uniforms));
|
||||
if (upload_texture)
|
||||
{
|
||||
|
@ -3121,6 +3296,8 @@ void GPU_HW::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32
|
|||
UpdateVRAMReadTexture(intersect_with_draw, intersect_with_write);
|
||||
AddUnclampedDrawnRectangle(dst_bounds);
|
||||
|
||||
DeactivateROV();
|
||||
|
||||
struct VRAMCopyUBOData
|
||||
{
|
||||
u32 u_src_x;
|
||||
|
@ -3149,8 +3326,7 @@ void GPU_HW::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32
|
|||
const GSVector4i dst_bounds_scaled = dst_bounds.mul32l(GSVector4i(m_resolution_scale));
|
||||
g_gpu_device->SetViewportAndScissor(dst_bounds_scaled);
|
||||
g_gpu_device->SetPipeline(
|
||||
m_vram_copy_pipelines[BoolToUInt8(m_GPUSTAT.check_mask_before_draw && !m_pgxp_depth_buffer && NeedsDepthBuffer())]
|
||||
.get());
|
||||
m_vram_copy_pipelines[BoolToUInt8(m_GPUSTAT.check_mask_before_draw && m_write_mask_as_depth)].get());
|
||||
g_gpu_device->PushUniformBuffer(&uniforms, sizeof(uniforms));
|
||||
g_gpu_device->Draw(3, 0);
|
||||
RestoreDeviceContext();
|
||||
|
@ -3285,8 +3461,8 @@ void GPU_HW::DispatchRenderCommand()
|
|||
{
|
||||
// transparency mode change
|
||||
const bool check_mask_before_draw = m_GPUSTAT.check_mask_before_draw;
|
||||
if (transparency_mode != GPUTransparencyMode::Disabled &&
|
||||
(texture_mode == BatchTextureMode::Disabled || !NeedsShaderBlending(transparency_mode, check_mask_before_draw)))
|
||||
if (transparency_mode != GPUTransparencyMode::Disabled && !m_rov_active && !m_prefer_shader_blend &&
|
||||
!NeedsShaderBlending(transparency_mode, texture_mode, check_mask_before_draw))
|
||||
{
|
||||
static constexpr float transparent_alpha[4][2] = {{0.5f, 0.5f}, {1.0f, 1.0f}, {1.0f, 1.0f}, {0.25f, 1.0f}};
|
||||
|
||||
|
@ -3399,7 +3575,8 @@ void GPU_HW::FlushRender()
|
|||
|
||||
if (m_wireframe_mode != GPUWireframeMode::OnlyWireframe)
|
||||
{
|
||||
if (NeedsShaderBlending(m_batch.transparency_mode, m_batch.check_mask_before_draw))
|
||||
if (NeedsShaderBlending(m_batch.transparency_mode, m_batch.texture_mode, m_batch.check_mask_before_draw) ||
|
||||
m_rov_active || (m_use_rov_for_shader_blend && m_pgxp_depth_buffer))
|
||||
{
|
||||
DrawBatchVertices(BatchRenderMode::ShaderBlend, index_count, base_index, base_vertex);
|
||||
}
|
||||
|
@ -3416,6 +3593,8 @@ void GPU_HW::FlushRender()
|
|||
|
||||
if (m_wireframe_mode != GPUWireframeMode::Disabled)
|
||||
{
|
||||
// This'll be less than ideal, but wireframe is for debugging, so take the perf hit.
|
||||
DeactivateROV();
|
||||
g_gpu_device->SetPipeline(m_wireframe_pipeline.get());
|
||||
g_gpu_device->DrawIndexed(index_count, base_index, base_vertex);
|
||||
}
|
||||
|
@ -3424,6 +3603,7 @@ void GPU_HW::FlushRender()
|
|||
void GPU_HW::UpdateDisplay()
|
||||
{
|
||||
FlushRender();
|
||||
DeactivateROV();
|
||||
|
||||
GL_SCOPE("UpdateDisplay()");
|
||||
|
||||
|
@ -3506,7 +3686,7 @@ void GPU_HW::UpdateDisplay()
|
|||
((m_vram_extract_depth_texture && m_vram_extract_depth_texture->GetWidth() == scaled_display_width &&
|
||||
m_vram_extract_depth_texture->GetHeight() == scaled_display_height) ||
|
||||
!g_gpu_device->ResizeTexture(&m_vram_extract_depth_texture, scaled_display_width, scaled_display_height,
|
||||
GPUTexture::Type::RenderTarget, VRAM_DS_EXTRACT_FORMAT)))
|
||||
GPUTexture::Type::RenderTarget, VRAM_DS_COLOR_FORMAT)))
|
||||
{
|
||||
depth_source->MakeReadyForSampling();
|
||||
g_gpu_device->InvalidateRenderTarget(m_vram_extract_depth_texture.get());
|
||||
|
|
|
@ -144,7 +144,6 @@ private:
|
|||
std::numeric_limits<s32>::min());
|
||||
|
||||
/// Returns true if a depth buffer should be created.
|
||||
bool NeedsDepthBuffer() const;
|
||||
GPUTexture::Format GetDepthBufferFormat() const;
|
||||
|
||||
bool CreateBuffers();
|
||||
|
@ -165,6 +164,7 @@ private:
|
|||
void ClearDepthBuffer();
|
||||
void SetScissor();
|
||||
void SetVRAMRenderTarget();
|
||||
void DeactivateROV();
|
||||
void MapGPUBuffer(u32 required_vertices, u32 required_indices);
|
||||
void UnmapGPUBuffer(u32 used_vertices, u32 used_indices);
|
||||
void DrawBatchVertices(BatchRenderMode render_mode, u32 num_indices, u32 base_index, u32 base_vertex);
|
||||
|
@ -197,7 +197,7 @@ private:
|
|||
bool NeedsTwoPassRendering() const;
|
||||
|
||||
/// Returns true if the draw is going to use shader blending/framebuffer fetch.
|
||||
bool NeedsShaderBlending(GPUTransparencyMode transparency, bool check_mask) const;
|
||||
bool NeedsShaderBlending(GPUTransparencyMode transparency, BatchTextureMode texture, bool check_mask) const;
|
||||
|
||||
void FillBackendCommandParameters(GPUBackendCommand* cmd) const;
|
||||
void FillDrawCommand(GPUBackendDrawCommand* cmd, GPURenderCommand rc) const;
|
||||
|
@ -281,8 +281,12 @@ private:
|
|||
bool m_compute_uv_range : 1 = false;
|
||||
bool m_allow_sprite_mode : 1 = false;
|
||||
bool m_allow_shader_blend : 1 = false;
|
||||
bool m_prefer_shader_blend : 1 = false;
|
||||
bool m_use_rov_for_shader_blend : 1 = false;
|
||||
bool m_write_mask_as_depth : 1 = false;
|
||||
bool m_depth_was_copied : 1 = false;
|
||||
bool m_texture_window_active : 1 = false;
|
||||
bool m_rov_active : 1 = false;
|
||||
|
||||
u8 m_texpage_dirty = 0;
|
||||
|
||||
|
|
|
@ -77,7 +77,8 @@ std::string GPU_HW_ShaderGen::GenerateBatchVertexShader(bool textured, bool pale
|
|||
{
|
||||
DeclareVertexEntryPoint(
|
||||
ss, {"float4 a_pos", "float4 a_col0", "uint a_texcoord", "uint a_texpage", "float4 a_uv_limits"}, 1, 1,
|
||||
{{"nointerpolation", palette ? "uint4 v_texpage" : "uint2 v_texpage"}, {"nointerpolation", "float4 v_uv_limits"}},
|
||||
{{"nointerpolation", palette ? "uint4 v_texpage" : "uint2 v_texpage"},
|
||||
{"nointerpolation", "float4 v_uv_limits"}},
|
||||
false, "", UsingMSAA(), UsingPerSampleShading(), m_disable_color_perspective);
|
||||
}
|
||||
else
|
||||
|
@ -647,28 +648,26 @@ void FilteredSampleFromVRAM(TEXPAGE_VALUE texpage, float2 coords, float4 uv_limi
|
|||
}
|
||||
}
|
||||
|
||||
std::string GPU_HW_ShaderGen::GenerateBatchFragmentShader(GPU_HW::BatchRenderMode render_mode,
|
||||
GPUTransparencyMode transparency,
|
||||
GPU_HW::BatchTextureMode texture_mode,
|
||||
GPUTextureFilter texture_filtering, bool uv_limits,
|
||||
bool force_round_texcoords, bool dithering, bool interlacing,
|
||||
bool check_mask)
|
||||
std::string GPU_HW_ShaderGen::GenerateBatchFragmentShader(
|
||||
GPU_HW::BatchRenderMode render_mode, GPUTransparencyMode transparency, GPU_HW::BatchTextureMode texture_mode,
|
||||
GPUTextureFilter texture_filtering, bool uv_limits, bool force_round_texcoords, bool dithering, bool interlacing,
|
||||
bool check_mask, bool use_rov, bool use_rov_depth, bool rov_depth_test)
|
||||
{
|
||||
// TODO: don't write depth for shader blend
|
||||
DebugAssert(transparency == GPUTransparencyMode::Disabled || render_mode == GPU_HW::BatchRenderMode::ShaderBlend);
|
||||
DebugAssert(!rov_depth_test || (use_rov && use_rov_depth));
|
||||
|
||||
const bool textured = (texture_mode != GPU_HW::BatchTextureMode::Disabled);
|
||||
const bool palette =
|
||||
(texture_mode == GPU_HW::BatchTextureMode::Palette4Bit || texture_mode == GPU_HW::BatchTextureMode::Palette8Bit);
|
||||
const bool shader_blending = (render_mode == GPU_HW::BatchRenderMode::ShaderBlend &&
|
||||
(transparency != GPUTransparencyMode::Disabled || check_mask));
|
||||
const bool use_dual_source = (!shader_blending && m_supports_dual_source_blend &&
|
||||
const bool shader_blending = (render_mode == GPU_HW::BatchRenderMode::ShaderBlend);
|
||||
const bool use_dual_source = (!shader_blending && !use_rov && m_supports_dual_source_blend &&
|
||||
((render_mode != GPU_HW::BatchRenderMode::TransparencyDisabled &&
|
||||
render_mode != GPU_HW::BatchRenderMode::OnlyOpaque) ||
|
||||
texture_filtering != GPUTextureFilter::Nearest));
|
||||
|
||||
std::stringstream ss;
|
||||
WriteHeader(ss);
|
||||
WriteHeader(ss, use_rov);
|
||||
DefineMacro(ss, "TRANSPARENCY", render_mode != GPU_HW::BatchRenderMode::TransparencyDisabled);
|
||||
DefineMacro(ss, "TRANSPARENCY_ONLY_OPAQUE", render_mode == GPU_HW::BatchRenderMode::OnlyOpaque);
|
||||
DefineMacro(ss, "TRANSPARENCY_ONLY_TRANSPARENT", render_mode == GPU_HW::BatchRenderMode::OnlyTransparent);
|
||||
|
@ -687,6 +686,9 @@ std::string GPU_HW_ShaderGen::GenerateBatchFragmentShader(GPU_HW::BatchRenderMod
|
|||
DefineMacro(ss, "TRUE_COLOR", m_true_color);
|
||||
DefineMacro(ss, "TEXTURE_FILTERING", texture_filtering != GPUTextureFilter::Nearest);
|
||||
DefineMacro(ss, "UV_LIMITS", uv_limits);
|
||||
DefineMacro(ss, "USE_ROV", use_rov);
|
||||
DefineMacro(ss, "USE_ROV_DEPTH", use_rov_depth);
|
||||
DefineMacro(ss, "ROV_DEPTH_TEST", rov_depth_test);
|
||||
DefineMacro(ss, "USE_DUAL_SOURCE", use_dual_source);
|
||||
DefineMacro(ss, "WRITE_MASK_AS_DEPTH", m_write_mask_as_depth);
|
||||
DefineMacro(ss, "FORCE_ROUND_TEXCOORDS", force_round_texcoords);
|
||||
|
@ -696,6 +698,13 @@ std::string GPU_HW_ShaderGen::GenerateBatchFragmentShader(GPU_HW::BatchRenderMod
|
|||
WriteBatchUniformBuffer(ss);
|
||||
DeclareTexture(ss, "samp0", 0);
|
||||
|
||||
if (use_rov)
|
||||
{
|
||||
DeclareImage(ss, "rov_color", 0);
|
||||
if (use_rov_depth)
|
||||
DeclareImage(ss, "rov_depth", 1, true);
|
||||
}
|
||||
|
||||
if (m_glsl)
|
||||
ss << "CONSTANT int[16] s_dither_values = int[16]( ";
|
||||
else
|
||||
|
@ -825,6 +834,7 @@ float3 ApplyDebanding(float2 frag_coord)
|
|||
}
|
||||
)";
|
||||
|
||||
const u32 num_fragment_outputs = use_rov ? 0 : (use_dual_source ? 2 : 1);
|
||||
if (textured)
|
||||
{
|
||||
if (texture_filtering != GPUTextureFilter::Nearest)
|
||||
|
@ -835,26 +845,29 @@ float3 ApplyDebanding(float2 frag_coord)
|
|||
DeclareFragmentEntryPoint(ss, 1, 1,
|
||||
{{"nointerpolation", palette ? "uint4 v_texpage" : "uint2 v_texpage"},
|
||||
{"nointerpolation", "float4 v_uv_limits"}},
|
||||
true, use_dual_source ? 2 : 1, use_dual_source, m_write_mask_as_depth, UsingMSAA(),
|
||||
UsingPerSampleShading(), false, m_disable_color_perspective, shader_blending);
|
||||
true, num_fragment_outputs, use_dual_source, m_write_mask_as_depth, UsingMSAA(),
|
||||
UsingPerSampleShading(), false, m_disable_color_perspective,
|
||||
shader_blending && !use_rov, use_rov);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeclareFragmentEntryPoint(ss, 1, 1, {{"nointerpolation", palette ? "uint4 v_texpage" : "uint2 v_texpage"}}, true,
|
||||
use_dual_source ? 2 : 1, use_dual_source, m_write_mask_as_depth, UsingMSAA(),
|
||||
UsingPerSampleShading(), false, m_disable_color_perspective, shader_blending);
|
||||
num_fragment_outputs, use_dual_source, m_write_mask_as_depth, UsingMSAA(),
|
||||
UsingPerSampleShading(), false, m_disable_color_perspective,
|
||||
shader_blending && !use_rov, use_rov);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DeclareFragmentEntryPoint(ss, 1, 0, {}, true, use_dual_source ? 2 : 1, use_dual_source, m_write_mask_as_depth,
|
||||
DeclareFragmentEntryPoint(ss, 1, 0, {}, true, num_fragment_outputs, use_dual_source, m_write_mask_as_depth,
|
||||
UsingMSAA(), UsingPerSampleShading(), false, m_disable_color_perspective,
|
||||
shader_blending);
|
||||
shader_blending && !use_rov, use_rov);
|
||||
}
|
||||
|
||||
ss << R"(
|
||||
{
|
||||
uint3 vertcol = uint3(v_col0.rgb * float3(255.0, 255.0, 255.0) + ApplyDebanding(v_pos.xy));
|
||||
uint2 fragpos = uint2(v_pos.xy);
|
||||
|
||||
bool semitransparent;
|
||||
uint3 icolor;
|
||||
|
@ -862,7 +875,7 @@ float3 ApplyDebanding(float2 frag_coord)
|
|||
float oalpha;
|
||||
|
||||
#if INTERLACING
|
||||
if ((uint(v_pos.y) & 1u) == u_interlaced_displayed_field)
|
||||
if ((fragpos.y & 1u) == u_interlaced_displayed_field)
|
||||
discard;
|
||||
#endif
|
||||
|
||||
|
@ -891,7 +904,7 @@ float3 ApplyDebanding(float2 frag_coord)
|
|||
icolor = uint3(texcol.rgb * float3(255.0, 255.0, 255.0)) >> 3;
|
||||
icolor = (icolor * vertcol) >> 4;
|
||||
#if DITHERING
|
||||
icolor = ApplyDithering(uint2(v_pos.xy), icolor);
|
||||
icolor = ApplyDithering(fragpos, icolor);
|
||||
#else
|
||||
icolor = min(icolor >> 3, uint3(31u, 31u, 31u));
|
||||
#endif
|
||||
|
@ -899,7 +912,7 @@ float3 ApplyDebanding(float2 frag_coord)
|
|||
icolor = uint3(texcol.rgb * float3(255.0, 255.0, 255.0) + ApplyDebanding(v_pos.xy));
|
||||
icolor = (icolor * vertcol) >> 7;
|
||||
#if DITHERING
|
||||
icolor = ApplyDithering(uint2(v_pos.xy), icolor);
|
||||
icolor = ApplyDithering(fragpos, icolor);
|
||||
#else
|
||||
icolor = min(icolor, uint3(255u, 255u, 255u));
|
||||
#endif
|
||||
|
@ -914,7 +927,7 @@ float3 ApplyDebanding(float2 frag_coord)
|
|||
ialpha = 1.0;
|
||||
|
||||
#if DITHERING
|
||||
icolor = ApplyDithering(uint2(v_pos.xy), icolor);
|
||||
icolor = ApplyDithering(fragpos, icolor);
|
||||
#else
|
||||
#if !TRUE_COLOR
|
||||
icolor >>= 3;
|
||||
|
@ -925,29 +938,34 @@ float3 ApplyDebanding(float2 frag_coord)
|
|||
oalpha = float(u_set_mask_while_drawing);
|
||||
#endif
|
||||
|
||||
// Premultiply alpha so we don't need to use a colour output for it.
|
||||
float premultiply_alpha = ialpha;
|
||||
#if TRANSPARENCY && !SHADER_BLENDING
|
||||
premultiply_alpha = ialpha * (semitransparent ? u_src_alpha_factor : 1.0);
|
||||
#endif
|
||||
|
||||
float3 color;
|
||||
#if !TRUE_COLOR
|
||||
// We want to apply the alpha before the truncation to 16-bit, otherwise we'll be passing a 32-bit precision color
|
||||
// into the blend unit, which can cause a small amount of error to accumulate.
|
||||
color = floor(float3(icolor) * premultiply_alpha) / float3(31.0, 31.0, 31.0);
|
||||
#else
|
||||
// True color is actually simpler here since we want to preserve the precision.
|
||||
color = (float3(icolor) * premultiply_alpha) / float3(255.0, 255.0, 255.0);
|
||||
#endif
|
||||
|
||||
#if SHADER_BLENDING
|
||||
float4 bg_col = LAST_FRAG_COLOR;
|
||||
float4 fg_col = float4(color, oalpha);
|
||||
#if USE_ROV
|
||||
BEGIN_ROV_REGION;
|
||||
float4 bg_col = ROV_LOAD(rov_color, fragpos);
|
||||
float4 o_col0;
|
||||
bool discarded = false;
|
||||
|
||||
#if CHECK_MASK_BIT
|
||||
if (bg_col.a != 0.0)
|
||||
discard;
|
||||
#if ROV_DEPTH_TEST
|
||||
float bg_depth = ROV_LOAD(rov_depth, fragpos).r;
|
||||
discarded = (v_pos.z > bg_depth);
|
||||
#endif
|
||||
#if CHECK_MASK_BIT
|
||||
discarded = discarded || (bg_col.a != 0.0);
|
||||
#endif
|
||||
#else
|
||||
float4 bg_col = LAST_FRAG_COLOR;
|
||||
#if CHECK_MASK_BIT
|
||||
if (bg_col.a != 0.0)
|
||||
discard;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Work in normalized space for true colour, matches HW blend.
|
||||
float4 fg_col = float4(float3(icolor), oalpha);
|
||||
#if TRUE_COLOR
|
||||
fg_col.rgb /= 255.0;
|
||||
#elif TRANSPARENCY // rgb not used in check-mask only
|
||||
bg_col.rgb = roundEven(bg_col.rgb * 31.0);
|
||||
#endif
|
||||
|
||||
#if TEXTURE_FILTERING
|
||||
|
@ -969,14 +987,87 @@ float3 ApplyDebanding(float2 frag_coord)
|
|||
#else
|
||||
o_col0.rgb = fg_col.rgb;
|
||||
#endif
|
||||
|
||||
// 16-bit truncation.
|
||||
#if !TRUE_COLOR && TRANSPARENCY
|
||||
o_col0.rgb = floor(o_col0.rgb);
|
||||
#endif
|
||||
|
||||
#if TRANSPARENCY
|
||||
// If pixel isn't marked as semitransparent, replace with previous colour.
|
||||
o_col0 = semitransparent ? o_col0 : fg_col;
|
||||
#endif
|
||||
#elif TRANSPARENCY && TEXTURED
|
||||
// Apply semitransparency. If not a semitransparent texel, destination alpha is ignored.
|
||||
if (semitransparent)
|
||||
{
|
||||
|
||||
// Normalize for non-true-color.
|
||||
#if !TRUE_COLOR
|
||||
o_col0.rgb /= 31.0;
|
||||
#endif
|
||||
|
||||
#if USE_ROV
|
||||
if (!discarded)
|
||||
{
|
||||
ROV_STORE(rov_color, fragpos, o_col0);
|
||||
#if USE_ROV_DEPTH
|
||||
ROV_STORE(rov_depth, fragpos, float4(v_pos.z, 0.0, 0.0, 0.0));
|
||||
#endif
|
||||
}
|
||||
END_ROV_REGION;
|
||||
#endif
|
||||
#else
|
||||
// Premultiply alpha so we don't need to use a colour output for it.
|
||||
float premultiply_alpha = ialpha;
|
||||
#if TRANSPARENCY
|
||||
premultiply_alpha = ialpha * (semitransparent ? u_src_alpha_factor : 1.0);
|
||||
#endif
|
||||
|
||||
float3 color;
|
||||
#if !TRUE_COLOR
|
||||
// We want to apply the alpha before the truncation to 16-bit, otherwise we'll be passing a 32-bit precision color
|
||||
// into the blend unit, which can cause a small amount of error to accumulate.
|
||||
color = floor(float3(icolor) * premultiply_alpha) / 31.0;
|
||||
#else
|
||||
// True color is actually simpler here since we want to preserve the precision.
|
||||
color = (float3(icolor) * premultiply_alpha) / 255.0;
|
||||
#endif
|
||||
|
||||
#if TRANSPARENCY && TEXTURED
|
||||
// Apply semitransparency. If not a semitransparent texel, destination alpha is ignored.
|
||||
if (semitransparent)
|
||||
{
|
||||
#if USE_DUAL_SOURCE
|
||||
o_col0 = float4(color, oalpha);
|
||||
o_col1 = float4(0.0, 0.0, 0.0, u_dst_alpha_factor / ialpha);
|
||||
#else
|
||||
o_col0 = float4(color, oalpha);
|
||||
#endif
|
||||
|
||||
#if WRITE_MASK_AS_DEPTH
|
||||
o_depth = oalpha * v_pos.z;
|
||||
#endif
|
||||
|
||||
#if TRANSPARENCY_ONLY_OPAQUE
|
||||
discard;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if USE_DUAL_SOURCE
|
||||
o_col0 = float4(color, oalpha);
|
||||
o_col1 = float4(0.0, 0.0, 0.0, 1.0 - ialpha);
|
||||
#else
|
||||
o_col0 = float4(color, oalpha);
|
||||
#endif
|
||||
|
||||
#if WRITE_MASK_AS_DEPTH
|
||||
o_depth = oalpha * v_pos.z;
|
||||
#endif
|
||||
|
||||
#if TRANSPARENCY_ONLY_TRANSPARENT
|
||||
discard;
|
||||
#endif
|
||||
}
|
||||
#elif TRANSPARENCY
|
||||
// We shouldn't be rendering opaque geometry only when untextured, so no need to test/discard here.
|
||||
#if USE_DUAL_SOURCE
|
||||
o_col0 = float4(color, oalpha);
|
||||
o_col1 = float4(0.0, 0.0, 0.0, u_dst_alpha_factor / ialpha);
|
||||
|
@ -987,50 +1078,17 @@ float3 ApplyDebanding(float2 frag_coord)
|
|||
#if WRITE_MASK_AS_DEPTH
|
||||
o_depth = oalpha * v_pos.z;
|
||||
#endif
|
||||
#else
|
||||
// Non-transparency won't enable blending so we can write the mask here regardless.
|
||||
o_col0 = float4(color, oalpha);
|
||||
|
||||
#if TRANSPARENCY_ONLY_OPAQUE
|
||||
discard;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if USE_DUAL_SOURCE
|
||||
o_col0 = float4(color, oalpha);
|
||||
o_col1 = float4(0.0, 0.0, 0.0, 1.0 - ialpha);
|
||||
#else
|
||||
o_col0 = float4(color, oalpha);
|
||||
#endif
|
||||
|
||||
#if WRITE_MASK_AS_DEPTH
|
||||
o_depth = oalpha * v_pos.z;
|
||||
#endif
|
||||
|
||||
#if TRANSPARENCY_ONLY_TRANSPARENT
|
||||
discard;
|
||||
#endif
|
||||
}
|
||||
#elif TRANSPARENCY
|
||||
// We shouldn't be rendering opaque geometry only when untextured, so no need to test/discard here.
|
||||
#if USE_DUAL_SOURCE
|
||||
o_col0 = float4(color, oalpha);
|
||||
o_col1 = float4(0.0, 0.0, 0.0, u_dst_alpha_factor / ialpha);
|
||||
#else
|
||||
o_col0 = float4(color, oalpha);
|
||||
#endif
|
||||
|
||||
#if WRITE_MASK_AS_DEPTH
|
||||
o_depth = oalpha * v_pos.z;
|
||||
#endif
|
||||
#else
|
||||
// Non-transparency won't enable blending so we can write the mask here regardless.
|
||||
o_col0 = float4(color, oalpha);
|
||||
|
||||
#if USE_DUAL_SOURCE
|
||||
o_col1 = float4(0.0, 0.0, 0.0, 1.0 - ialpha);
|
||||
#endif
|
||||
|
||||
#if WRITE_MASK_AS_DEPTH
|
||||
o_depth = oalpha * v_pos.z;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ public:
|
|||
std::string GenerateBatchFragmentShader(GPU_HW::BatchRenderMode render_mode, GPUTransparencyMode transparency,
|
||||
GPU_HW::BatchTextureMode texture_mode, GPUTextureFilter texture_filtering,
|
||||
bool uv_limits, bool force_round_texcoords, bool dithering, bool interlacing,
|
||||
bool check_mask);
|
||||
bool check_mask, bool use_rov, bool use_rov_depth, bool rov_depth_test);
|
||||
std::string GenerateWireframeGeometryShader();
|
||||
std::string GenerateWireframeFragmentShader();
|
||||
std::string GenerateVRAMReadFragmentShader();
|
||||
|
|
|
@ -271,8 +271,10 @@ bool Host::CreateGPUDevice(RenderAPI api, Error* error)
|
|||
disabled_features |= GPUDevice::FEATURE_MASK_FRAMEBUFFER_FETCH;
|
||||
if (g_settings.gpu_disable_texture_buffers)
|
||||
disabled_features |= GPUDevice::FEATURE_MASK_TEXTURE_BUFFERS;
|
||||
if (g_settings.gpu_disable_texture_copy_to_self)
|
||||
disabled_features |= GPUDevice::FEATURE_MASK_TEXTURE_COPY_TO_SELF;
|
||||
if (g_settings.gpu_disable_memory_import)
|
||||
disabled_features |= GPUDevice::FEATURE_MASK_MEMORY_IMPORT;
|
||||
if (g_settings.gpu_disable_raster_order_views)
|
||||
disabled_features |= GPUDevice::FEATURE_MASK_RASTER_ORDER_VIEWS;
|
||||
|
||||
Error create_error;
|
||||
if (!g_gpu_device || !g_gpu_device->Create(g_settings.gpu_adapter,
|
||||
|
|
|
@ -191,6 +191,7 @@ void Settings::Load(SettingsInterface& si)
|
|||
gpu_disable_texture_buffers = si.GetBoolValue("GPU", "DisableTextureBuffers", false);
|
||||
gpu_disable_texture_copy_to_self = si.GetBoolValue("GPU", "DisableTextureCopyToSelf", false);
|
||||
gpu_disable_memory_import = si.GetBoolValue("GPU", "DisableMemoryImport", false);
|
||||
gpu_disable_raster_order_views = si.GetBoolValue("GPU", "DisableRasterOrderViews", false);
|
||||
gpu_per_sample_shading = si.GetBoolValue("GPU", "PerSampleShading", false);
|
||||
gpu_use_thread = si.GetBoolValue("GPU", "UseThread", true);
|
||||
gpu_use_software_renderer_for_readbacks = si.GetBoolValue("GPU", "UseSoftwareRendererForReadbacks", false);
|
||||
|
@ -199,6 +200,7 @@ void Settings::Load(SettingsInterface& si)
|
|||
gpu_debanding = si.GetBoolValue("GPU", "Debanding", false);
|
||||
gpu_scaled_dithering = si.GetBoolValue("GPU", "ScaledDithering", true);
|
||||
gpu_force_round_texcoords = si.GetBoolValue("GPU", "ForceRoundTextureCoordinates", false);
|
||||
gpu_accurate_blending = si.GetBoolValue("GPU", "AccurateBlending", false);
|
||||
gpu_texture_filter =
|
||||
ParseTextureFilterName(
|
||||
si.GetStringValue("GPU", "TextureFilter", GetTextureFilterName(DEFAULT_GPU_TEXTURE_FILTER)).c_str())
|
||||
|
@ -494,6 +496,7 @@ void Settings::Save(SettingsInterface& si, bool ignore_base) const
|
|||
si.SetBoolValue("GPU", "DisableTextureBuffers", gpu_disable_texture_buffers);
|
||||
si.SetBoolValue("GPU", "DisableTextureCopyToSelf", gpu_disable_texture_copy_to_self);
|
||||
si.SetBoolValue("GPU", "DisableMemoryImport", gpu_disable_memory_import);
|
||||
si.SetBoolValue("GPU", "DisableRasterOrderViews", gpu_disable_raster_order_views);
|
||||
}
|
||||
|
||||
si.SetBoolValue("GPU", "PerSampleShading", gpu_per_sample_shading);
|
||||
|
@ -504,6 +507,7 @@ void Settings::Save(SettingsInterface& si, bool ignore_base) const
|
|||
si.SetBoolValue("GPU", "Debanding", gpu_debanding);
|
||||
si.SetBoolValue("GPU", "ScaledDithering", gpu_scaled_dithering);
|
||||
si.SetBoolValue("GPU", "ForceRoundTextureCoordinates", gpu_force_round_texcoords);
|
||||
si.SetBoolValue("GPU", "AccurateBlending", gpu_accurate_blending);
|
||||
si.SetStringValue("GPU", "TextureFilter", GetTextureFilterName(gpu_texture_filter));
|
||||
si.SetStringValue(
|
||||
"GPU", "SpriteTextureFilter",
|
||||
|
|
|
@ -114,11 +114,13 @@ struct Settings
|
|||
bool gpu_disable_texture_buffers : 1 = false;
|
||||
bool gpu_disable_texture_copy_to_self : 1 = false;
|
||||
bool gpu_disable_memory_import : 1 = false;
|
||||
bool gpu_disable_raster_order_views : 1 = false;
|
||||
bool gpu_per_sample_shading : 1 = false;
|
||||
bool gpu_true_color : 1 = true;
|
||||
bool gpu_debanding : 1 = false;
|
||||
bool gpu_scaled_dithering : 1 = true;
|
||||
bool gpu_force_round_texcoords : 1 = false;
|
||||
bool gpu_accurate_blending : 1 = false;
|
||||
bool gpu_disable_interlacing : 1 = true;
|
||||
bool gpu_force_ntsc_timings : 1 = false;
|
||||
bool gpu_widescreen_hack : 1 = false;
|
||||
|
@ -280,6 +282,7 @@ struct Settings
|
|||
bool log_to_file : 1 = false;
|
||||
|
||||
ALWAYS_INLINE bool IsUsingSoftwareRenderer() const { return (gpu_renderer == GPURenderer::Software); }
|
||||
ALWAYS_INLINE bool IsUsingAccurateBlending() const { return (gpu_accurate_blending && !gpu_true_color); }
|
||||
ALWAYS_INLINE bool IsRunaheadEnabled() const { return (runahead_frames > 0); }
|
||||
|
||||
ALWAYS_INLINE PGXPMode GetPGXPMode()
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
#pragma once
|
||||
#include "common/types.h"
|
||||
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 17;
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 18;
|
||||
|
|
|
@ -3938,6 +3938,7 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
|
|||
g_settings.gpu_disable_texture_buffers != old_settings.gpu_disable_texture_buffers ||
|
||||
g_settings.gpu_disable_texture_copy_to_self != old_settings.gpu_disable_texture_copy_to_self ||
|
||||
g_settings.gpu_disable_memory_import != old_settings.gpu_disable_memory_import ||
|
||||
g_settings.gpu_disable_raster_order_views != old_settings.gpu_disable_raster_order_views ||
|
||||
g_settings.display_exclusive_fullscreen_control != old_settings.display_exclusive_fullscreen_control))
|
||||
{
|
||||
// if debug device/threaded presentation change, we need to recreate the whole display
|
||||
|
@ -3950,6 +3951,7 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
|
|||
g_settings.gpu_disable_texture_buffers != old_settings.gpu_disable_texture_buffers ||
|
||||
g_settings.gpu_disable_texture_copy_to_self != old_settings.gpu_disable_texture_copy_to_self ||
|
||||
g_settings.gpu_disable_memory_import != old_settings.gpu_disable_memory_import ||
|
||||
g_settings.gpu_disable_raster_order_views != old_settings.gpu_disable_raster_order_views ||
|
||||
g_settings.display_exclusive_fullscreen_control != old_settings.display_exclusive_fullscreen_control);
|
||||
|
||||
Host::AddIconOSDMessage("RendererSwitch", ICON_FA_PAINT_ROLLER,
|
||||
|
@ -4055,6 +4057,7 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
|
|||
g_settings.gpu_debanding != old_settings.gpu_debanding ||
|
||||
g_settings.gpu_scaled_dithering != old_settings.gpu_scaled_dithering ||
|
||||
g_settings.gpu_force_round_texcoords != old_settings.gpu_force_round_texcoords ||
|
||||
g_settings.gpu_accurate_blending != old_settings.gpu_accurate_blending ||
|
||||
g_settings.gpu_texture_filter != old_settings.gpu_texture_filter ||
|
||||
g_settings.gpu_sprite_texture_filter != old_settings.gpu_sprite_texture_filter ||
|
||||
g_settings.gpu_line_detect_mode != old_settings.gpu_line_detect_mode ||
|
||||
|
|
|
@ -138,6 +138,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
|||
"UseSoftwareRendererForReadbacks", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.forceRoundedTexcoords, "GPU", "ForceRoundTextureCoordinates",
|
||||
false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.accurateBlending, "GPU", "AccurateBlending", false);
|
||||
|
||||
SettingWidgetBinder::SetAvailability(m_ui.scaledDithering,
|
||||
!m_dialog->hasGameTrait(GameDatabase::Trait::DisableScaledDithering));
|
||||
|
@ -388,6 +389,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
|||
m_ui.forceRoundedTexcoords, tr("Round Upscaled Texture Coordinates"), tr("Unchecked"),
|
||||
tr("Rounds texture coordinates instead of flooring when upscaling. Can fix misaligned textures in some games, but "
|
||||
"break others, and is incompatible with texture filtering."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.accurateBlending, tr("Accurate Blending"), tr("Unchecked"),
|
||||
tr("Forces blending to be done in the shader at 16-bit precision, when not using true color. Very few games "
|
||||
"actually require this, and there is a <strong>non-trivial</strong> performance cost."));
|
||||
|
||||
// PGXP Tab
|
||||
|
||||
|
@ -520,6 +525,12 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
|||
dialog->registerWidgetHelp(m_ui.disableTextureCopyToSelf, tr("Disable Texture Copies To Self"), tr("Unchecked"),
|
||||
tr("Disables the use of self-copy updates for the VRAM texture. Useful for testing broken "
|
||||
"graphics drivers. <strong>Only for developer use.</strong>"));
|
||||
dialog->registerWidgetHelp(m_ui.disableMemoryImport, tr("Disable Memory Import"), tr("Unchecked"),
|
||||
tr("Disables the use of host memory importing. Useful for testing broken graphics "
|
||||
"drivers. <strong>Only for developer use.</strong>"));
|
||||
dialog->registerWidgetHelp(m_ui.disableRasterOrderViews, tr("Disable Rasterizer Order Views"), tr("Unchecked"),
|
||||
tr("Disables the use of rasterizer order views. Useful for testing broken graphics "
|
||||
"drivers. <strong>Only for developer use.</strong>"));
|
||||
}
|
||||
|
||||
GraphicsSettingsWidget::~GraphicsSettingsWidget() = default;
|
||||
|
@ -669,6 +680,8 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
|||
m_ui.debanding->setEnabled(is_hardware);
|
||||
m_ui.scaledDithering->setEnabled(is_hardware && !m_dialog->hasGameTrait(GameDatabase::Trait::DisableScaledDithering));
|
||||
m_ui.useSoftwareRendererForReadbacks->setEnabled(is_hardware);
|
||||
m_ui.forceRoundedTexcoords->setEnabled(is_hardware);
|
||||
m_ui.accurateBlending->setEnabled(is_hardware);
|
||||
|
||||
m_ui.tabs->setTabEnabled(TAB_INDEX_TEXTURE_REPLACEMENTS, is_hardware);
|
||||
|
||||
|
@ -881,9 +894,9 @@ void GraphicsSettingsWidget::onTrueColorChanged()
|
|||
const bool true_color = m_dialog->getEffectiveBoolValue("GPU", "TrueColor", false);
|
||||
const bool allow_scaled_dithering =
|
||||
(resolution_scale != 1 && !true_color && !m_dialog->hasGameTrait(GameDatabase::Trait::DisableScaledDithering));
|
||||
const bool allow_debanding = true_color;
|
||||
m_ui.scaledDithering->setEnabled(allow_scaled_dithering);
|
||||
m_ui.debanding->setEnabled(allow_debanding);
|
||||
m_ui.debanding->setEnabled(true_color);
|
||||
m_ui.accurateBlending->setEnabled(!true_color);
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onDownsampleModeChanged()
|
||||
|
|
|
@ -392,13 +392,6 @@
|
|||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="gpuThread">
|
||||
<property name="text">
|
||||
<string>Threaded Rendering</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="scaledDithering">
|
||||
<property name="text">
|
||||
|
@ -406,13 +399,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="useSoftwareRendererForReadbacks">
|
||||
<property name="text">
|
||||
<string>Software Renderer Readbacks</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="debanding">
|
||||
<property name="text">
|
||||
|
@ -420,13 +406,34 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="useSoftwareRendererForReadbacks">
|
||||
<property name="text">
|
||||
<string>Software Renderer Readbacks</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="forceRoundedTexcoords">
|
||||
<property name="text">
|
||||
<string>Round Upscaled Texture Coordinates</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="gpuThread">
|
||||
<property name="text">
|
||||
<string>Threaded Rendering</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="accurateBlending">
|
||||
<property name="text">
|
||||
<string>Accurate Blending</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
|
@ -993,13 +1000,6 @@
|
|||
<layout class="QFormLayout" name="formLayout_10">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout_8">
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="disableFramebufferFetch">
|
||||
<property name="text">
|
||||
<string>Disable Framebuffer Fetch</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="disableTextureCopyToSelf">
|
||||
<property name="text">
|
||||
|
@ -1007,13 +1007,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="disableDualSource">
|
||||
<property name="text">
|
||||
<string>Disable Dual-Source Blending</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="useDebugDevice">
|
||||
<property name="text">
|
||||
|
@ -1021,10 +1014,17 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="disableShaderCache">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="disableDualSource">
|
||||
<property name="text">
|
||||
<string>Disable Shader Cache</string>
|
||||
<string>Disable Dual-Source Blending</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="disableFramebufferFetch">
|
||||
<property name="text">
|
||||
<string>Disable Framebuffer Fetch</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -1035,6 +1035,27 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="disableShaderCache">
|
||||
<property name="text">
|
||||
<string>Disable Shader Cache</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="disableMemoryImport">
|
||||
<property name="text">
|
||||
<string>Disable Memory Import</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="disableRasterOrderViews">
|
||||
<property name="text">
|
||||
<string>Disable Rasterizer Order Views</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
@ -149,7 +149,7 @@ TinyString ShaderGen::GetGLSLVersionString(RenderAPI render_api, u32 version)
|
|||
}
|
||||
#endif
|
||||
|
||||
void ShaderGen::WriteHeader(std::stringstream& ss)
|
||||
void ShaderGen::WriteHeader(std::stringstream& ss, bool enable_rov /* = false */)
|
||||
{
|
||||
if (m_shader_language == GPUShaderLanguage::GLSL || m_shader_language == GPUShaderLanguage::GLSLES)
|
||||
ss << m_glsl_version_string << "\n\n";
|
||||
|
@ -211,6 +211,11 @@ void ShaderGen::WriteHeader(std::stringstream& ss)
|
|||
if (!GLAD_GL_VERSION_4_3 && !GLAD_GL_ES_VERSION_3_1 && GLAD_GL_ARB_shader_storage_buffer_object)
|
||||
ss << "#extension GL_ARB_shader_storage_buffer_object : require\n";
|
||||
}
|
||||
else if (m_shader_language == GPUShaderLanguage::GLSLVK)
|
||||
{
|
||||
if (enable_rov)
|
||||
ss << "#extension GL_ARB_fragment_shader_interlock : require\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
DefineMacro(ss, "API_OPENGL", m_render_api == RenderAPI::OpenGL);
|
||||
|
@ -413,6 +418,27 @@ void ShaderGen::DeclareTextureBuffer(std::stringstream& ss, const char* name, u3
|
|||
}
|
||||
}
|
||||
|
||||
void ShaderGen::DeclareImage(std::stringstream& ss, const char* name, u32 index, bool is_float /* = false */,
|
||||
bool is_int /* = false */, bool is_unsigned /* = false */)
|
||||
{
|
||||
if (m_glsl)
|
||||
{
|
||||
if (m_spirv)
|
||||
ss << "layout(set = " << (m_has_uniform_buffer ? 2 : 1) << ", binding = " << index;
|
||||
else
|
||||
ss << "layout(binding = " << index;
|
||||
|
||||
ss << ", " << (is_int ? (is_unsigned ? "rgba8ui" : "rgba8i") : "rgba8") << ") "
|
||||
<< "uniform restrict coherent image2D " << name << ";\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << "RasterizerOrderedTexture2D<"
|
||||
<< (is_int ? (is_unsigned ? "uint4" : "int4") : (is_float ? "float4" : "unorm float4")) << "> " << name
|
||||
<< " : register(u" << index << ");\n";
|
||||
}
|
||||
}
|
||||
|
||||
const char* ShaderGen::GetInterpolationQualifier(bool interface_block, bool centroid_interpolation,
|
||||
bool sample_interpolation, bool is_out) const
|
||||
{
|
||||
|
@ -545,7 +571,8 @@ void ShaderGen::DeclareFragmentEntryPoint(
|
|||
const std::initializer_list<std::pair<const char*, const char*>>& additional_inputs /* = */,
|
||||
bool declare_fragcoord /* = false */, u32 num_color_outputs /* = 1 */, bool dual_source_output /* = false */,
|
||||
bool depth_output /* = false */, bool msaa /* = false */, bool ssaa /* = false */,
|
||||
bool declare_sample_id /* = false */, bool noperspective_color /* = false */, bool feedback_loop /* = false */)
|
||||
bool declare_sample_id /* = false */, bool noperspective_color /* = false */, bool feedback_loop /* = false */,
|
||||
bool rov /* = false */)
|
||||
{
|
||||
if (m_glsl)
|
||||
{
|
||||
|
@ -603,6 +630,8 @@ void ShaderGen::DeclareFragmentEntryPoint(
|
|||
|
||||
if (feedback_loop)
|
||||
{
|
||||
Assert(!rov);
|
||||
|
||||
#ifdef ENABLE_OPENGL
|
||||
if (m_render_api == RenderAPI::OpenGL || m_render_api == RenderAPI::OpenGLES)
|
||||
{
|
||||
|
@ -647,6 +676,14 @@ void ShaderGen::DeclareFragmentEntryPoint(
|
|||
}
|
||||
#endif
|
||||
}
|
||||
else if (rov)
|
||||
{
|
||||
ss << "layout(pixel_interlock_ordered) in;\n";
|
||||
ss << "#define ROV_LOAD(name, coords) imageLoad(name, ivec2(coords))\n";
|
||||
ss << "#define ROV_STORE(name, coords, value) imageStore(name, ivec2(coords), value)\n";
|
||||
ss << "#define BEGIN_ROV_REGION beginInvocationInterlockARB()\n";
|
||||
ss << "#define END_ROV_REGION endInvocationInterlockARB()\n";
|
||||
}
|
||||
|
||||
if (m_use_glsl_binding_layout)
|
||||
{
|
||||
|
@ -679,48 +716,64 @@ void ShaderGen::DeclareFragmentEntryPoint(
|
|||
}
|
||||
else
|
||||
{
|
||||
if (rov)
|
||||
{
|
||||
ss << "#define ROV_LOAD(name, coords) name[uint2(coords)]\n";
|
||||
ss << "#define ROV_STORE(name, coords, value) name[uint2(coords)] = value\n";
|
||||
ss << "#define BEGIN_ROV_REGION\n";
|
||||
ss << "#define END_ROV_REGION\n";
|
||||
}
|
||||
|
||||
const char* qualifier = GetInterpolationQualifier(false, msaa, ssaa, false);
|
||||
|
||||
ss << "void main(\n";
|
||||
|
||||
bool first = true;
|
||||
for (u32 i = 0; i < num_color_inputs; i++)
|
||||
ss << " " << qualifier << (noperspective_color ? "noperspective " : "") << "in float4 v_col" << i << " : COLOR"
|
||||
<< i << ",\n";
|
||||
{
|
||||
ss << (first ? "" : ",\n") << " " << qualifier << (noperspective_color ? "noperspective " : "")
|
||||
<< "in float4 v_col" << i << " : COLOR" << i;
|
||||
first = false;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < num_texcoord_inputs; i++)
|
||||
ss << " " << qualifier << "in float2 v_tex" << i << " : TEXCOORD" << i << ",\n";
|
||||
{
|
||||
ss << (first ? "" : ",\n") << " " << qualifier << "in float2 v_tex" << i << " : TEXCOORD" << i;
|
||||
first = false;
|
||||
}
|
||||
|
||||
u32 additional_counter = num_texcoord_inputs;
|
||||
for (const auto& [qualifiers, name] : additional_inputs)
|
||||
{
|
||||
const char* qualifier_to_use = (std::strlen(qualifiers) > 0) ? qualifiers : qualifier;
|
||||
ss << " " << qualifier_to_use << " in " << name << " : TEXCOORD" << additional_counter << ",\n";
|
||||
ss << (first ? "" : ",\n") << " " << qualifier_to_use << " in " << name << " : TEXCOORD" << additional_counter;
|
||||
additional_counter++;
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (declare_fragcoord)
|
||||
ss << " in float4 v_pos : SV_Position,\n";
|
||||
{
|
||||
ss << (first ? "" : ",\n") << " in float4 v_pos : SV_Position";
|
||||
first = false;
|
||||
}
|
||||
if (declare_sample_id)
|
||||
ss << " in uint f_sample_index : SV_SampleIndex,\n";
|
||||
{
|
||||
ss << (first ? "" : ",\n") << " in uint f_sample_index : SV_SampleIndex";
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (depth_output)
|
||||
{
|
||||
ss << " out float o_depth : SV_Depth";
|
||||
if (num_color_outputs > 0)
|
||||
ss << ",\n";
|
||||
else
|
||||
ss << ")\n";
|
||||
ss << (first ? "" : ",\n") << " out float o_depth : SV_Depth";
|
||||
first = false;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < num_color_outputs; i++)
|
||||
{
|
||||
ss << " out float4 o_col" << i << " : SV_Target" << i;
|
||||
|
||||
if (i == (num_color_outputs - 1))
|
||||
ss << ")\n";
|
||||
else
|
||||
ss << ",\n";
|
||||
ss << (first ? "" : ",\n") << " out float4 o_col" << i << " : SV_Target" << i;
|
||||
first = false;
|
||||
}
|
||||
|
||||
ss << ")";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,13 +44,15 @@ protected:
|
|||
|
||||
void DefineMacro(std::stringstream& ss, const char* name, bool enabled);
|
||||
void DefineMacro(std::stringstream& ss, const char* name, s32 value);
|
||||
void WriteHeader(std::stringstream& ss);
|
||||
void WriteHeader(std::stringstream& ss, bool enable_rov = false);
|
||||
void WriteUniformBufferDeclaration(std::stringstream& ss, bool push_constant_on_vulkan);
|
||||
void DeclareUniformBuffer(std::stringstream& ss, const std::initializer_list<const char*>& members,
|
||||
bool push_constant_on_vulkan);
|
||||
void DeclareTexture(std::stringstream& ss, const char* name, u32 index, bool multisampled = false,
|
||||
bool is_int = false, bool is_unsigned = false);
|
||||
void DeclareTextureBuffer(std::stringstream& ss, const char* name, u32 index, bool is_int, bool is_unsigned);
|
||||
void DeclareImage(std::stringstream& ss, const char* name, u32 index, bool is_float = false, bool is_int = false,
|
||||
bool is_unsigned = false);
|
||||
void DeclareVertexEntryPoint(std::stringstream& ss, const std::initializer_list<const char*>& attributes,
|
||||
u32 num_color_outputs, u32 num_texcoord_outputs,
|
||||
const std::initializer_list<std::pair<const char*, const char*>>& additional_outputs,
|
||||
|
@ -62,7 +64,7 @@ protected:
|
|||
bool declare_fragcoord = false, u32 num_color_outputs = 1, bool dual_source_output = false,
|
||||
bool depth_output = false, bool msaa = false, bool ssaa = false,
|
||||
bool declare_sample_id = false, bool noperspective_color = false,
|
||||
bool feedback_loop = false);
|
||||
bool feedback_loop = false, bool rov = false);
|
||||
|
||||
RenderAPI m_render_api;
|
||||
GPUShaderLanguage m_shader_language;
|
||||
|
|
Loading…
Reference in New Issue