@@ -4156,8 +4156,6 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
4156
4156
// Sometimes hardware doesn't get affected, likely due to the difference in how GPU's handle textures (Persona minimap).
4157
4157
void GSState::RoundSTCoords ()
4158
4158
{
4159
- const bool is_sprite = GSUtil::GetPrimClass (PRIM->PRIM ) == GS_PRIM_CLASS::GS_SPRITE_CLASS;
4160
-
4161
4159
// ST's have the lowest 9 bits (or greater depending on exponent difference) rounded down (from hardware tests).
4162
4160
// This gives the bitmask for the lower 9 (or more) bits.
4163
4161
auto LowerBitsMask = [](int exp, int max_exp)
@@ -4170,9 +4168,11 @@ void GSState::RoundSTCoords()
4170
4168
{
4171
4169
GSVertex* v = &m_vertex.buff [m_index.buff [i]];
4172
4170
4173
- // Only Q on the second vertex is valid
4174
- if (!(i & 1 ) && is_sprite)
4175
- v->RGBAQ .Q = m_vertex.buff [m_index.buff [i + 1 ]].RGBAQ .Q ;
4171
+ if (m_vt.m_primclass == GS_SPRITE_CLASS && (i & 1 ))
4172
+ {
4173
+ // FIXME: Remove this once done debugging
4174
+ pxAssertMsg (m_vertex.buff [m_index.buff [i]].RGBAQ .Q == m_vertex.buff [m_index.buff [i - 1 ]].RGBAQ .Q , " Sprite Qs different" );
4175
+ }
4176
4176
4177
4177
int S = std::bit_cast<int >(v->ST .S );
4178
4178
int T = std::bit_cast<int >(v->ST .T );
@@ -4189,9 +4189,6 @@ void GSState::RoundSTCoords()
4189
4189
v->ST .S = std::bit_cast<float >(S);
4190
4190
v->ST .T = std::bit_cast<float >(T);
4191
4191
4192
- if (!is_sprite || (i & 1 ))
4193
- v->RGBAQ .Q = std::bit_cast<float >(Q);
4194
-
4195
4192
const float U = (v->ST .S / v->RGBAQ .Q ) * (1 << m_context->TEX0 .TW );
4196
4193
const float V = (v->ST .T / v->RGBAQ .Q ) * (1 << m_context->TEX0 .TH );
4197
4194
const float Qf = std::bit_cast<float >(Q);
@@ -4208,48 +4205,39 @@ void GSState::RoundSTCoords()
4208
4205
m_vt.m_max .t = m_vt.m_max .t .min (GSVector4 (2047 .0f )).max (GSVector4 (-2047 .0f )).xyzw (m_vt.m_max .t );
4209
4206
}
4210
4207
4211
- // Handle the huge ST coords in by culling primitives with NaN coords and
4212
- // replacing the primitives with huge coords with a new one that has the huge coordinate replaced with +/- 2047 .
4208
+ // Handle the huge or NaN ST coords culling primitives or replacing
4209
+ // replacing the primitives with valid coordinates .
4213
4210
// This is based on hardware test that show that seem to show that ST coordinate get clamped to +/- 2047
4214
- // (perhaps before applying repeat or region repeat) .
4215
- // Note that the huge texture coords may be a symptom of floating point issues upstream in the EE and
4216
- // it would be better to have them fixed there; this is a bandaid .
4211
+ // before applying repeat or region repeat.
4212
+ // Note that the huge texture coords may be a symptom of floating point issues in the EE and
4213
+ // it would be better to have them fixed there.
4217
4214
void GSState::FixHugeSTCoords ()
4218
4215
{
4219
- bool sprite = GSUtil::GetPrimClass (PRIM->PRIM ) == GS_SPRITE_CLASS;
4220
4216
switch (GSUtil::GetClassVertexCount (GSUtil::GetPrimClass (PRIM->PRIM )))
4221
4217
{
4222
4218
case 1 :
4223
- if (sprite)
4224
- FixHugeSTCoordsImpl<1 , true >();
4225
- else
4226
- FixHugeSTCoordsImpl<1 , false >();
4219
+ FixHugeSTCoordsImpl<1 , false >();
4227
4220
break ;
4228
4221
case 2 :
4229
- if (sprite)
4230
- FixHugeSTCoordsImpl<2 , true >();
4231
- else
4232
- FixHugeSTCoordsImpl<2 , false >();
4222
+ FixHugeSTCoordsImpl<2 , false >();
4233
4223
break ;
4234
4224
case 3 :
4235
- if (sprite)
4236
- FixHugeSTCoordsImpl<3 , true >();
4237
- else
4238
- FixHugeSTCoordsImpl<3 , false >();
4225
+ FixHugeSTCoordsImpl<3 , false >();
4239
4226
break ;
4240
4227
default :
4241
4228
pxFail (" Impossible" );
4242
4229
}
4243
4230
}
4244
4231
4245
- template <u32 n, bool sprite> void GSState::FixHugeSTCoordsImpl ()
4232
+ template <u32 n, bool cull>
4233
+ void GSState::FixHugeSTCoordsImpl ()
4246
4234
{
4247
4235
GSVertex* const vertex = m_vertex.buff ;
4248
4236
u16 * const index = m_index.buff ;
4249
4237
4250
4238
u32 new_index_tail = 0 ;
4251
4239
4252
- constexpr float huge = 1e10f; // arbitrary large value
4240
+ constexpr float huge = 1e10f; // Arbitrary large value
4253
4241
4254
4242
const float tex_width = 1 << m_context->TEX0 .TW ;
4255
4243
const float tex_height = 1 << m_context->TEX0 .TH ;
@@ -4260,138 +4248,92 @@ template <u32 n, bool sprite> void GSState::FixHugeSTCoordsImpl()
4260
4248
{
4261
4249
bool nan_s = false ;
4262
4250
bool nan_t = false ;
4263
- bool huge_s_pos = false ;
4264
- bool huge_s_neg = false ;
4265
- bool huge_t_pos = false ;
4266
- bool huge_t_neg = false ;
4251
+ bool huge_pos_s = false ;
4252
+ bool huge_neg_s = false ;
4253
+ bool huge_pos_t = false ;
4254
+ bool huge_neg_t = false ;
4267
4255
4268
- if (sprite )
4256
+ if (m_vt. m_primclass == GS_SPRITE_CLASS )
4269
4257
{
4270
- // Sprites behave as if both Qs are same as the second one
4271
- const float s0 = vertex[index[i + 0 ]].ST .S / vertex[index[i + 1 ]].RGBAQ .Q ;
4272
- const float t0 = vertex[index[i + 0 ]].ST .T / vertex[index[i + 1 ]].RGBAQ .Q ;
4273
- const float s1 = vertex[index[i + 1 ]].ST .S / vertex[index[i + 1 ]].RGBAQ .Q ;
4274
- const float t1 = vertex[index[i + 1 ]].ST .T / vertex[index[i + 1 ]].RGBAQ .Q ;
4275
- nan_s = std::isnan (s0) || std::isnan (s1);
4276
- nan_t = std::isnan (t0) || std::isnan (t1);
4277
- huge_s_pos = s0 > huge || s1 > huge;
4278
- huge_s_neg = s0 < -huge || s1 < -huge;
4279
- huge_t_pos = t0 > huge || t1 > huge;
4280
- huge_t_neg = t0 < -huge || t1 < -huge;
4258
+ // FIXME: Remove this once done debugging
4259
+ pxAssertMsg (vertex[index[i + 0 ]].RGBAQ .Q == vertex[index[i + 1 ]].RGBAQ .Q , " Sprite Qs different" );
4281
4260
}
4282
- else
4261
+
4262
+ for (u32 j = 0 ; j < n; j++)
4283
4263
{
4284
- for (u32 j = 0 ; j < n; j++)
4285
- {
4286
- const float s = vertex[index[i + j]].ST .S / vertex[index[i + j]].RGBAQ .Q ;
4287
- const float t = vertex[index[i + j]].ST .T / vertex[index[i + j]].RGBAQ .Q ;
4288
- nan_s |= std::isnan (s);
4289
- nan_t |= std::isnan (t);
4290
- huge_s_pos |= s > huge;
4291
- huge_t_pos |= t > huge;
4292
- huge_s_neg |= s < -huge;
4293
- huge_t_neg |= t < -huge;
4294
- }
4264
+ const float s = vertex[index[i + j]].ST .S / vertex[index[i + j]].RGBAQ .Q ;
4265
+ const float t = vertex[index[i + j]].ST .T / vertex[index[i + j]].RGBAQ .Q ;
4266
+ nan_s |= std::isnan (s);
4267
+ nan_t |= std::isnan (t);
4268
+ huge_pos_s |= s > huge;
4269
+ huge_pos_t |= t > huge;
4270
+ huge_neg_s |= s < -huge;
4271
+ huge_neg_t |= t < -huge;
4295
4272
}
4296
4273
4297
4274
// ambiguous = true would probably result in NaN in the SW rasterizer or something undefined in HW.
4298
4275
// PS2 does not have NaN so there is no really accurate way to emulate this.
4299
4276
// huge = true and ambiguous = false seems to have well-defined behavior on the PS2:
4300
4277
// it clamps huge values to +/-2047 in UV coordinates space. We try to approximate this by
4301
4278
// giving ST the values that would result in exactly +/-2047 across the primitive.
4302
- const bool ambiguous = nan_s || nan_t || (huge_s_pos && huge_s_neg) || (huge_s_pos && huge_s_neg);
4303
- const bool huge = huge_s_pos || huge_t_pos || huge_s_neg || huge_t_neg;
4279
+ // For ambiguous values either cull the primitive or replace coordinates by 0.
4280
+ const bool ambiguous_s = nan_s || (huge_pos_s && huge_neg_s);
4281
+ const bool ambiguous_t = nan_t || (huge_pos_t && huge_neg_t );
4304
4282
4305
- if (ambiguous )
4283
+ if ((ambiguous_s || ambiguous_t ) && cull )
4306
4284
{
4307
4285
// Cull the primitive by not saving the indices
4308
4286
continue ;
4309
4287
}
4310
4288
4311
- if (huge )
4289
+ if (huge_pos_s || huge_pos_t || huge_neg_s || huge_neg_t || ambiguous_s || ambiguous_t )
4312
4290
{
4313
4291
// Add new vertices to replace the primitive with another primitive with clamped values.
4314
4292
new_prims = true ;
4315
-
4316
- if (sprite)
4293
+
4294
+ // Copy old values to tail of vertex buffer.
4295
+ // The vertex buffer is allocated so that there is always at least room for 3 new vertices at the end.
4296
+ for (u32 j = 0 ; j < n; j++)
4297
+ vertex[m_vertex.tail + j] = vertex[index[i + j]];
4298
+
4299
+ const float new_u_val = ambiguous_s ? 0 .0f :
4300
+ huge_pos_s ? 2047 .0f :
4301
+ huge_neg_s ? -2047 .0f :
4302
+ NAN;
4303
+ const float new_v_val = ambiguous_t ? 0 .0f :
4304
+ huge_pos_t ? 2047 .0f :
4305
+ huge_neg_t ? -2047 .0f :
4306
+ NAN;
4307
+
4308
+ // If we are replacing both S and T, replace Q by 1.0f
4309
+ if (!std::isnan (new_u_val) && !std::isnan (new_v_val))
4317
4310
{
4318
- // Handle sprite separately since it uses the second Q for both vertices
4319
- GSVertex v_new0 = vertex[index[i + 0 ]];
4320
- GSVertex v_new1 = vertex[index[i + 1 ]];
4321
-
4322
- // Try to set values so that we get constant UV +/-2047 across the entire triangle after interpolation
4323
- // Sprites behave as if both Qs are same as the second one
4324
- if (huge_s_pos)
4325
- {
4326
- v_new1.ST .S = v_new0.ST .S = 2047 .0f * v_new1.RGBAQ .Q / tex_width;
4327
- }
4328
- else if (huge_s_neg)
4329
- {
4330
- v_new1.ST .S = v_new0.ST .S = -2047 .0f * v_new1.RGBAQ .Q / tex_width;
4331
- }
4332
-
4333
- if (huge_t_pos)
4334
- {
4335
- v_new1.ST .T = v_new0.ST .T = 2047 .0f * v_new1.RGBAQ .Q / tex_height;
4336
- }
4337
- else if (huge_t_neg)
4338
- {
4339
- v_new1.ST .T = v_new0.ST .T = -2047 .0f * v_new1.RGBAQ .Q / tex_height;
4340
- }
4341
-
4342
- // Copy old values to tail of vertex buffer.
4343
- // The vertex buffer is allocated so that there is always at least room for 3 new vertices at the end.
4344
- vertex[m_vertex.tail + 0 ] = v_new0;
4345
- vertex[m_vertex.tail + 1 ] = v_new1;
4346
-
4347
- // Make new indices point to new vertices
4348
- index[new_index_tail + 0 ] = m_vertex.tail + 0 ;
4349
- index[new_index_tail + 1 ] = m_vertex.tail + 1 ;
4311
+ for (u32 j = 0 ; j < n; j++)
4312
+ vertex[m_vertex.tail + j].RGBAQ .Q = 1 .0f ;
4350
4313
}
4351
- else
4314
+
4315
+ // Try to replace huge/ambiguous values so that we get constant U or V across the entire primitive after interpolation
4316
+ if (!std::isnan (new_u_val))
4352
4317
{
4353
- // Copy old values to tail of vertex buffer.
4354
- // The vertex buffer is allocated so that there is always at least room for 3 new vertices at the end.
4355
4318
for (u32 j = 0 ; j < n; j++)
4356
- vertex[m_vertex.tail + j] = vertex[index[i + j]];
4357
-
4358
- // Try to set values so that we get constant UV +/-2047 across the entire primitive after interpolation
4359
- if (huge_s_pos)
4360
- {
4361
- for (u32 j = 0 ; j < n; j++)
4362
- vertex[m_vertex.tail + j].ST .S = 2047 .0f * vertex[m_vertex.tail + j].RGBAQ .Q / tex_width;
4363
- }
4364
- else if (huge_s_neg)
4365
- {
4366
- for (u32 j = 0 ; j < n; j++)
4367
- vertex[m_vertex.tail + j].ST .S = -2047 .0f * vertex[m_vertex.tail + j].RGBAQ .Q / tex_width;
4368
- }
4369
-
4370
- if (huge_t_pos)
4371
- {
4372
- for (int j = 0 ; j < n; j++)
4373
- vertex[m_vertex.tail + j].ST .T = 2047 .0f * vertex[m_vertex.tail + j].RGBAQ .Q / tex_height;
4374
- }
4375
- else if (huge_t_neg)
4376
- {
4377
- for (u32 j = 0 ; j < n; j++)
4378
- vertex[m_vertex.tail + j].ST .T = -2047 .0f * vertex[m_vertex.tail + j].RGBAQ .Q / tex_height;
4379
- }
4319
+ vertex[m_vertex.tail + j].ST .S = new_u_val * vertex[m_vertex.tail + j].RGBAQ .Q / tex_width;
4320
+ }
4380
4321
4381
- // Make new indices point to new vertices
4322
+ if (!std::isnan (new_v_val))
4323
+ {
4382
4324
for (u32 j = 0 ; j < n; j++)
4383
- {
4384
- index[new_index_tail + j] = m_vertex.tail + j;
4385
- }
4325
+ vertex[m_vertex.tail + j].ST .T = new_v_val * vertex[m_vertex.tail + j].RGBAQ .Q / tex_width;
4386
4326
}
4387
4327
4328
+ // Make new indices point to new vertices
4329
+ for (u32 j = 0 ; j < n; j++)
4330
+ index[new_index_tail + j] = m_vertex.tail + j;
4331
+
4388
4332
// Advance tail since we pushed new vertices
4389
4333
m_vertex.tail += n;
4390
4334
4391
4335
if (m_vertex.tail >= m_vertex.maxcount )
4392
- {
4393
4336
GrowVertexBuffer ();
4394
- }
4395
4337
}
4396
4338
else if (new_index_tail < i) // If new_index_tail == i, don't update indices since no primitives have been culled
4397
4339
{
@@ -4405,11 +4347,9 @@ template <u32 n, bool sprite> void GSState::FixHugeSTCoordsImpl()
4405
4347
4406
4348
m_index.tail = new_index_tail;
4407
4349
4350
+ // If indexed new primitives at the end of the buffer, update head and next also
4408
4351
if (new_prims)
4409
- {
4410
- // We indexed new primitives at the end of the buffer so update head and next also
4411
4352
m_vertex.head = m_vertex.next = m_vertex.tail ;
4412
- }
4413
4353
}
4414
4354
4415
4355
void GSState::CalcAlphaMinMax (const int tex_alpha_min, const int tex_alpha_max)
0 commit comments