1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
22 #include "StringUtil.h"
28 #include "Statistics.h"
30 #include "VideoConfig.h"
32 #include "VertexManager.h"
34 #include "OpcodeDecoding.h"
35 #include "BPStructs.h"
36 #include "XFStructs.h"
38 #include "VertexShaderManager.h"
39 #include "PixelShaderManager.h"
40 #include "VertexShaderCache.h"
41 #include "PixelShaderCache.h"
42 #include "VertexLoaderManager.h"
43 #include "TextureCache.h"
44 #include "EmuWindow.h"
46 #include "OnScreenDisplay.h"
47 #include "FramebufferManager.h"
49 #include "TextureConverter.h"
52 #include "debugger/debugger.h"
56 static bool WindowResized
;
57 static int s_target_width
;
58 static int s_target_height
;
60 static int s_Fulltarget_width
;
61 static int s_Fulltarget_height
;
63 static int s_backbuffer_width
;
64 static int s_backbuffer_height
;
66 static int s_XFB_width
;
67 static int s_XFB_height
;
72 static float EFBxScale
;
73 static float EFByScale
;
75 static int s_recordWidth
;
76 static int s_recordHeight
;
78 static bool s_bLastFrameDumped
;
79 static bool s_bAVIDumping
;
81 static u32 s_blendMode
;
83 static u32 s_LastEFBScale
;
85 static bool XFBWrited
= false;
87 // used extern by other files. need to clean this up at some point.
92 static bool s_bScreenshot
= false;
93 static Common::CriticalSection s_criticalScreenshot
;
94 static char s_sScreenshotName
[1024];
95 static LPDIRECT3DSURFACE9 ScreenShootMEMSurface
= NULL
;
98 // State translation lookup tables
99 static const D3DBLEND d3dSrcFactors
[8] =
104 D3DBLEND_INVDESTCOLOR
,
106 D3DBLEND_INVSRCALPHA
,
108 D3DBLEND_INVDESTALPHA
111 static const D3DBLEND d3dDestFactors
[8] =
116 D3DBLEND_INVSRCCOLOR
,
118 D3DBLEND_INVSRCALPHA
,
120 D3DBLEND_INVDESTALPHA
124 // 1 Source & destination
125 // 2 Source & ~destination
127 // 4 ~Source & destination
129 // 6 Source ^ destination = Source & ~destination | ~Source & destination
130 // 7 Source | destination
132 // 8 ~(Source | destination)
133 // 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination
135 // 11 Source | ~destination
137 // 13 ~Source | destination
138 // 14 ~(Source & destination)
141 static const D3DBLENDOP d3dLogicOpop
[16] =
147 D3DBLENDOP_REVSUBTRACT
,
162 static const D3DBLEND d3dLogicOpSrcFactors
[16] =
170 D3DBLEND_INVDESTCOLOR
,
171 D3DBLEND_INVDESTCOLOR
,
173 D3DBLEND_INVSRCCOLOR
,
174 D3DBLEND_INVSRCCOLOR
,
175 D3DBLEND_INVDESTCOLOR
,
177 D3DBLEND_INVSRCCOLOR
,
178 D3DBLEND_INVSRCCOLOR
,
179 D3DBLEND_INVDESTCOLOR
,
183 static const D3DBLEND d3dLogicOpDestFactors
[16] =
187 D3DBLEND_INVSRCCOLOR
,
191 D3DBLEND_INVSRCCOLOR
,
194 D3DBLEND_INVDESTCOLOR
,
196 D3DBLEND_INVDESTCOLOR
,
197 D3DBLEND_INVDESTCOLOR
,
198 D3DBLEND_INVSRCCOLOR
,
200 D3DBLEND_INVSRCCOLOR
,
204 static const D3DCULL d3dCullModes
[4] =
212 static const D3DCMPFUNC d3dCmpFuncs
[8] =
224 static const D3DTEXTUREFILTERTYPE d3dMipFilters
[4] =
229 D3DTEXF_NONE
, //reserved
232 static const D3DTEXTUREADDRESS d3dClamps
[4] =
237 D3DTADDRESS_WRAP
//reserved
240 void SetupDeviceObjects()
243 VertexLoaderManager::Init();
244 g_framebufferManager
.Create();
246 VertexShaderManager::Dirty();
247 PixelShaderManager::Dirty();
248 TextureConverter::Init();
250 // To avoid shader compilation stutters, read back all shaders from cache.
251 VertexShaderCache::Init();
252 PixelShaderCache::Init();
253 // Texture cache will recreate themselves over time.
256 // Kill off all POOL_DEFAULT device objects.
257 void TeardownDeviceObjects()
259 if(ScreenShootMEMSurface
)
260 ScreenShootMEMSurface
->Release();
261 ScreenShootMEMSurface
= NULL
;
262 D3D::dev
->SetRenderTarget(0, D3D::GetBackBufferSurface());
263 D3D::dev
->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface());
264 g_framebufferManager
.Destroy();
265 D3D::font
.Shutdown();
266 TextureCache::Invalidate(false);
267 VertexLoaderManager::Shutdown();
268 VertexShaderCache::Shutdown();
269 PixelShaderCache::Shutdown();
270 TextureConverter::Shutdown();
274 bool Renderer::Init()
276 st
= new char[32768];
277 UpdateActiveConfig();
278 int fullScreenRes
, x
, y
, w_temp
, h_temp
;
280 // Multisample Anti-aliasing hasn't been implemented yet use supersamling instead
281 int backbuffer_ms_mode
= 0;
283 g_VideoInitialize
.pRequestWindowSize(x
, y
, w_temp
, h_temp
);
285 for (fullScreenRes
= 0; fullScreenRes
< (int)D3D::GetAdapter(g_ActiveConfig
.iAdapter
).resolutions
.size(); fullScreenRes
++)
287 if ((D3D::GetAdapter(g_ActiveConfig
.iAdapter
).resolutions
[fullScreenRes
].xres
== w_temp
) &&
288 (D3D::GetAdapter(g_ActiveConfig
.iAdapter
).resolutions
[fullScreenRes
].yres
== h_temp
))
291 if (fullScreenRes
== D3D::GetAdapter(g_ActiveConfig
.iAdapter
).resolutions
.size())
294 D3D::Create(g_ActiveConfig
.iAdapter
, EmuWindow::GetWnd(),
295 fullScreenRes
, backbuffer_ms_mode
, false);
297 IS_AMD
= D3D::IsATIDevice();
299 // Decide frambuffer size
300 s_backbuffer_width
= D3D::GetBackBufferWidth();
301 s_backbuffer_height
= D3D::GetBackBufferHeight();
303 s_XFB_width
= MAX_XFB_WIDTH
;
304 s_XFB_height
= MAX_XFB_HEIGHT
;
306 TargetRectangle dst_rect
;
307 ComputeDrawRectangle(s_backbuffer_width
, s_backbuffer_height
, false, &dst_rect
);
309 if(g_ActiveConfig
.bUseRealXFB
)
316 xScale
= (float)(dst_rect
.right
- dst_rect
.left
) / (float)s_XFB_width
;
317 yScale
= (float)(dst_rect
.bottom
- dst_rect
.top
) / (float)s_XFB_height
;
320 s_LastAA
= g_ActiveConfig
.iMultisampleMode
;
321 s_LastEFBScale
= g_ActiveConfig
.iEFBScale
;
322 float SupersampleCoeficient
= s_LastAA
+ 1;
323 switch(s_LastEFBScale
)
330 EFBxScale
= ceilf(xScale
);
331 EFByScale
= ceilf(yScale
);
334 EFBxScale
= g_ActiveConfig
.iEFBScale
- 1;
335 EFByScale
= EFBxScale
;
339 EFBxScale
*= SupersampleCoeficient
;
340 EFByScale
*= SupersampleCoeficient
;
342 s_target_width
= EFB_WIDTH
* EFBxScale
;
343 s_target_height
= EFB_HEIGHT
* EFByScale
;
345 s_Fulltarget_width
= s_target_width
;
346 s_Fulltarget_height
= s_target_height
;
348 s_bLastFrameDumped
= false;
349 s_bAVIDumping
= false;
351 // We're not using fixed function.
352 // Let's just set the matrices to identity to be sure.
354 D3DXMatrixIdentity(&mtx
);
355 D3D::dev
->SetTransform(D3DTS_VIEW
, &mtx
);
356 D3D::dev
->SetTransform(D3DTS_WORLD
, &mtx
);
358 SetupDeviceObjects();
360 for (int stage
= 0; stage
< 8; stage
++)
361 D3D::SetSamplerState(stage
, D3DSAMP_MAXANISOTROPY
, g_ActiveConfig
.iMaxAnisotropy
);
366 vp
.Width
= s_backbuffer_width
;
367 vp
.Height
= s_backbuffer_height
;
370 D3D::dev
->SetViewport(&vp
);
371 D3D::dev
->Clear(0, NULL
, D3DCLEAR_TARGET
, 0x0, 0, 0);
373 D3D::dev
->SetRenderTarget(0, g_framebufferManager
.GetEFBColorRTSurface());
374 D3D::dev
->SetDepthStencilSurface(g_framebufferManager
.GetEFBDepthRTSurface());
375 vp
.X
= (s_Fulltarget_width
- s_target_width
) / 2;
376 vp
.Y
= (s_Fulltarget_height
- s_target_height
) / 2;
377 vp
.Width
= s_target_width
;
378 vp
.Height
= s_target_height
;
379 D3D::dev
->SetViewport(&vp
);
380 D3D::dev
->Clear(0, NULL
, D3DCLEAR_TARGET
| D3DCLEAR_ZBUFFER
, 0x0, 1.0f
, 0);
382 D3D::SetRenderState(D3DRS_SCISSORTESTENABLE
, true);
383 D3D::dev
->CreateOffscreenPlainSurface(s_backbuffer_width
,s_backbuffer_height
, D3DFMT_X8R8G8B8
, D3DPOOL_SYSTEMMEM
, &ScreenShootMEMSurface
, NULL
);
387 void Renderer::Shutdown()
389 TeardownDeviceObjects();
401 // Return the rendering target width and height
402 int Renderer::GetTargetWidth()
404 return s_target_width
;
407 int Renderer::GetTargetHeight()
409 return s_target_height
;
412 int Renderer::GetFullTargetWidth()
414 return s_Fulltarget_width
;
417 int Renderer::GetFullTargetHeight()
419 return s_Fulltarget_height
;
422 float Renderer::GetTargetScaleX()
427 float Renderer::GetTargetScaleY()
432 float Renderer::GetXFBScaleX()
437 float Renderer::GetXFBScaleY()
442 // Create On-Screen-Messages
443 void Renderer::DrawDebugText()
446 if (g_ActiveConfig
.bOSDHotKey
)
450 OSDTime
= Common::Timer::GetTimeMs() + 3000;
451 OSDChoice
= -OSDChoice
;
453 if ((u32
)OSDTime
> Common::Timer::GetTimeMs())
455 std::string T1
= "", T2
= "";
456 std::vector
<std::string
> T0
;
459 switch(g_ActiveConfig
.iEFBScale
)
462 OSDM1
= "Auto (fractional)";
465 OSDM1
= "Auto (integral)";
479 switch(g_ActiveConfig
.iAspectRatio
)
484 case ASPECT_FORCE_16_9
:
487 case ASPECT_FORCE_4_3
:
495 g_ActiveConfig
.bCrop
? " (crop)" : "";
496 std::string OSDM3
= g_ActiveConfig
.bEFBCopyDisable
? "Disabled" :
497 g_ActiveConfig
.bCopyEFBToTexture
? "To Texture" : "To RAM";
499 // If there is more text than this we will have a collision
500 if (g_ActiveConfig
.bShowFPS
)
507 T0
.push_back(StringFromFormat("3: Internal Resolution: %s\n", OSDM1
.c_str()));
508 T0
.push_back(StringFromFormat("4: Aspect Ratio: %s%s\n", OSDM21
.c_str(), OSDM22
.c_str()));
509 T0
.push_back(StringFromFormat("5: Copy EFB: %s\n", OSDM3
.c_str()));
510 T0
.push_back(StringFromFormat("6: Fog: %s\n", g_ActiveConfig
.bDisableFog
? "Disabled" : "Enabled"));
511 T0
.push_back(StringFromFormat("7: Material Lighting: %s\n", g_ActiveConfig
.bDisableLighting
? "Disabled" : "Enabled"));
513 // The latest changed setting in yellow
514 T1
+= (OSDChoice
== -1) ? T0
.at(0) : "\n";
515 T1
+= (OSDChoice
== -2) ? T0
.at(1) : "\n";
516 T1
+= (OSDChoice
== -3) ? T0
.at(2) : "\n";
517 T1
+= (OSDChoice
== -4) ? T0
.at(3) : "\n";
518 T1
+= (OSDChoice
== -5) ? T0
.at(4) : "\n";
520 // The other settings in cyan
521 T2
+= (OSDChoice
!= -1) ? T0
.at(0) : "\n";
522 T2
+= (OSDChoice
!= -2) ? T0
.at(1) : "\n";
523 T2
+= (OSDChoice
!= -3) ? T0
.at(2) : "\n";
524 T2
+= (OSDChoice
!= -4) ? T0
.at(3) : "\n";
525 T2
+= (OSDChoice
!= -5) ? T0
.at(4) : "\n";
527 // Render a shadow, and then the text
528 Renderer::RenderText(T1
.c_str(), 21, 21, 0xDD000000);
529 Renderer::RenderText(T1
.c_str(), 20, 20, 0xFFffff00);
530 Renderer::RenderText(T2
.c_str(), 21, 21, 0xDD000000);
531 Renderer::RenderText(T2
.c_str(), 20, 20, 0xFF00FFFF);
536 void Renderer::RenderText(const char *text
, int left
, int top
, u32 color
)
538 D3D::font
.DrawTextScaled((float)left
, (float)top
, 20, 20, 0.0f
, color
, text
, false);
541 TargetRectangle
Renderer::ConvertEFBRectangle(const EFBRectangle
& rc
)
543 TargetRectangle result
;
544 int Xstride
= (s_Fulltarget_width
- s_target_width
) / 2;
545 int Ystride
= (s_Fulltarget_height
- s_target_height
) / 2;
546 result
.left
= (int)(rc
.left
* EFBxScale
) + Xstride
;
547 result
.top
= (int)(rc
.top
* EFByScale
) + Ystride
;
548 result
.right
= (int)(rc
.right
* EFBxScale
) + Xstride
;
549 result
.bottom
= (int)(rc
.bottom
* EFByScale
) + Ystride
;
553 void formatBufferDump(const char *in
, char *out
, int w
, int h
, int p
)
555 for (int y
= 0; y
< h
; y
++)
557 const char *line
= in
+ (h
- y
- 1) * p
;
558 for (int x
= 0; x
< w
; x
++)
560 memcpy(out
, line
, 3);
567 // With D3D, we have to resize the backbuffer if the window changed
569 void CheckForResize()
571 while (EmuWindow::IsSizing())
574 if (EmuWindow::GetParentWnd())
576 // Re-stretch window to parent window size again, if it has a parent window.
578 GetWindowRect(EmuWindow::GetParentWnd(), &rcParentWindow
);
579 int width
= rcParentWindow
.right
- rcParentWindow
.left
;
580 int height
= rcParentWindow
.bottom
- rcParentWindow
.top
;
581 if (width
!= s_backbuffer_width
|| height
!= s_backbuffer_height
)
582 MoveWindow(EmuWindow::GetWnd(), 0, 0, width
, height
, FALSE
);
585 GetClientRect(EmuWindow::GetWnd(), &rcWindow
);
586 int client_width
= rcWindow
.right
- rcWindow
.left
;
587 int client_height
= rcWindow
.bottom
- rcWindow
.top
;
590 if ((client_width
!= s_backbuffer_width
||
591 client_height
!= s_backbuffer_height
) &&
592 client_width
>= 4 && client_height
>= 4)
594 TeardownDeviceObjects();
597 s_backbuffer_width
= D3D::GetBackBufferWidth();
598 s_backbuffer_height
= D3D::GetBackBufferHeight();
599 if(ScreenShootMEMSurface
)
600 ScreenShootMEMSurface
->Release();
601 D3D::dev
->CreateOffscreenPlainSurface(s_backbuffer_width
,s_backbuffer_height
, D3DFMT_X8R8G8B8
, D3DPOOL_SYSTEMMEM
, &ScreenShootMEMSurface
, NULL
);
602 WindowResized
= true;
606 void Renderer::RenderToXFB(u32 xfbAddr
, u32 fbWidth
, u32 fbHeight
, const EFBRectangle
& sourceRc
)
608 if (!fbWidth
|| !fbHeight
)
610 VideoFifo_CheckEFBAccess();
611 VideoFifo_CheckSwapRequestAt(xfbAddr
, fbWidth
, fbHeight
);
613 // XXX: Without the VI, how would we know what kind of field this is? So
614 // just use progressive.
615 if (g_ActiveConfig
.bUseXFB
)
617 g_framebufferManager
.CopyToXFB(xfbAddr
, fbWidth
, fbHeight
, sourceRc
);
621 Renderer::Swap(xfbAddr
, FIELD_PROGRESSIVE
, fbWidth
, fbHeight
,sourceRc
);
622 Common::AtomicStoreRelease(s_swapRequested
, FALSE
);
626 bool Renderer::SetScissorRect()
628 int xoff
= bpmem
.scissorOffset
.x
* 2 - 342;
629 int yoff
= bpmem
.scissorOffset
.y
* 2 - 342;
631 rc
.left
= (int)((float)bpmem
.scissorTL
.x
- xoff
- 342);
632 rc
.top
= (int)((float)bpmem
.scissorTL
.y
- yoff
- 342);
633 rc
.right
= (int)((float)bpmem
.scissorBR
.x
- xoff
- 341);
634 rc
.bottom
= (int)((float)bpmem
.scissorBR
.y
- yoff
- 341);
636 if (rc
.left
< 0) rc
.left
= 0;
637 if (rc
.right
< 0) rc
.right
= 0;
638 if (rc
.left
> EFB_WIDTH
) rc
.left
= EFB_WIDTH
;
639 if (rc
.right
> EFB_WIDTH
) rc
.right
= EFB_WIDTH
;
640 if (rc
.top
< 0) rc
.top
= 0;
641 if (rc
.bottom
< 0) rc
.bottom
= 0;
642 if (rc
.top
> EFB_HEIGHT
) rc
.top
= EFB_HEIGHT
;
643 if (rc
.bottom
> EFB_HEIGHT
) rc
.bottom
= EFB_HEIGHT
;
645 if (rc
.left
> rc
.right
)
651 if (rc
.top
> rc
.bottom
)
653 int temp
= rc
.bottom
;
658 int Xstride
= (s_Fulltarget_width
- s_target_width
) / 2;
659 int Ystride
= (s_Fulltarget_height
- s_target_height
) / 2;
661 rc
.left
= (int)(rc
.left
* EFBxScale
) + Xstride
;
662 rc
.top
= (int)(rc
.top
* EFByScale
) + Ystride
;
663 rc
.right
= (int)(rc
.right
* EFBxScale
) + Xstride
;
664 rc
.bottom
= (int)(rc
.bottom
* EFByScale
) + Ystride
;
666 // Check that the coordinates are good
667 if (rc
.right
!= rc
.left
&& rc
.bottom
!= rc
.top
)
669 D3D::dev
->SetScissorRect(&rc
);
674 //WARN_LOG(VIDEO, "Bad scissor rectangle: %i %i %i %i", rc.left, rc.top, rc.right, rc.bottom);
677 rc
.right
= Xstride
+ s_target_width
;
678 rc
.bottom
= Ystride
+ s_target_height
;
679 D3D::dev
->SetScissorRect(&rc
);
684 void Renderer::SetColorMask()
686 DWORD color_mask
= 0;
687 if (bpmem
.blendmode
.alphaupdate
)
688 color_mask
= D3DCOLORWRITEENABLE_ALPHA
;
689 if (bpmem
.blendmode
.colorupdate
)
690 color_mask
|= D3DCOLORWRITEENABLE_RED
| D3DCOLORWRITEENABLE_GREEN
| D3DCOLORWRITEENABLE_BLUE
;
691 D3D::SetRenderState(D3DRS_COLORWRITEENABLE
, color_mask
);
694 u32
Renderer::AccessEFB(EFBAccessType type
, u32 x
, u32 y
, u32 poke_data
)
696 if (!g_ActiveConfig
.bEFBAccessEnable
)
701 static bool alert_only_once
= true;
702 if (!alert_only_once
) return 0;
703 PanicAlert("EFB: Poke Z not implemented (tried to poke z value %#x at (%d,%d))", poke_data
, x
, y
);
704 alert_only_once
= false;
708 // We're using three surfaces here:
709 // - pEFBSurf: EFB Surface. Source surface when peeking, destination surface when poking.
710 // - pBufferRT: A render target surface. When peeking, we render a textured quad to this surface.
711 // - pSystemBuf: An offscreen surface. Used to retrieve the pixel data from pBufferRT.
712 LPDIRECT3DSURFACE9 pEFBSurf
, pBufferRT
, pSystemBuf
;
713 if(type
== PEEK_Z
|| type
== POKE_Z
)
715 pEFBSurf
= g_framebufferManager
.GetEFBDepthRTSurface();
716 pBufferRT
= g_framebufferManager
.GetEFBDepthReadSurface();
717 pSystemBuf
= g_framebufferManager
.GetEFBDepthOffScreenRTSurface();
719 else //if(type == PEEK_COLOR || type == POKE_COLOR)
721 pEFBSurf
= g_framebufferManager
.GetEFBColorRTSurface();
722 pBufferRT
= g_framebufferManager
.GetEFBColorReadSurface();
723 pSystemBuf
= g_framebufferManager
.GetEFBColorOffScreenRTSurface();
726 // Buffer not found alert
728 PanicAlert("No %s!", (type
== PEEK_Z
|| type
== POKE_Z
) ? "Z-Buffer" : "Color EFB");
732 // Convert EFB dimensions to the ones of our render target
733 EFBRectangle efbPixelRc
;
736 efbPixelRc
.right
= x
+ 1;
737 efbPixelRc
.bottom
= y
+ 1;
739 TargetRectangle targetPixelRc
= ConvertEFBRectangle(efbPixelRc
);
744 RectToLock
.bottom
= targetPixelRc
.bottom
;
745 RectToLock
.left
= targetPixelRc
.left
;
746 RectToLock
.right
= targetPixelRc
.right
;
747 RectToLock
.top
= targetPixelRc
.top
;
750 if (g_framebufferManager
.GetEFBDepthRTSurfaceFormat() == D3DFMT_D24X8
)
754 PixelRect
.bottom
= 4;
758 RectToLock
.bottom
+=2;
762 if ((RectToLock
.bottom
- RectToLock
.top
) > 4)
764 if ((RectToLock
.right
- RectToLock
.left
) > 4)
767 ResetAPIState(); // Reset any game specific settings
768 D3D::dev
->SetDepthStencilSurface(NULL
);
769 D3D::dev
->SetRenderTarget(0, pBufferRT
);
771 // Stretch picture with increased internal resolution
779 D3D::dev
->SetViewport(&vp
);
781 float colmat
[16] = {0.0f
};
782 float fConstAdd
[4] = {0.0f
};
783 colmat
[0] = colmat
[5] = colmat
[10] = 1.0f
;
784 PixelShaderManager::SetColorMatrix(colmat
, fConstAdd
); // set transformation
785 LPDIRECT3DTEXTURE9 read_texture
= g_framebufferManager
.GetEFBDepthTexture();
787 D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER
, D3DTEXF_POINT
);
789 D3D::drawShadedTexQuad(
792 Renderer::GetFullTargetWidth(),
793 Renderer::GetFullTargetHeight(),
795 (g_framebufferManager
.GetEFBDepthRTSurfaceFormat() == FOURCC_RAWZ
) ? PixelShaderCache::GetColorMatrixProgram(0) : PixelShaderCache::GetDepthMatrixProgram(0),
796 VertexShaderCache::GetSimpleVertexShader(0));
798 D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER
);
800 D3D::dev
->SetRenderTarget(0, g_framebufferManager
.GetEFBColorRTSurface());
801 D3D::dev
->SetDepthStencilSurface(g_framebufferManager
.GetEFBDepthRTSurface());
804 // Retrieve the pixel data to the local memory buffer
805 RectToLock
.bottom
= 4;
807 RectToLock
.right
= 4;
809 D3D::dev
->GetRenderTargetData(pBufferRT
, pSystemBuf
);
811 // EFB data successfully retrieved, now get the pixel data
812 D3DLOCKED_RECT drect
;
813 pSystemBuf
->LockRect(&drect
, &RectToLock
, D3DLOCK_READONLY
);
817 switch (g_framebufferManager
.GetEFBDepthReadSurfaceFormat())
820 val
= ((float*)drect
.pBits
)[6];
823 float ffrac
= 1.0f
/255.0f
;
824 z
= ((u32
*)drect
.pBits
)[6];
825 val
= ((float)((z
>>16) & 0xFF)) * ffrac
;
827 val
+= ((float)((z
>>8) & 0xFF)) * ffrac
;
829 val
+= ((float)(z
& 0xFF)) * ffrac
;
832 z
= ((u32
)(val
* 0xffffff));
834 pSystemBuf
->UnlockRect();
835 // TODO: in RE0 this value is often off by one, which causes lighting to disappear
838 else if(type
== PEEK_COLOR
)
840 // TODO: Can't we directly StretchRect to System buf?
841 hr
= D3D::dev
->StretchRect(pEFBSurf
, &RectToLock
, pBufferRT
, NULL
, D3DTEXF_NONE
);
842 D3D::dev
->GetRenderTargetData(pBufferRT
, pSystemBuf
);
844 // EFB data successfully retrieved, now get the pixel data
845 RectToLock
.bottom
= 1;
847 RectToLock
.right
= 1;
849 D3DLOCKED_RECT drect
;
850 pSystemBuf
->LockRect(&drect
, &RectToLock
, D3DLOCK_READONLY
);
852 z
= ((u32
*)drect
.pBits
)[0];
853 pSystemBuf
->UnlockRect();
856 else //if(type == POKE_COLOR)
858 // TODO: Speed this up by batching pokes?
860 D3D::drawColorQuad(poke_data
, (float)RectToLock
.left
* 2.f
/ (float)Renderer::GetFullTargetWidth() - 1.f
,
861 - (float)RectToLock
.top
* 2.f
/ (float)Renderer::GetFullTargetHeight() + 1.f
,
862 (float)RectToLock
.right
* 2.f
/ (float)Renderer::GetFullTargetWidth() - 1.f
,
863 - (float)RectToLock
.bottom
* 2.f
/ (float)Renderer::GetFullTargetHeight() + 1.f
);
869 // Called from VertexShaderManager
870 void UpdateViewport()
872 // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
875 // [2] = 16777215 * (farz - nearz)
876 // [3] = xorig + width/2 + 342
877 // [4] = yorig + height/2 + 342
878 // [5] = 16777215 * farz
879 const int old_fulltarget_w
= s_Fulltarget_width
;
880 const int old_fulltarget_h
= s_Fulltarget_height
;
882 int scissorXOff
= bpmem
.scissorOffset
.x
* 2;
883 int scissorYOff
= bpmem
.scissorOffset
.y
* 2;
885 int Xstride
= (s_Fulltarget_width
- s_target_width
) / 2;
886 int Ystride
= (s_Fulltarget_height
- s_target_height
) / 2;
890 // Stretch picture with increased internal resolution
891 int X
= (int)(ceil(xfregs
.rawViewport
[3] - xfregs
.rawViewport
[0] - (scissorXOff
)) * EFBxScale
) + Xstride
;
892 int Y
= (int)(ceil(xfregs
.rawViewport
[4] + xfregs
.rawViewport
[1] - (scissorYOff
)) * EFByScale
) + Ystride
;
893 int Width
= (int)ceil(2.0f
* xfregs
.rawViewport
[0] * EFBxScale
);
894 int Height
= (int)ceil(-2.0f
* xfregs
.rawViewport
[1] * EFByScale
);
905 bool sizeChanged
= false;
908 s_Fulltarget_width
-= 2 * X
;
914 s_Fulltarget_height
-= 2 * Y
;
920 if(X
+ Width
> s_Fulltarget_width
)
922 s_Fulltarget_width
+= (X
+ Width
- s_Fulltarget_width
) * 2;
925 if(Y
+ Height
> s_Fulltarget_height
)
927 s_Fulltarget_height
+= (Y
+ Height
- s_Fulltarget_height
) * 2;
933 D3DCAPS9 caps
= D3D::GetCaps();
934 // Make sure that the requested size is actually supported by the GFX driver
935 if (s_Fulltarget_width
> caps
.MaxTextureWidth
|| s_Fulltarget_height
> caps
.MaxTextureHeight
)
937 // Skip EFB recreation and viewport setting. Most likely causes glitches in this case, but prevents crashes at least
938 ERROR_LOG(VIDEO
, "Tried to set a viewport which is too wide to emulate with Direct3D9. Requested EFB size is %dx%d, keeping the %dx%d EFB now\n", s_Fulltarget_width
, s_Fulltarget_height
, old_fulltarget_w
, old_fulltarget_h
);
940 // Fix the viewport to fit to the old EFB size, TODO: Check this for off-by-one errors
941 X
*= old_fulltarget_w
/ s_Fulltarget_width
;
942 Y
*= old_fulltarget_h
/ s_Fulltarget_height
;
943 Width
*= old_fulltarget_w
/ s_Fulltarget_width
;
944 Height
*= old_fulltarget_h
/ s_Fulltarget_height
;
946 s_Fulltarget_width
= old_fulltarget_w
;
947 s_Fulltarget_height
= old_fulltarget_h
;
951 D3D::dev
->SetRenderTarget(0, D3D::GetBackBufferSurface());
952 D3D::dev
->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface());
953 g_framebufferManager
.Destroy();
954 g_framebufferManager
.Create();
955 D3D::dev
->SetRenderTarget(0, g_framebufferManager
.GetEFBColorRTSurface());
956 D3D::dev
->SetDepthStencilSurface(g_framebufferManager
.GetEFBDepthRTSurface());
964 // Some games set invalids values for z min and z max so fix them to the max an min alowed and let the shaders do this work
965 vp
.MinZ
= 0.0f
; // (xfregs.rawViewport[5] - xfregs.rawViewport[2]) / 16777216.0f;
966 vp
.MaxZ
= 1.0f
; // xfregs.rawViewport[5] / 16777216.0f;
967 D3D::dev
->SetViewport(&vp
);
970 void Renderer::ClearScreen(const EFBRectangle
& rc
, bool colorEnable
, bool alphaEnable
, bool zEnable
, u32 color
, u32 z
)
972 // Update the view port for clearing the picture
973 TargetRectangle targetRc
= ConvertEFBRectangle(rc
);
975 vp
.X
= targetRc
.left
;
977 vp
.Width
= targetRc
.GetWidth();
978 vp
.Height
= targetRc
.GetHeight();
981 D3D::dev
->SetViewport(&vp
);
983 // Always set the scissor in case it was set by the game and has not been reset
985 sicr
.left
= targetRc
.left
;
986 sicr
.top
= targetRc
.top
;
987 sicr
.right
= targetRc
.right
;
988 sicr
.bottom
= targetRc
.bottom
;
989 D3D::dev
->SetScissorRect(&sicr
);
990 D3D::ChangeRenderState(D3DRS_ALPHABLENDENABLE
, false);
992 D3D::ChangeRenderState(D3DRS_ZFUNC
, D3DCMP_ALWAYS
);
993 D3D::drawClearQuad(color
, (z
& 0xFFFFFF) / float(0xFFFFFF), PixelShaderCache::GetClearProgram(), VertexShaderCache::GetClearVertexShader());
995 D3D::RefreshRenderState(D3DRS_ZFUNC
);
996 D3D::RefreshRenderState(D3DRS_ALPHABLENDENABLE
);
1001 void Renderer::SetBlendMode(bool forceUpdate
)
1003 if (bpmem
.blendmode
.logicopenable
)
1006 if (bpmem
.blendmode
.subtract
&& bpmem
.blendmode
.blendenable
)
1008 D3D::SetRenderState(D3DRS_ALPHABLENDENABLE
, true);
1009 D3D::SetRenderState(D3DRS_BLENDOP
, D3DBLENDOP_REVSUBTRACT
);
1010 D3D::SetRenderState(D3DRS_SRCBLEND
, d3dSrcFactors
[1]);
1011 D3D::SetRenderState(D3DRS_DESTBLEND
, d3dDestFactors
[1]);
1015 D3D::SetRenderState(D3DRS_ALPHABLENDENABLE
, bpmem
.blendmode
.blendenable
&& (!( bpmem
.blendmode
.srcfactor
== 1 && bpmem
.blendmode
.dstfactor
== 0)));
1016 if (bpmem
.blendmode
.blendenable
&& (!( bpmem
.blendmode
.srcfactor
== 1 && bpmem
.blendmode
.dstfactor
== 0)))
1018 D3D::SetRenderState(D3DRS_BLENDOP
, D3DBLENDOP_ADD
);
1019 D3D::SetRenderState(D3DRS_SRCBLEND
, d3dSrcFactors
[bpmem
.blendmode
.srcfactor
]);
1020 D3D::SetRenderState(D3DRS_DESTBLEND
, d3dDestFactors
[bpmem
.blendmode
.dstfactor
]);
1025 static bool RightFrame
= false;
1026 // This function has the final picture. We adjust the aspect ratio here.
1027 void Renderer::Swap(u32 xfbAddr
, FieldType field
, u32 fbWidth
, u32 fbHeight
,const EFBRectangle
& rc
)
1029 if (g_bSkipCurrentFrame
|| (!XFBWrited
&& !g_ActiveConfig
.bUseRealXFB
) || !fbWidth
|| !fbHeight
)
1031 g_VideoInitialize
.pCopiedToXFB(false);
1034 // this function is called after the XFB field is changed, not after
1035 // EFB is copied to XFB. In this way, flickering is reduced in games
1036 // and seems to also give more FPS in ZTP
1038 if (field
== FIELD_LOWER
) xfbAddr
-= fbWidth
* 2;
1040 const XFBSource
** xfbSourceList
= g_framebufferManager
.GetXFBSource(xfbAddr
, fbWidth
, fbHeight
, xfbCount
);
1041 if ((!xfbSourceList
|| xfbCount
== 0) && g_ActiveConfig
.bUseXFB
&& !g_ActiveConfig
.bUseRealXFB
)
1043 g_VideoInitialize
.pCopiedToXFB(false);
1048 if(g_ActiveConfig
.bAnaglyphStereo
)
1052 D3D::SetRenderState(D3DRS_COLORWRITEENABLE
, D3DCOLORWRITEENABLE_BLUE
| D3DCOLORWRITEENABLE_GREEN
);
1053 VertexShaderManager::ResetView();
1054 VertexShaderManager::TranslateView(-0.001f
* g_ActiveConfig
.iAnaglyphStereoSeparation
,0.0f
);
1055 VertexShaderManager::RotateView(-0.0001 *g_ActiveConfig
.iAnaglyphFocalAngle
,0.0f
);
1060 D3D::SetRenderState(D3DRS_COLORWRITEENABLE
, D3DCOLORWRITEENABLE_RED
);
1061 VertexShaderManager::ResetView();
1062 VertexShaderManager::TranslateView(0.001f
*g_ActiveConfig
.iAnaglyphStereoSeparation
,0.0f
);
1063 VertexShaderManager::RotateView(0.0001 * g_ActiveConfig
.iAnaglyphFocalAngle
,0.0f
);
1068 // Prepare to copy the XFBs to our backbuffer
1069 D3D::dev
->SetDepthStencilSurface(NULL
);
1070 D3D::dev
->SetRenderTarget(0, D3D::GetBackBufferSurface());
1072 TargetRectangle dst_rect
;
1073 ComputeDrawRectangle(s_backbuffer_width
, s_backbuffer_height
, false, &dst_rect
);
1076 // Clear full target screen (edges, borders etc)
1079 vp
.Width
= s_backbuffer_width
;
1080 vp
.Height
= s_backbuffer_height
;
1083 D3D::dev
->SetViewport(&vp
);
1084 //D3D::dev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
1085 D3D::drawClearQuad(0, 1.0, PixelShaderCache::GetClearProgram(), VertexShaderCache::GetClearVertexShader());
1087 int X
= dst_rect
.left
;
1088 int Y
= dst_rect
.top
;
1089 int Width
= dst_rect
.right
- dst_rect
.left
;
1090 int Height
= dst_rect
.bottom
- dst_rect
.top
;
1095 if (X
> s_backbuffer_width
) X
= s_backbuffer_width
;
1096 if (Y
> s_backbuffer_height
) Y
= s_backbuffer_height
;
1097 if (Width
< 0) Width
= 0;
1098 if (Height
< 0) Height
= 0;
1099 if (Width
> (s_backbuffer_width
- X
)) Width
= s_backbuffer_width
- X
;
1100 if (Height
> (s_backbuffer_height
- Y
)) Height
= s_backbuffer_height
- Y
;
1109 D3D::dev
->SetViewport(&vp
);
1111 D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER
, D3DTEXF_LINEAR
);
1112 D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER
, D3DTEXF_LINEAR
);
1114 const XFBSource
* xfbSource
= NULL
;
1116 if(g_ActiveConfig
.bUseXFB
)
1118 // draw each xfb source
1119 // Render to the real buffer now.
1120 for (u32 i
= 0; i
< xfbCount
; ++i
)
1122 xfbSource
= xfbSourceList
[i
];
1124 MathUtil::Rectangle
<float> sourceRc
;
1128 sourceRc
.right
= xfbSource
->texWidth
;
1129 sourceRc
.bottom
= xfbSource
->texHeight
;
1131 MathUtil::Rectangle
<float> drawRc
;
1133 if (!g_ActiveConfig
.bUseRealXFB
)
1135 // use virtual xfb with offset
1136 int xfbHeight
= xfbSource
->srcHeight
;
1137 int xfbWidth
= xfbSource
->srcWidth
;
1138 int hOffset
= ((s32
)xfbSource
->srcAddr
- (s32
)xfbAddr
) / ((s32
)fbWidth
* 2);
1140 drawRc
.bottom
= 1.0f
- (2.0f
* (hOffset
) / (float)fbHeight
);
1141 drawRc
.top
= 1.0f
- (2.0f
* (hOffset
+ xfbHeight
) / (float)fbHeight
);
1142 drawRc
.left
= -(xfbWidth
/ (float)fbWidth
);
1143 drawRc
.right
= (xfbWidth
/ (float)fbWidth
);
1145 // The following code disables auto stretch. Kept for reference.
1146 // scale draw area for a 1 to 1 pixel mapping with the draw target
1147 //float vScale = (float)fbHeight / (float)dst_rect.GetHeight();
1148 //float hScale = (float)fbWidth / (float)dst_rect.GetWidth();
1149 //drawRc.top *= vScale;
1150 //drawRc.bottom *= vScale;
1151 //drawRc.left *= hScale;
1152 //drawRc.right *= hScale;
1162 D3D::drawShadedTexSubQuad(xfbSource
->texture
,&sourceRc
,xfbSource
->texWidth
,xfbSource
->texHeight
,&drawRc
,Width
,Height
,PixelShaderCache::GetColorCopyProgram(0),VertexShaderCache::GetSimpleVertexShader(0));
1167 TargetRectangle targetRc
= ConvertEFBRectangle(rc
);
1168 LPDIRECT3DTEXTURE9 read_texture
= g_framebufferManager
.GetEFBColorTexture();
1169 D3D::drawShadedTexQuad(read_texture
,targetRc
.AsRECT(),Renderer::GetFullTargetWidth(),Renderer::GetFullTargetHeight(),Width
,Height
,PixelShaderCache::GetColorCopyProgram(g_Config
.iMultisampleMode
),VertexShaderCache::GetSimpleVertexShader(g_Config
.iMultisampleMode
));
1171 D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER
);
1172 D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER
);
1174 if(g_ActiveConfig
.bAnaglyphStereo
)
1176 DWORD color_mask
= D3DCOLORWRITEENABLE_ALPHA
| D3DCOLORWRITEENABLE_RED
| D3DCOLORWRITEENABLE_GREEN
| D3DCOLORWRITEENABLE_BLUE
;
1177 D3D::SetRenderState(D3DRS_COLORWRITEENABLE
, color_mask
);
1182 vp
.Width
= s_backbuffer_width
;
1183 vp
.Height
= s_backbuffer_height
;
1186 D3D::dev
->SetViewport(&vp
);
1191 s_criticalScreenshot
.Enter();
1192 HRESULT hr
= D3D::dev
->GetRenderTargetData(D3D::GetBackBufferSurface(),ScreenShootMEMSurface
);
1195 PanicAlert("Error dumping surface data.");
1197 hr
= PD3DXSaveSurfaceToFileA(s_sScreenshotName
, D3DXIFF_PNG
, ScreenShootMEMSurface
, NULL
, dst_rect
.AsRECT());
1200 PanicAlert("Error saving screen.");
1202 s_bScreenshot
= false;
1203 s_criticalScreenshot
.Leave();
1205 if (g_ActiveConfig
.bDumpFrames
)
1207 HRESULT hr
= D3D::dev
->GetRenderTargetData(D3D::GetBackBufferSurface(),ScreenShootMEMSurface
);
1208 if (!s_bLastFrameDumped
)
1210 s_recordWidth
= dst_rect
.GetWidth();
1211 s_recordHeight
= dst_rect
.GetHeight();
1212 s_bAVIDumping
= AVIDump::Start(EmuWindow::GetParentWnd(), s_recordWidth
, s_recordHeight
);
1215 PanicAlert("Error dumping frames to AVI.");
1220 sprintf_s(msg
,255, "Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)", File::GetUserPath(D_DUMPFRAMES_IDX
), s_recordWidth
, s_recordHeight
);
1221 OSD::AddMessage(msg
, 2000);
1226 D3DLOCKED_RECT rect
;
1227 if (SUCCEEDED(ScreenShootMEMSurface
->LockRect(&rect
, dst_rect
.AsRECT(), D3DLOCK_NO_DIRTY_UPDATE
| D3DLOCK_NOSYSLOCK
| D3DLOCK_READONLY
)))
1229 char* data
= (char*)malloc(3 * s_recordWidth
* s_recordHeight
);
1230 formatBufferDump((const char*)rect
.pBits
, data
, s_recordWidth
, s_recordHeight
, rect
.Pitch
);
1231 AVIDump::AddFrame(data
);
1233 ScreenShootMEMSurface
->UnlockRect();
1236 s_bLastFrameDumped
= true;
1240 if (s_bLastFrameDumped
&& s_bAVIDumping
)
1243 s_bAVIDumping
= false;
1244 OSD::AddMessage("Stop dumping frames to AVI", 2000);
1246 s_bLastFrameDumped
= false;
1249 // Finish up the current frame, print some stats
1250 if (g_ActiveConfig
.bShowFPS
)
1253 StringCchPrintfA(fps
, 20, "FPS: %d\n", s_fps
);
1254 D3D::font
.DrawTextScaled(0, 30, 20, 20, 0.0f
, 0xFF00FFFF, fps
, false);
1256 Renderer::DrawDebugText();
1258 if (g_ActiveConfig
.bOverlayStats
)
1260 Statistics::ToString(st
);
1261 D3D::font
.DrawTextScaled(0, 30, 20, 20, 0.0f
, 0xFF00FFFF, st
, false);
1263 else if (g_ActiveConfig
.bOverlayProjStats
)
1265 Statistics::ToStringProj(st
);
1266 D3D::font
.DrawTextScaled(0, 30, 20, 20, 0.0f
, 0xFF00FFFF, st
, false);
1269 OSD::DrawMessages();
1272 DLCache::ProgressiveCleanup();
1273 TextureCache::Cleanup();
1275 // Enable any configuration changes
1276 UpdateActiveConfig();
1277 WindowResized
= false;
1280 bool xfbchanged
= false;
1282 if (s_XFB_width
!= fbWidth
|| s_XFB_height
!= fbHeight
)
1285 s_XFB_width
= fbWidth
;
1286 s_XFB_height
= fbHeight
;
1287 if (s_XFB_width
< 1) s_XFB_width
= MAX_XFB_WIDTH
;
1288 if (s_XFB_width
> MAX_XFB_WIDTH
) s_XFB_width
= MAX_XFB_WIDTH
;
1289 if (s_XFB_height
< 1) s_XFB_height
= MAX_XFB_HEIGHT
;
1290 if (s_XFB_height
> MAX_XFB_HEIGHT
) s_XFB_height
= MAX_XFB_HEIGHT
;
1293 u32 newAA
= g_ActiveConfig
.iMultisampleMode
;
1295 if (xfbchanged
|| WindowResized
|| s_LastEFBScale
!= g_ActiveConfig
.iEFBScale
)
1299 ComputeDrawRectangle(s_backbuffer_width
, s_backbuffer_height
, false, &dst_rect
);
1301 if(g_ActiveConfig
.bUseRealXFB
)
1308 xScale
= (float)(dst_rect
.right
- dst_rect
.left
) / (float)s_XFB_width
;
1309 yScale
= (float)(dst_rect
.bottom
- dst_rect
.top
) / (float)s_XFB_height
;
1312 float SupersampleCoeficient
= s_LastAA
+ 1;
1313 s_LastEFBScale
= g_ActiveConfig
.iEFBScale
;
1314 switch(s_LastEFBScale
)
1321 EFBxScale
= ceilf(xScale
);
1322 EFByScale
= ceilf(yScale
);
1325 EFBxScale
= g_ActiveConfig
.iEFBScale
- 1;
1326 EFByScale
= EFBxScale
;
1330 EFBxScale
*= SupersampleCoeficient
;
1331 EFByScale
*= SupersampleCoeficient
;
1333 s_target_width
= EFB_WIDTH
* EFBxScale
;
1334 s_target_height
= EFB_HEIGHT
* EFByScale
;
1336 s_Fulltarget_width
= s_target_width
;
1337 s_Fulltarget_height
= s_target_height
;
1339 D3D::dev
->SetRenderTarget(0, D3D::GetBackBufferSurface());
1340 D3D::dev
->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface());
1343 SetupDeviceObjects();
1347 g_framebufferManager
.Destroy();
1348 g_framebufferManager
.Create();
1350 D3D::dev
->SetRenderTarget(0, g_framebufferManager
.GetEFBColorRTSurface());
1351 D3D::dev
->SetDepthStencilSurface(g_framebufferManager
.GetEFBDepthRTSurface());
1354 // Place messages on the picture, then copy it to the screen
1355 // ---------------------------------------------------------------------
1358 static int fpscount
= 0;
1359 static unsigned long lasttime
= 0;
1360 if (Common::Timer::GetTimeMs() - lasttime
>= 1000)
1362 lasttime
= Common::Timer::GetTimeMs();
1370 // Set default viewport and scissor, for the clear to work correctly
1374 // Flip/present backbuffer to frontbuffer here
1379 D3D::dev
->SetRenderTarget(0, g_framebufferManager
.GetEFBColorRTSurface());
1380 D3D::dev
->SetDepthStencilSurface(g_framebufferManager
.GetEFBDepthRTSurface());
1382 VertexShaderManager::SetViewportChanged();
1383 // For testing zbuffer targets.
1384 // Renderer::SetZBufferRender();
1385 // SaveTexture("tex.tga", GL_TEXTURE_RECTANGLE_ARB, s_FakeZTarget,
1386 // GetTargetWidth(), GetTargetHeight());
1387 g_VideoInitialize
.pCopiedToXFB(XFBWrited
|| g_ActiveConfig
.bUseRealXFB
);
1391 // ALWAYS call RestoreAPIState for each ResetAPIState call you're doing
1392 void Renderer::ResetAPIState()
1394 D3D::SetRenderState(D3DRS_SCISSORTESTENABLE
, FALSE
);
1395 D3D::SetRenderState(D3DRS_CULLMODE
, D3DCULL_NONE
);
1396 D3D::SetRenderState(D3DRS_ALPHABLENDENABLE
, FALSE
);
1397 D3D::SetRenderState(D3DRS_ZENABLE
, FALSE
);
1398 D3D::SetRenderState(D3DRS_ZWRITEENABLE
, FALSE
);
1399 DWORD color_mask
= D3DCOLORWRITEENABLE_ALPHA
| D3DCOLORWRITEENABLE_RED
| D3DCOLORWRITEENABLE_GREEN
| D3DCOLORWRITEENABLE_BLUE
;
1400 D3D::SetRenderState(D3DRS_COLORWRITEENABLE
, color_mask
);
1403 void Renderer::RestoreAPIState()
1405 // Gets us back into a more game-like state.
1406 D3D::SetRenderState(D3DRS_SCISSORTESTENABLE
, TRUE
);
1409 if (bpmem
.zmode
.testenable
)
1410 D3D::SetRenderState(D3DRS_ZENABLE
, TRUE
);
1411 if (bpmem
.zmode
.updateenable
)
1412 D3D::SetRenderState(D3DRS_ZWRITEENABLE
, TRUE
);
1417 void Renderer::SetGenerationMode()
1419 D3D::SetRenderState(D3DRS_CULLMODE
, d3dCullModes
[bpmem
.genMode
.cullmode
]);
1422 void Renderer::SetDepthMode()
1424 if (bpmem
.zmode
.testenable
)
1426 D3D::SetRenderState(D3DRS_ZENABLE
, TRUE
);
1427 D3D::SetRenderState(D3DRS_ZWRITEENABLE
, bpmem
.zmode
.updateenable
);
1428 D3D::SetRenderState(D3DRS_ZFUNC
, d3dCmpFuncs
[bpmem
.zmode
.func
]);
1432 // if the test is disabled write is disabled too
1433 D3D::SetRenderState(D3DRS_ZENABLE
, FALSE
);
1434 D3D::SetRenderState(D3DRS_ZWRITEENABLE
, FALSE
); // ??
1438 void Renderer::SetLogicOpMode()
1440 if (bpmem
.blendmode
.logicopenable
&& bpmem
.blendmode
.logicmode
!= 3)
1442 D3D::SetRenderState(D3DRS_ALPHABLENDENABLE
, true);
1443 D3D::SetRenderState(D3DRS_BLENDOP
, d3dLogicOpop
[bpmem
.blendmode
.logicmode
]);
1444 D3D::SetRenderState(D3DRS_SRCBLEND
, d3dLogicOpSrcFactors
[bpmem
.blendmode
.logicmode
]);
1445 D3D::SetRenderState(D3DRS_DESTBLEND
, d3dLogicOpDestFactors
[bpmem
.blendmode
.logicmode
]);
1453 void Renderer::SetDitherMode()
1455 D3D::SetRenderState(D3DRS_DITHERENABLE
, bpmem
.blendmode
.dither
);
1458 void Renderer::SetLineWidth()
1460 // We can't change line width in D3D unless we use ID3DXLine
1461 float fratio
= xfregs
.rawViewport
[0] != 0 ? Renderer::GetTargetScaleX() : 1.0f
;
1462 float psize
= bpmem
.lineptwidth
.linesize
* fratio
/ 6.0f
;
1463 D3D::SetRenderState(D3DRS_POINTSIZE
, *((DWORD
*)&psize
));
1466 void Renderer::SetSamplerState(int stage
, int texindex
)
1468 const FourTexUnits
&tex
= bpmem
.tex
[texindex
];
1469 const TexMode0
&tm0
= tex
.texMode0
[stage
];
1470 const TexMode1
&tm1
= tex
.texMode1
[stage
];
1472 D3DTEXTUREFILTERTYPE min
, mag
, mip
;
1473 if (g_ActiveConfig
.bForceFiltering
)
1475 min
= mag
= mip
= D3DTEXF_LINEAR
;
1479 min
= (tm0
.min_filter
& 4) ? D3DTEXF_LINEAR
: D3DTEXF_POINT
;
1480 mag
= tm0
.mag_filter
? D3DTEXF_LINEAR
: D3DTEXF_POINT
;
1481 mip
= (tm0
.min_filter
== 8) ? D3DTEXF_NONE
: d3dMipFilters
[tm0
.min_filter
& 3];
1482 if((tm0
.min_filter
& 3) && (tm0
.min_filter
!= 8) && ((tm1
.max_lod
>> 4) == 0))
1488 if (mag
== D3DTEXF_LINEAR
&& min
== D3DTEXF_LINEAR
&& g_ActiveConfig
.iMaxAnisotropy
> 1)
1490 min
= D3DTEXF_ANISOTROPIC
;
1492 D3D::SetSamplerState(stage
, D3DSAMP_MINFILTER
, min
);
1493 D3D::SetSamplerState(stage
, D3DSAMP_MAGFILTER
, mag
);
1494 D3D::SetSamplerState(stage
, D3DSAMP_MIPFILTER
, mip
);
1496 D3D::SetSamplerState(stage
, D3DSAMP_ADDRESSU
, d3dClamps
[tm0
.wrap_s
]);
1497 D3D::SetSamplerState(stage
, D3DSAMP_ADDRESSV
, d3dClamps
[tm0
.wrap_t
]);
1498 //float SuperSampleCoeficient = (s_LastAA < 3)? s_LastAA + 1 : s_LastAA - 1;// uncoment this changes to conserve detail when incresing ssaa level
1499 float lodbias
= (tm0
.lod_bias
/ 32.0f
);// + (s_LastAA)?(log(SuperSampleCoeficient) / log(2.0f)):0;
1500 D3D::SetSamplerState(stage
, D3DSAMP_MIPMAPLODBIAS
, *(DWORD
*)&lodbias
);
1501 D3D::SetSamplerState(stage
, D3DSAMP_MAXMIPLEVEL
, tm1
.min_lod
>> 4);
1504 void Renderer::SetInterlacingMode()
1510 void Renderer::SetScreenshot(const char *filename
)
1512 s_criticalScreenshot
.Enter();
1513 strcpy_s(s_sScreenshotName
, filename
);
1514 s_bScreenshot
= true;
1515 s_criticalScreenshot
.Leave();