1 // Copyright 2014 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #include <cstring>
6 
7 #include "Common/ChunkFile.h"
8 #include "Common/CommonTypes.h"
9 #include "VideoCommon/BPMemory.h"
10 #include "VideoCommon/GeometryShaderManager.h"
11 #include "VideoCommon/VideoConfig.h"
12 #include "VideoCommon/XFMemory.h"
13 
14 static const int LINE_PT_TEX_OFFSETS[8] = {0, 16, 8, 4, 2, 1, 1, 1};
15 
16 GeometryShaderConstants GeometryShaderManager::constants;
17 bool GeometryShaderManager::dirty;
18 
19 static bool s_projection_changed;
20 static bool s_viewport_changed;
21 
Init()22 void GeometryShaderManager::Init()
23 {
24   constants = {};
25 
26   // Init any intial constants which aren't zero when bpmem is zero.
27   SetViewportChanged();
28   SetProjectionChanged();
29 
30   dirty = true;
31 }
32 
Dirty()33 void GeometryShaderManager::Dirty()
34 {
35   // This function is called after a savestate is loaded.
36   // Any constants that can changed based on settings should be re-calculated
37   s_projection_changed = true;
38 
39   dirty = true;
40 }
41 
SetConstants()42 void GeometryShaderManager::SetConstants()
43 {
44   if (s_projection_changed && g_ActiveConfig.stereo_mode != StereoMode::Off)
45   {
46     s_projection_changed = false;
47 
48     if (xfmem.projection.type == GX_PERSPECTIVE)
49     {
50       float offset = (g_ActiveConfig.iStereoDepth / 1000.0f) *
51                      (g_ActiveConfig.iStereoDepthPercentage / 100.0f);
52       constants.stereoparams[0] = g_ActiveConfig.bStereoSwapEyes ? offset : -offset;
53       constants.stereoparams[1] = g_ActiveConfig.bStereoSwapEyes ? -offset : offset;
54     }
55     else
56     {
57       constants.stereoparams[0] = constants.stereoparams[1] = 0;
58     }
59 
60     constants.stereoparams[2] = (float)(g_ActiveConfig.iStereoConvergence *
61                                         (g_ActiveConfig.iStereoConvergencePercentage / 100.0f));
62 
63     dirty = true;
64   }
65 
66   if (s_viewport_changed)
67   {
68     s_viewport_changed = false;
69 
70     constants.lineptparams[0] = 2.0f * xfmem.viewport.wd;
71     constants.lineptparams[1] = -2.0f * xfmem.viewport.ht;
72 
73     dirty = true;
74   }
75 }
76 
SetViewportChanged()77 void GeometryShaderManager::SetViewportChanged()
78 {
79   s_viewport_changed = true;
80 }
81 
SetProjectionChanged()82 void GeometryShaderManager::SetProjectionChanged()
83 {
84   s_projection_changed = true;
85 }
86 
SetLinePtWidthChanged()87 void GeometryShaderManager::SetLinePtWidthChanged()
88 {
89   constants.lineptparams[2] = bpmem.lineptwidth.linesize / 6.f;
90   constants.lineptparams[3] = bpmem.lineptwidth.pointsize / 6.f;
91   constants.texoffset[2] = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.lineoff];
92   constants.texoffset[3] = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.pointoff];
93   dirty = true;
94 }
95 
SetTexCoordChanged(u8 texmapid)96 void GeometryShaderManager::SetTexCoordChanged(u8 texmapid)
97 {
98   TCoordInfo& tc = bpmem.texcoords[texmapid];
99   int bitmask = 1 << texmapid;
100   constants.texoffset[0] &= ~bitmask;
101   constants.texoffset[0] |= tc.s.line_offset << texmapid;
102   constants.texoffset[1] &= ~bitmask;
103   constants.texoffset[1] |= tc.s.point_offset << texmapid;
104   dirty = true;
105 }
106 
DoState(PointerWrap & p)107 void GeometryShaderManager::DoState(PointerWrap& p)
108 {
109   p.Do(s_projection_changed);
110   p.Do(s_viewport_changed);
111 
112   p.Do(constants);
113 
114   if (p.GetMode() == PointerWrap::MODE_READ)
115   {
116     // Fixup the current state from global GPU state
117     // NOTE: This requires that all GPU memory has been loaded already.
118     Dirty();
119   }
120 }
121