/[pcsx2_0.9.7]/trunk/plugins/GSdx/GSRenderer.cpp
ViewVC logotype

Contents of /trunk/plugins/GSdx/GSRenderer.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 2 months ago) by william
File size: 17968 byte(s)
re-commit (had local access denied errors when committing)
1 /*
2 * Copyright (C) 2007-2009 Gabest
3 * http://www.gabest.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "StdAfx.h"
23 #include "GSRenderer.h"
24
25 GSRenderer::GSRenderer()
26 : GSState()
27 , m_tex_buff( (uint8*)_aligned_malloc(1024 * 1024 * sizeof(uint32), 16) )
28 , m_vt(this)
29 , m_dev(NULL)
30 , m_shader(0)
31 {
32 m_GStitleInfoBuffer[0] = 0;
33
34 m_interlace = theApp.GetConfig("interlace", 0);
35 m_aspectratio = theApp.GetConfig("aspectratio", 1);
36 m_filter = theApp.GetConfig("filter", 1);
37 m_vsync = !!theApp.GetConfig("vsync", 0);
38 m_nativeres = !!theApp.GetConfig("nativeres", 0);
39
40 m_upscale_multiplier = theApp.GetConfig("upscale_multiplier", 1);
41 if(m_nativeres) m_upscale_multiplier = 1;
42 else if (m_upscale_multiplier > 6) m_upscale_multiplier = 1;
43
44 m_aa1 = !!theApp.GetConfig("aa1", 0);
45
46 if(m_nativeres) m_filter = 2;
47
48 s_n = 0;
49 s_dump = !!theApp.GetConfig("dump", 0);
50 s_save = !!theApp.GetConfig("save", 0);
51 s_savez = !!theApp.GetConfig("savez", 0);
52 s_saven = theApp.GetConfig("saven", 0);
53
54 InitializeCriticalSection(&m_pGSsetTitle_Crit);
55 }
56
57 GSRenderer::~GSRenderer()
58 {
59 /*if(m_dev)
60 {
61 m_dev->Reset(1, 1, GSDevice::Windowed);
62 }*/
63
64 _aligned_free( m_tex_buff );
65
66 delete m_dev;
67 DeleteCriticalSection(&m_pGSsetTitle_Crit);
68 }
69
70 bool GSRenderer::CreateWnd(const string& title, int w, int h)
71 {
72 if(!m_wnd.Create(title.c_str(), w, h))
73 {
74 return false;
75 }
76 return true;
77 }
78
79 bool GSRenderer::CreateDevice(GSDevice* dev)
80 {
81 ASSERT(dev);
82 ASSERT(!m_dev);
83
84 if(!dev->Create(&m_wnd))
85 {
86 return false;
87 }
88
89 m_dev = dev;
90 m_dev->SetVsync( m_vsync && m_framelimit );
91
92 return true;
93 }
94
95 bool GSRenderer::Merge(int field)
96 {
97 bool en[2];
98
99 GSVector4i fr[2];
100 GSVector4i dr[2];
101
102 int baseline = INT_MAX;
103
104 for(int i = 0; i < 2; i++)
105 {
106 en[i] = IsEnabled(i);
107
108 if(en[i])
109 {
110 fr[i] = GetFrameRect(i);
111 dr[i] = GetDisplayRect(i);
112
113 baseline = min(dr[i].top, baseline);
114
115 // printf("[%d]: %d %d %d %d, %d %d %d %d\n", i, fr[i], dr[i]);
116 }
117 }
118
119 if(!en[0] && !en[1])
120 {
121 return false;
122 }
123
124 // try to avoid fullscreen blur, could be nice on tv but on a monitor it's like double vision, hurts my eyes (persona 4, guitar hero)
125 //
126 // NOTE: probably the technique explained in graphtip.pdf (Antialiasing by Supersampling / 4. Reading Odd/Even Scan Lines Separately with the PCRTC then Blending)
127
128 bool samesrc =
129 en[0] && en[1] &&
130 m_regs->DISP[0].DISPFB.FBP == m_regs->DISP[1].DISPFB.FBP &&
131 m_regs->DISP[0].DISPFB.FBW == m_regs->DISP[1].DISPFB.FBW &&
132 m_regs->DISP[0].DISPFB.PSM == m_regs->DISP[1].DISPFB.PSM;
133
134 bool blurdetected = false;
135
136 if(samesrc /*&& m_regs->PMODE.SLBG == 0 && m_regs->PMODE.MMOD == 1 && m_regs->PMODE.ALP == 0x80*/)
137 {
138 if(fr[0].eq(fr[1] + GSVector4i(0, -1, 0, 0)) && dr[0].eq(dr[1] + GSVector4i(0, 0, 0, 1))
139 || fr[1].eq(fr[0] + GSVector4i(0, -1, 0, 0)) && dr[1].eq(dr[0] + GSVector4i(0, 0, 0, 1)))
140 {
141 // persona 4:
142 //
143 // fr[0] = 0 0 640 448
144 // fr[1] = 0 1 640 448
145 // dr[0] = 159 50 779 498
146 // dr[1] = 159 50 779 497
147 //
148 // second image shifted up by 1 pixel and blended over itself
149 //
150 // god of war:
151 //
152 // fr[0] = 0 1 512 448
153 // fr[1] = 0 0 512 448
154 // dr[0] = 127 50 639 497
155 // dr[1] = 127 50 639 498
156 //
157 // same just the first image shifted
158
159 int top = min(fr[0].top, fr[1].top);
160 int bottom = max(dr[0].bottom, dr[1].bottom);
161
162 fr[0].top = top;
163 fr[1].top = top;
164 dr[0].bottom = bottom;
165 dr[1].bottom = bottom;
166
167 blurdetected = true;
168 }
169 else if(dr[0].eq(dr[1]) && (fr[0].eq(fr[1] + GSVector4i(0, 1, 0, 1)) || fr[1].eq(fr[0] + GSVector4i(0, 1, 0, 1))))
170 {
171 // dq5:
172 //
173 // fr[0] = 0 1 512 445
174 // fr[1] = 0 0 512 444
175 // dr[0] = 127 50 639 494
176 // dr[1] = 127 50 639 494
177
178 int top = min(fr[0].top, fr[1].top);
179 int bottom = min(fr[0].bottom, fr[1].bottom);
180
181 fr[0].top = fr[1].top = top;
182 fr[0].bottom = fr[1].bottom = bottom;
183
184 blurdetected = true;
185 }
186 //printf("samesrc = %d blurdetected = %d\n",samesrc,blurdetected);
187 }
188
189 GSVector2i fs(0, 0);
190 GSVector2i ds(0, 0);
191
192 GSTexture* tex[2] = {NULL, NULL};
193
194 if(samesrc && fr[0].bottom == fr[1].bottom)
195 {
196 tex[0] = GetOutput(0);
197 tex[1] = tex[0]; // saves one texture fetch
198 }
199 else
200 {
201 if(en[0]) tex[0] = GetOutput(0);
202 if(en[1]) tex[1] = GetOutput(1);
203 }
204
205 GSVector4 src[2];
206 GSVector4 dst[2];
207
208 for(int i = 0; i < 2; i++)
209 {
210 if(!en[i] || !tex[i]) continue;
211
212 GSVector4i r = fr[i];
213
214 // overscan hack
215
216 if(dr[i].height() > 512) // hmm
217 {
218 int y = GetDeviceSize(i).y;
219 if(m_regs->SMODE2.INT && m_regs->SMODE2.FFMD) y /= 2;
220 r.bottom = r.top + y;
221 }
222
223 // Breaks the blur filter, and actually makes games blurry again.
224 // This might have to do with earlier changes to device size detection.
225 /*if(blurdetected && i == 1)
226 {
227 r += GSVector4i(0, 1).xyxy();
228 }*/
229
230 GSVector4 scale = GSVector4(tex[i]->GetScale()).xyxy();
231
232 src[i] = GSVector4(r) * scale / GSVector4(tex[i]->GetSize()).xyxy();
233
234 GSVector2 o(0, 0);
235
236 if(dr[i].top - baseline >= 4) // 2?
237 {
238 o.y = tex[i]->GetScale().y * (dr[i].top - baseline);
239
240 if(m_regs->SMODE2.INT && m_regs->SMODE2.FFMD)
241 {
242 o.y /= 2;
243 }
244 }
245
246 dst[i] = GSVector4(o).xyxy() + scale * GSVector4(r.rsize());
247
248 fs.x = max(fs.x, (int)(dst[i].z + 0.5f));
249 fs.y = max(fs.y, (int)(dst[i].w + 0.5f));
250 }
251
252 ds = fs;
253
254 if(m_regs->SMODE2.INT && m_regs->SMODE2.FFMD)
255 {
256 ds.y *= 2;
257 }
258
259 bool slbg = m_regs->PMODE.SLBG;
260 bool mmod = m_regs->PMODE.MMOD;
261
262 if(tex[0] || tex[1])
263 {
264 GSVector4 c = GSVector4((int)m_regs->BGCOLOR.R, (int)m_regs->BGCOLOR.G, (int)m_regs->BGCOLOR.B, (int)m_regs->PMODE.ALP) / 255;
265
266 m_dev->Merge(tex, src, dst, fs, slbg, mmod, c);
267
268 if(m_regs->SMODE2.INT && m_interlace > 0)
269 {
270 int field2 = 1 - ((m_interlace - 1) & 1);
271 int mode = (m_interlace - 1) >> 1;
272
273 m_dev->Interlace(ds, field ^ field2, mode, tex[1] ? tex[1]->GetScale().y : tex[0]->GetScale().y);
274 }
275 }
276
277 return true;
278 }
279
280 void GSRenderer::SetFrameLimit(bool limit)
281 {
282 m_framelimit = limit;
283 if( m_dev ) m_dev->SetVsync(m_vsync && m_framelimit);
284 }
285
286 void GSRenderer::SetVsync(bool enabled)
287 {
288 m_vsync = enabled;
289 if( m_dev ) m_dev->SetVsync(m_vsync);
290 }
291
292
293 void GSRenderer::VSync(int field)
294 {
295 GSPerfMonAutoTimer pmat(m_perfmon);
296
297 m_perfmon.Put(GSPerfMon::Frame);
298
299 Flush();
300
301 if(!m_dev->IsLost(true))
302 {
303 if(!Merge(field ? 1 : 0))
304 {
305 return;
306 }
307 }
308 else
309 {
310 ResetDevice();
311 }
312
313 // osd
314
315 if((m_perfmon.GetFrame() & 0x1f) == 0)
316 {
317 m_perfmon.Update();
318
319 double fps = 1000.0f / m_perfmon.Get(GSPerfMon::Frame);
320
321 GSVector4i r = GetDisplayRect();
322
323 string s;
324
325 #ifdef GSTITLEINFO_API_FORCE_VERBOSE
326 if (1)//force verbose reply
327 #else
328 if (m_wnd.IsManaged())
329 #endif
330 {//GSdx owns the window's title, be verbose.
331 string s2 = m_regs->SMODE2.INT ? (string("Interlaced ") + (m_regs->SMODE2.FFMD ? "(frame)" : "(field)")) : "Progressive";
332 s = format(
333 "%I64d | %d x %d | %.2f fps (%d%%) | %s - %s | %s | %d/%d/%d | %d%% CPU | %.2f | %.2f",
334 m_perfmon.GetFrame(), r.width(), r.height(), fps, (int)(100.0 * fps / GetFPS()),
335 s2.c_str(),
336 GSSettingsDlg::g_interlace[m_interlace].name.c_str(),
337 GSSettingsDlg::g_aspectratio[m_aspectratio].name.c_str(),
338 (int)m_perfmon.Get(GSPerfMon::Quad),
339 (int)m_perfmon.Get(GSPerfMon::Prim),
340 (int)m_perfmon.Get(GSPerfMon::Draw),
341 m_perfmon.CPU(),
342 m_perfmon.Get(GSPerfMon::Swizzle) / 1024,
343 m_perfmon.Get(GSPerfMon::Unswizzle) / 1024
344 );
345
346 double fillrate = m_perfmon.Get(GSPerfMon::Fillrate);
347
348 if(fillrate > 0)
349 {
350 s += format(" | %.2f mpps", fps * fillrate / (1024 * 1024));
351 }
352
353 }
354 else
355 {
356 //Satisfy PCSX2's request for title info: minimal verbosity due to more external title text
357 s = format(
358 "%dx%d | %s",
359 r.width(), r.height(),
360 GSSettingsDlg::g_interlace[m_interlace].name.c_str()
361 );
362 }
363
364
365 if(m_capture.IsCapturing())
366 {
367 s += " | Recording...";
368 }
369
370 if (m_wnd.IsManaged())
371 {
372 m_wnd.SetWindowText(s.c_str());
373 }
374 else
375 {
376 // note: do not use TryEnterCriticalSection. It is unnecessary code complication in
377 // an area that absolutely does not matter (even if it were 100 times slower, it wouldn't
378 // be noticeable). Besides, these locks are extremely short -- overhead of conditional
379 // is way more expensive than just waiting for the CriticalSection in 1 of 10,000,000 tries. --air
380
381 EnterCriticalSection(&m_pGSsetTitle_Crit);
382
383 strncpy(m_GStitleInfoBuffer, s.c_str(), ArraySize(m_GStitleInfoBuffer)-1);
384 m_GStitleInfoBuffer[sizeof(m_GStitleInfoBuffer)-1] = 0;// make sure null terminated even if text overflows
385
386 LeaveCriticalSection(&m_pGSsetTitle_Crit);
387 }
388
389
390 }
391 else
392 {
393 // [TODO]
394 // We don't have window title rights, or the window has no title,
395 // so let's use actual OSD!
396 }
397
398 if(m_frameskip)
399 {
400 return;
401 }
402
403 // present
404
405 m_dev->Present(m_wnd.GetClientRect().fit(m_aspectratio), m_shader);
406
407 // snapshot
408
409 if(!m_snapshot.empty())
410 {
411 if(!m_dump && (::GetAsyncKeyState(VK_SHIFT) & 0x8000))
412 {
413 GSFreezeData fd;
414 fd.size = 0;
415 fd.data = NULL;
416 Freeze(&fd, true);
417 fd.data = new uint8[fd.size];
418 Freeze(&fd, false);
419
420 m_dump.Open(m_snapshot, m_crc, fd, m_regs);
421
422 delete [] fd.data;
423 }
424
425 if(GSTexture* t = m_dev->GetCurrent())
426 {
427 t->Save(m_snapshot + ".bmp");
428 }
429
430 m_snapshot.clear();
431 }
432 else
433 {
434 if(m_dump)
435 {
436 m_dump.VSync(field, !(::GetAsyncKeyState(VK_CONTROL) & 0x8000), m_regs);
437 }
438 }
439
440 // capture
441
442 if(m_capture.IsCapturing())
443 {
444 if(GSTexture* current = m_dev->GetCurrent())
445 {
446 GSVector2i size = m_capture.GetSize();
447
448 if(GSTexture* offscreen = m_dev->CopyOffscreen(current, GSVector4(0, 0, 1, 1), size.x, size.y))
449 {
450 GSTexture::GSMap m;
451
452 if(offscreen->Map(m))
453 {
454 m_capture.DeliverFrame(m.bits, m.pitch, !m_dev->IsRBSwapped());
455
456 offscreen->Unmap();
457 }
458
459 m_dev->Recycle(offscreen);
460 }
461 }
462 }
463 }
464
465 bool GSRenderer::MakeSnapshot(const string& path)
466 {
467 if(m_snapshot.empty())
468 {
469 time_t t = time(NULL);
470
471 char buff[16];
472
473 if(strftime(buff, sizeof(buff), "%Y%m%d%H%M%S", localtime(&t)))
474 {
475 m_snapshot = format("%s_%s", path.c_str(), buff);
476 }
477 }
478
479 return true;
480 }
481
482 void GSRenderer::BeginCapture()
483 {
484 m_capture.BeginCapture(GetFPS());
485 }
486
487 void GSRenderer::EndCapture()
488 {
489 m_capture.EndCapture();
490 }
491
492 void GSRenderer::KeyEvent(GSKeyEventData* e)
493 {
494 if(e->type == KEYPRESS)
495 {
496 // TODO: linux
497
498 int step = (::GetAsyncKeyState(VK_SHIFT) & 0x8000) ? -1 : 1;
499
500 switch(e->key)
501 {
502 case VK_F5:
503 m_interlace = (m_interlace + 7 + step) % 7;
504 return;
505 case VK_F6:
506 m_aspectratio = (m_aspectratio + 3 + step) % 3;
507 return;
508 case VK_F7:
509 m_shader = (m_shader + 3 + step) % 3;
510 return;
511 case VK_DELETE:
512 m_aa1 = !m_aa1;
513 return;
514 }
515 }
516 }
517
518 void GSRenderer::GetTextureMinMax(GSVector4i& r, bool linear)
519 {
520 const GSDrawingContext* context = m_context;
521
522 int tw = context->TEX0.TW;
523 int th = context->TEX0.TH;
524
525 int w = 1 << tw;
526 int h = 1 << th;
527
528 GSVector4i tr(0, 0, w, h);
529
530 int wms = context->CLAMP.WMS;
531 int wmt = context->CLAMP.WMT;
532
533 int minu = (int)context->CLAMP.MINU;
534 int minv = (int)context->CLAMP.MINV;
535 int maxu = (int)context->CLAMP.MAXU;
536 int maxv = (int)context->CLAMP.MAXV;
537
538 GSVector4i vr = tr;
539
540 switch(wms)
541 {
542 case CLAMP_REPEAT:
543 break;
544 case CLAMP_CLAMP:
545 break;
546 case CLAMP_REGION_CLAMP:
547 if(vr.x < minu) vr.x = minu;
548 if(vr.z > maxu + 1) vr.z = maxu + 1;
549 break;
550 case CLAMP_REGION_REPEAT:
551 vr.x = maxu;
552 vr.z = vr.x + (minu + 1);
553 break;
554 default:
555 __assume(0);
556 }
557
558 switch(wmt)
559 {
560 case CLAMP_REPEAT:
561 break;
562 case CLAMP_CLAMP:
563 break;
564 case CLAMP_REGION_CLAMP:
565 if(vr.y < minv) vr.y = minv;
566 if(vr.w > maxv + 1) vr.w = maxv + 1;
567 break;
568 case CLAMP_REGION_REPEAT:
569 vr.y = maxv;
570 vr.w = vr.y + (minv + 1);
571 break;
572 default:
573 __assume(0);
574 }
575
576 if(wms + wmt < 6)
577 {
578 GSVector4 st = m_vt.m_min.t.xyxy(m_vt.m_max.t);
579
580 if(linear)
581 {
582 st += GSVector4(-0x8000, 0x8000).xxyy();
583 }
584
585 GSVector4i uv = GSVector4i(st).sra32(16);
586
587 GSVector4i u, v;
588
589 int mask = 0;
590
591 if(wms == CLAMP_REPEAT || wmt == CLAMP_REPEAT)
592 {
593 u = uv & GSVector4i::xffffffff().srl32(32 - tw);
594 v = uv & GSVector4i::xffffffff().srl32(32 - th);
595
596 GSVector4i uu = uv.sra32(tw);
597 GSVector4i vv = uv.sra32(th);
598
599 mask = (uu.upl32(vv) == uu.uph32(vv)).mask();
600 }
601
602 uv = uv.rintersect(tr);
603
604 switch(wms)
605 {
606 case CLAMP_REPEAT:
607 if(mask & 0x000f) {if(vr.x < u.x) vr.x = u.x; if(vr.z > u.z + 1) vr.z = u.z + 1;}
608 break;
609 case CLAMP_CLAMP:
610 case CLAMP_REGION_CLAMP:
611 if(vr.x < uv.x) vr.x = uv.x;
612 if(vr.z > uv.z + 1) vr.z = uv.z + 1;
613 break;
614 case CLAMP_REGION_REPEAT: // TODO
615 break;
616 default:
617 __assume(0);
618 }
619
620 switch(wmt)
621 {
622 case CLAMP_REPEAT:
623 if(mask & 0xf000) {if(vr.y < v.y) vr.y = v.y; if(vr.w > v.w + 1) vr.w = v.w + 1;}
624 break;
625 case CLAMP_CLAMP:
626 case CLAMP_REGION_CLAMP:
627 if(vr.y < uv.y) vr.y = uv.y;
628 if(vr.w > uv.w + 1) vr.w = uv.w + 1;
629 break;
630 case CLAMP_REGION_REPEAT: // TODO
631 //Xenosaga 2 and 3 use it
632 //printf("gsdx: CLAMP_REGION_REPEAT not implemented, please report\n");
633 break;
634 default:
635 __assume(0);
636 }
637 }
638
639 r = vr.rintersect(tr);
640 }
641
642 void GSRenderer::GetAlphaMinMax()
643 {
644 if(m_vt.m_alpha.valid)
645 {
646 return;
647 }
648
649 const GSDrawingEnvironment& env = m_env;
650 const GSDrawingContext* context = m_context;
651
652 GSVector4i a = m_vt.m_min.c.uph32(m_vt.m_max.c).zzww();
653
654 if(PRIM->TME && context->TEX0.TCC)
655 {
656 switch(GSLocalMemory::m_psm[context->TEX0.PSM].fmt)
657 {
658 case 0:
659 a.y = 0;
660 a.w = 0xff;
661 break;
662 case 1:
663 a.y = env.TEXA.AEM ? 0 : env.TEXA.TA0;
664 a.w = env.TEXA.TA0;
665 break;
666 case 2:
667 a.y = env.TEXA.AEM ? 0 : min(env.TEXA.TA0, env.TEXA.TA1);
668 a.w = max(env.TEXA.TA0, env.TEXA.TA1);
669 break;
670 case 3:
671 m_mem.m_clut.GetAlphaMinMax32(a.y, a.w);
672 break;
673 default:
674 __assume(0);
675 }
676
677 switch(context->TEX0.TFX)
678 {
679 case TFX_MODULATE:
680 a.x = (a.x * a.y) >> 7;
681 a.z = (a.z * a.w) >> 7;
682 if(a.x > 0xff) a.x = 0xff;
683 if(a.z > 0xff) a.z = 0xff;
684 break;
685 case TFX_DECAL:
686 a.x = a.y;
687 a.z = a.w;
688 break;
689 case TFX_HIGHLIGHT:
690 a.x = a.x + a.y;
691 a.z = a.z + a.w;
692 if(a.x > 0xff) a.x = 0xff;
693 if(a.z > 0xff) a.z = 0xff;
694 break;
695 case TFX_HIGHLIGHT2:
696 a.x = a.y;
697 a.z = a.w;
698 break;
699 default:
700 __assume(0);
701 }
702 }
703
704 m_vt.m_alpha.min = a.x;
705 m_vt.m_alpha.max = a.z;
706 m_vt.m_alpha.valid = true;
707 }
708
709 bool GSRenderer::TryAlphaTest(uint32& fm, uint32& zm)
710 {
711 const GSDrawingContext* context = m_context;
712
713 bool pass = true;
714
715 if(context->TEST.ATST == ATST_NEVER)
716 {
717 pass = false;
718 }
719 else if(context->TEST.ATST != ATST_ALWAYS)
720 {
721 GetAlphaMinMax();
722
723 int amin = m_vt.m_alpha.min;
724 int amax = m_vt.m_alpha.max;
725
726 int aref = context->TEST.AREF;
727
728 switch(context->TEST.ATST)
729 {
730 case ATST_NEVER:
731 pass = false;
732 break;
733 case ATST_ALWAYS:
734 pass = true;
735 break;
736 case ATST_LESS:
737 if(amax < aref) pass = true;
738 else if(amin >= aref) pass = false;
739 else return false;
740 break;
741 case ATST_LEQUAL:
742 if(amax <= aref) pass = true;
743 else if(amin > aref) pass = false;
744 else return false;
745 break;
746 case ATST_EQUAL:
747 if(amin == aref && amax == aref) pass = true;
748 else if(amin > aref || amax < aref) pass = false;
749 else return false;
750 break;
751 case ATST_GEQUAL:
752 if(amin >= aref) pass = true;
753 else if(amax < aref) pass = false;
754 else return false;
755 break;
756 case ATST_GREATER:
757 if(amin > aref) pass = true;
758 else if(amax <= aref) pass = false;
759 else return false;
760 break;
761 case ATST_NOTEQUAL:
762 if(amin == aref && amax == aref) pass = false;
763 else if(amin > aref || amax < aref) pass = true;
764 else return false;
765 break;
766 default:
767 __assume(0);
768 }
769 }
770
771 if(!pass)
772 {
773 switch(context->TEST.AFAIL)
774 {
775 case AFAIL_KEEP: fm = zm = 0xffffffff; break;
776 case AFAIL_FB_ONLY: zm = 0xffffffff; break;
777 case AFAIL_ZB_ONLY: fm = 0xffffffff; break;
778 case AFAIL_RGB_ONLY: fm |= 0xff000000; zm = 0xffffffff; break;
779 default: __assume(0);
780 }
781 }
782
783 return true;
784 }
785
786 bool GSRenderer::IsLinear()
787 {
788 const GIFRegTEX1& TEX1 = m_context->TEX1;
789
790 bool mmin = TEX1.IsMinLinear();
791 bool mmag = TEX1.IsMagLinear();
792
793 if(mmag == mmin || TEX1.MXL == 0) // MXL == 0 => MMIN ignored, tested it on ps2
794 {
795 return mmag;
796 }
797 // if FST => assume Q = 1.0f (should not, but Q is very often bogus, 0 or DEN)
798 // Fixme : Why should Q be bogus?
799 if(!TEX1.LCM && !PRIM->FST)
800 {
801 float K = (float)TEX1.K / 16;
802 float f = (float)(1 << TEX1.L) / log(2.0f);
803
804 // TODO: abs(Qmin) may not be <= abs(Qmax), check the sign
805
806 float LODmin = K + log(1.0f / abs(m_vt.m_max.t.z)) * f;
807 float LODmax = K + log(1.0f / abs(m_vt.m_min.t.z)) * f;
808
809 return LODmax <= 0 ? mmag : LODmin > 0 ? mmin : mmag || mmin;
810 }
811 else
812 {
813 return TEX1.K <= 0 ? mmag : TEX1.K > 0 ? mmin : mmag || mmin;
814 }
815 }
816
817 bool GSRenderer::IsOpaque()
818 {
819 if(PRIM->AA1)
820 {
821 return false;
822 }
823
824 if(!PRIM->ABE)
825 {
826 return true;
827 }
828
829 const GSDrawingContext* context = m_context;
830
831 int amin = 0, amax = 0xff;
832
833 if(context->ALPHA.A != context->ALPHA.B)
834 {
835 if(context->ALPHA.C == 0)
836 {
837 GetAlphaMinMax();
838
839 amin = m_vt.m_alpha.min;
840 amax = m_vt.m_alpha.max;
841 }
842 else if(context->ALPHA.C == 1)
843 {
844 if(context->FRAME.PSM == PSM_PSMCT24 || context->FRAME.PSM == PSM_PSMZ24)
845 {
846 amin = amax = 0x80;
847 }
848 }
849 else if(context->ALPHA.C == 2)
850 {
851 amin = amax = context->ALPHA.FIX;
852 }
853 }
854
855 return context->ALPHA.IsOpaque(amin, amax);
856 }

  ViewVC Help
Powered by ViewVC 1.1.22