@@ -18,57 +18,95 @@ void GSVertexTrace::Update(const void* vertex, const u16* index, int v_count, in
1818 if (i_count == 0 )
1919 return ;
2020
21+ const GSDrawingContext* context = m_state->m_context ;
22+
2123 m_primclass = primclass;
2224
25+ // Setup selector parameters for FindMinMax()
2326 const u32 iip = m_state->PRIM ->IIP ;
2427 const u32 tme = m_state->PRIM ->TME ;
2528 const u32 fst = m_state->PRIM ->FST ;
26- const u32 color = !(m_state->PRIM ->TME && m_state-> m_context -> TEX0 .TFX == TFX_DECAL && m_state-> m_context ->TEX0 .TCC );
29+ const u32 color = !(m_state->PRIM ->TME && context-> TEX0 .TFX == TFX_DECAL && context ->TEX0 .TCC );
2730
28- m_fmm[color][fst][tme][iip][primclass](*this , vertex, index, i_count);
31+ // Select correct FindMinMax() function to calculaute raw min/max values
32+ GSVector4 tmin, tmax;
33+ GSVector4i cmin, cmax, pmin, pmax;
34+ m_fmm[color][fst][tme][iip][primclass](vertex, index, i_count, tmin, tmax, cmin, cmax, pmin, pmax);
2935
30- // Potential float overflow detected. Better uses the slower division instead
31- // Note: If Q is too big, 1/Q will end up as 0. 1e30 is a random number
32- // that feel big enough.
33- if (!fst && !m_accurate_stq && m_min.t .z > 1e30 )
36+ // Set m_min and m_max values based on the raw min/max values
37+ const GSVector4 offset (m_state->m_context ->XYOFFSET );
38+ const GSVector4 pscale (1 .0f / 16 , 1 .0f / 16 , 0 .0f , 1 .0f );
39+
40+ m_min.p = (GSVector4 (pmin) - offset) * pscale;
41+ m_max.p = (GSVector4 (pmax) - offset) * pscale;
42+
43+ // Do Z separately, requires unsigned int conversion
44+ m_min.p .z = static_cast <float >(static_cast <u32 >(pmin.z ));
45+ m_max.p .z = static_cast <float >(static_cast <u32 >(pmax.z ));
46+
47+ m_min.t = GSVector4::zero ();
48+ m_max.t = GSVector4::zero ();
49+ m_min.c = GSVector4i::zero ();
50+ m_max.c = GSVector4i::zero ();
51+
52+ if (tme)
3453 {
35- Console.Warning (" Vertex Trace: float overflow detected ! min %e max %e" , m_min.t .z , m_max.t .z );
36- m_accurate_stq = true ;
54+ GSVector4 tscale;
55+ if (fst)
56+ tscale = GSVector4 (1 .0f / 16 , 1 .0f / 16 , 1 .0f , 1 .0f );
57+ else
58+ tscale = GSVector4 (static_cast <float >(1 << context->TEX0 .TW ), static_cast <float >(1 << context->TEX0 .TH ), 1 .0f , 1 .0f );
59+ m_min.t = tmin * tscale;
60+ m_max.t = tmax * tscale;
61+ }
62+
63+ if (color)
64+ {
65+ m_min.c = cmin.u8to32 ();
66+ m_max.c = cmax.u8to32 ();
3767 }
3868
3969 // AA1: Set alpha min max to coverage 128 when there is no alpha blending.
40- if (!m_state->PRIM ->ABE && m_state->PRIM ->AA1 && (m_primclass == GS_LINE_CLASS || m_primclass == GS_TRIANGLE_CLASS))
70+ if (!m_state->PRIM ->ABE && m_state->PRIM ->AA1 && (primclass == GS_LINE_CLASS || primclass == GS_TRIANGLE_CLASS))
4171 {
4272 m_min.c .a = 128 ;
4373 m_max.c .a = 128 ;
4474 }
4575
46- m_eq.value = (m_min.c == m_max.c ).mask () | ((m_min.p == m_max.p ).mask () << 16 ) | ((m_min.t == m_max.t ).mask () << 20 );
47-
4876 m_alpha.valid = false ;
4977
50- // I'm not sure of the cost. In doubt let's do it only when depth is enabled
51- if (m_state->m_context ->TEST .ZTE == 1 && m_state->m_context ->TEST .ZTST > ZTST_ALWAYS)
78+ // Set m_eq flags for when vertex values are constant.
79+ const u32 t_eq = (m_min.t == m_max.t ).mask (); // GSVector4, 4 bit mask.
80+ const u32 p_eq = GSVector4::cast (pmin == pmax).mask (); // Cast to GSVector4() for 4 bit mask.
81+ const u32 c_eq = (m_min.c == m_max.c ).mask (); // GSVector4i, 16 bit mask.
82+ m_eq.value = c_eq | (p_eq << 16 ) | (t_eq << 20 );
83+
84+ // Potential float overflow detected. Better uses the slower division instead
85+ // Note: If Q is too big, 1/Q will end up as 0. 1e30 is a random number
86+ // that feel big enough.
87+ if (!fst && !m_accurate_stq && m_min.t .z > 1e30 )
5288 {
53- CorrectDepthTrace (vertex, v_count);
89+ Console.Warning (" Vertex Trace: float overflow detected ! min %e max %e" , m_min.t .z , m_max.t .z );
90+ m_accurate_stq = true ;
5491 }
5592
93+ // Determine mipmapping LOD and whether linear filter is used.
5694 if (tme)
5795 {
5896 const GIFRegTEX1& TEX1 = m_state->m_context ->TEX1 ;
5997
6098 m_filter.mmag = TEX1.IsMagLinear ();
6199 m_filter.mmin = TEX1.IsMinLinear ();
62100
63- if (TEX1.MXL == 0 ) // MXL == 0 => MMIN ignored, tested it on ps2
101+ if (TEX1.MXL == 0 ) // MXL == 0 => MMIN ignored, tested it on ps2.
64102 {
65103 m_filter.linear = m_filter.mmag ;
66104 }
67105 else
68106 {
69107 const float K = static_cast <float >(TEX1.K ) / 16 ;
70108
71- if (TEX1.LCM == 0 && m_state->PRIM ->FST == 0 ) // FST == 1 => Q is not interpolated
109+ if (TEX1.LCM == 0 && m_state->PRIM ->FST == 0 ) // FST == 1 => Q is not interpolated.
72110 {
73111 // LOD = log2(1/|Q|) * (1 << L) + K
74112
@@ -108,7 +146,7 @@ void GSVertexTrace::Update(const void* vertex, const u16* index, int v_count, in
108146 break ;
109147
110148 case BiFiltering::Forced_But_Sprite:
111- // Special case to reduce the number of glitch when upscaling is enabled
149+ // Special case to reduce the number of glitch when upscaling is enabled.
112150 m_filter.opt_linear = (m_primclass == GS_SPRITE_CLASS) ? m_filter.linear : 1 ;
113151 break ;
114152
@@ -123,50 +161,3 @@ void GSVertexTrace::Update(const void* vertex, const u16* index, int v_count, in
123161 }
124162 }
125163}
126-
127- void GSVertexTrace::CorrectDepthTrace (const void * vertex, int count)
128- {
129- if (m_eq.z == 0 )
130- return ;
131-
132- // FindMinMax isn't accurate for the depth value. Lsb bit is always 0.
133- // The code below will check that depth value is really constant
134- // and will update m_min/m_max/m_eq accordingly
135- //
136- // Really impact Xenosaga3
137- //
138- // Hopefully function is barely called so AVX/SSE will be useless here
139-
140-
141- const GSVertex* RESTRICT v = (GSVertex*)vertex;
142-
143- const int sprite_step = (m_primclass == GS_SPRITE_CLASS) ? 1 : 0 ;
144-
145- u32 z = v[sprite_step].XYZ .Z ;
146-
147- if (z & 1 )
148- {
149- // Check that first bit is always 1
150- for (int i = sprite_step; i < count; i += (sprite_step + 1 ))
151- {
152- z &= v[i].XYZ .Z ;
153- }
154- }
155- else
156- {
157- // Check that first bit is always 0
158- for (int i = sprite_step; i < count; i += (sprite_step + 1 ))
159- {
160- z |= v[i].XYZ .Z ;
161- }
162- }
163-
164- if (z == v[sprite_step].XYZ .Z )
165- {
166- m_eq.z = 1 ;
167- }
168- else
169- {
170- m_eq.z = 0 ;
171- }
172- }
0 commit comments