Files
parallel-gx1/Source/Core/VideoCommon/GeometryShaderManager.cpp
T
2026-10-16 14:27:05 +01:00

164 lines
4.4 KiB
C++

// Copyright 2014 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoCommon/GeometryShaderManager.h"
#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/RenderState.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h"
#ifdef __LIBRETRO__
#include <cmath>
#include "VideoCommon/VertexShaderManager.h"
#endif
static constexpr int LINE_PT_TEX_OFFSETS[8] = {0, 16, 8, 4, 2, 1, 1, 1};
void GeometryShaderManager::Init()
{
constants = {};
// Init any initial constants which aren't zero when bpmem is zero.
SetViewportChanged();
SetProjectionChanged();
dirty = true;
}
void GeometryShaderManager::Dirty()
{
// This function is called after a savestate is loaded.
// Any constants that can changed based on settings should be re-calculated
m_projection_changed = true;
// Uses EFB scale config
SetLinePtWidthChanged();
dirty = true;
}
void GeometryShaderManager::SetVSExpand(VSExpand expand)
{
if (constants.vs_expand != expand)
{
constants.vs_expand = expand;
dirty = true;
}
}
void GeometryShaderManager::SetConstants(PrimitiveType prim)
{
if (m_projection_changed && g_ActiveConfig.stereo_mode != StereoMode::Off)
{
m_projection_changed = false;
if (xfmem.projection.type == ProjectionType::Perspective)
{
const float offset = g_ActiveConfig.stereo_depth;
constants.stereoparams[0] = g_ActiveConfig.bStereoSwapEyes ? offset : -offset;
constants.stereoparams[1] = g_ActiveConfig.bStereoSwapEyes ? -offset : offset;
}
else
{
constants.stereoparams[0] = constants.stereoparams[1] = 0;
}
constants.stereoparams[2] = g_ActiveConfig.stereo_convergence;
#ifdef __LIBRETRO__
if (g_libretro_vr_camera.applied)
{
// Move each eye onto its own headset frustum as well as separating it. The shader adds
// hoffset * (w - convergence), so scaling the convergence keeps the separation's constant
// term while hoffset gains the frustum offset.
const float offset = g_ActiveConfig.stereo_depth;
const float eye_offset = g_libretro_vr_camera.eye_offset_x;
const float left = eye_offset - offset;
constants.stereoparams[0] = left;
constants.stereoparams[1] = -left;
constants.stereoparams[2] =
std::abs(left) > 1e-6f ? g_ActiveConfig.stereo_convergence * -offset / left : 0.0f;
}
else if (g_libretro_vr_camera.screen_applied)
{
// 2D has w = 1, so this moves each eye's copy of the screen onto its own frustum. Both
// eyes then see it in the same direction.
const float eye_offset = g_libretro_vr_camera.eye_offset_x;
constants.stereoparams[0] = eye_offset;
constants.stereoparams[1] = -eye_offset;
constants.stereoparams[2] = 0.0f;
}
#endif
dirty = true;
}
if (g_ActiveConfig.UseVSForLinePointExpand())
{
if (prim == PrimitiveType::Points)
SetVSExpand(VSExpand::Point);
else if (prim == PrimitiveType::Lines)
SetVSExpand(VSExpand::Line);
else
SetVSExpand(VSExpand::None);
}
if (m_viewport_changed)
{
m_viewport_changed = false;
constants.lineptparams[0] = 2.0f * xfmem.viewport.wd;
constants.lineptparams[1] = -2.0f * xfmem.viewport.ht;
dirty = true;
}
}
void GeometryShaderManager::SetViewportChanged()
{
m_viewport_changed = true;
}
void GeometryShaderManager::SetProjectionChanged()
{
m_projection_changed = true;
}
void GeometryShaderManager::SetLinePtWidthChanged()
{
constants.lineptparams[2] = bpmem.lineptwidth.linesize / 6.f;
constants.lineptparams[3] = bpmem.lineptwidth.pointsize / 6.f;
constants.texoffset[2] = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.lineoff];
constants.texoffset[3] = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.pointoff];
dirty = true;
}
void GeometryShaderManager::SetTexCoordChanged(u8 texmapid)
{
TCoordInfo& tc = bpmem.texcoords[texmapid];
int bitmask = 1 << texmapid;
constants.texoffset[0] &= ~bitmask;
constants.texoffset[0] |= tc.s.line_offset << texmapid;
constants.texoffset[1] &= ~bitmask;
constants.texoffset[1] |= tc.s.point_offset << texmapid;
dirty = true;
}
void GeometryShaderManager::DoState(PointerWrap& p)
{
p.Do(m_projection_changed);
p.Do(m_viewport_changed);
p.Do(constants);
if (p.IsReadMode())
{
// Fixup the current state from global GPU state
// NOTE: This requires that all GPU memory has been loaded already.
Dirty();
}
}