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/
20 #include "StringUtil.h"
26 #include "Statistics.h"
28 #include "VideoConfig.h"
30 #include "VertexManager.h"
32 #include "OpcodeDecoding.h"
33 #include "BPStructs.h"
34 #include "XFStructs.h"
36 #include "VertexShaderManager.h"
37 #include "PixelShaderManager.h"
38 #include "VertexShaderCache.h"
39 #include "PixelShaderCache.h"
40 #include "VertexLoaderManager.h"
41 #include "TextureCache.h"
42 #include "EmuWindow.h"
44 #include "OnScreenDisplay.h"
45 #include "FBManager.h"
53 static bool WindowResized
;
54 static int s_target_width
;
55 static int s_target_height
;
57 static int s_Fulltarget_width
;
58 static int s_Fulltarget_height
;
60 static int s_backbuffer_width
;
61 static int s_backbuffer_height
;
63 static int s_XFB_width
;
64 static int s_XFB_height
;
69 static u32 s_blendMode
;
70 static bool XFBWrited
;
72 static bool s_bScreenshot
= false;
73 static Common::CriticalSection s_criticalScreenshot
;
74 static char s_sScreenshotName
[1024];
76 ID3D11Buffer
* access_efb_cbuf
= NULL
;
77 ID3D11DepthStencilState
* cleardepthstates
[2] = {NULL
};
78 ID3D11RasterizerState
* clearraststate
= NULL
;
79 ID3D11BlendState
* resetblendstate
= NULL
;
80 ID3D11DepthStencilState
* resetdepthstate
= NULL
;
81 ID3D11RasterizerState
* resetraststate
= NULL
;
83 bool reset_called
= false;
85 // state translation lookup tables
86 static const D3D11_BLEND d3dSrcFactors
[8] =
90 D3D11_BLEND_DEST_COLOR
,
91 D3D11_BLEND_INV_DEST_COLOR
,
92 D3D11_BLEND_SRC_ALPHA
,
93 D3D11_BLEND_INV_SRC_ALPHA
,
94 D3D11_BLEND_DEST_ALPHA
,
95 D3D11_BLEND_INV_DEST_ALPHA
98 static const D3D11_BLEND d3dDestFactors
[8] =
102 D3D11_BLEND_SRC_COLOR
,
103 D3D11_BLEND_INV_SRC_COLOR
,
104 D3D11_BLEND_SRC_ALPHA
,
105 D3D11_BLEND_INV_SRC_ALPHA
,
106 D3D11_BLEND_DEST_ALPHA
,
107 D3D11_BLEND_INV_DEST_ALPHA
111 // 1 Source & destination
112 // 2 Source & ~destination
114 // 4 ~Source & destination
116 // 6 Source ^ destination = Source & ~destination | ~Source & destination
117 // 7 Source | destination
119 // 8 ~(Source | destination)
120 // 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination
122 // 11 Source | ~destination
124 // 13 ~Source | destination
125 // 14 ~(Source & destination)
128 static const D3D11_BLEND_OP d3dLogicOps
[16] =
130 D3D11_BLEND_OP_ADD
,//0
131 D3D11_BLEND_OP_ADD
,//1
132 D3D11_BLEND_OP_SUBTRACT
,//2
133 D3D11_BLEND_OP_ADD
,//3
134 D3D11_BLEND_OP_REV_SUBTRACT
,//4
135 D3D11_BLEND_OP_ADD
,//5
136 D3D11_BLEND_OP_MAX
,//6
137 D3D11_BLEND_OP_ADD
,//7
139 D3D11_BLEND_OP_MAX
,//8
140 D3D11_BLEND_OP_MAX
,//9
141 D3D11_BLEND_OP_ADD
,//10
142 D3D11_BLEND_OP_ADD
,//11
143 D3D11_BLEND_OP_ADD
,//12
144 D3D11_BLEND_OP_ADD
,//13
145 D3D11_BLEND_OP_ADD
,//14
146 D3D11_BLEND_OP_ADD
//15
149 static const D3D11_BLEND d3dLogicOpSrcFactors
[16] =
152 D3D11_BLEND_DEST_COLOR
,//1
155 D3D11_BLEND_DEST_COLOR
,//4
157 D3D11_BLEND_INV_DEST_COLOR
,//6
158 D3D11_BLEND_INV_DEST_COLOR
,//7
160 D3D11_BLEND_INV_SRC_COLOR
,//8
161 D3D11_BLEND_INV_SRC_COLOR
,//9
162 D3D11_BLEND_INV_DEST_COLOR
,//10
164 D3D11_BLEND_INV_SRC_COLOR
,//12
165 D3D11_BLEND_INV_SRC_COLOR
,//13
166 D3D11_BLEND_INV_DEST_COLOR
,//14
170 static const D3D11_BLEND d3dLogicOpDestFactors
[16] =
174 D3D11_BLEND_INV_SRC_COLOR
,//2
178 D3D11_BLEND_INV_SRC_COLOR
,//6
181 D3D11_BLEND_INV_DEST_COLOR
,//8
182 D3D11_BLEND_SRC_COLOR
,//9
183 D3D11_BLEND_INV_DEST_COLOR
,//10
184 D3D11_BLEND_INV_DEST_COLOR
,//11
185 D3D11_BLEND_INV_SRC_COLOR
,//12
187 D3D11_BLEND_INV_SRC_COLOR
,//14
191 static const D3D11_CULL_MODE d3dCullModes
[4] =
199 static const D3D11_COMPARISON_FUNC d3dCmpFuncs
[8] =
201 D3D11_COMPARISON_NEVER
,
202 D3D11_COMPARISON_LESS
,
203 D3D11_COMPARISON_EQUAL
,
204 D3D11_COMPARISON_LESS_EQUAL
,
205 D3D11_COMPARISON_GREATER
,
206 D3D11_COMPARISON_NOT_EQUAL
,
207 D3D11_COMPARISON_GREATER_EQUAL
,
208 D3D11_COMPARISON_ALWAYS
213 #define TEXF_LINEAR 2
214 static const unsigned int d3dMipFilters
[4] =
219 TEXF_NONE
, //reserved
222 static const D3D11_TEXTURE_ADDRESS_MODE d3dClamps
[4] =
224 D3D11_TEXTURE_ADDRESS_CLAMP
,
225 D3D11_TEXTURE_ADDRESS_WRAP
,
226 D3D11_TEXTURE_ADDRESS_MIRROR
,
227 D3D11_TEXTURE_ADDRESS_WRAP
//reserved
230 void SetupDeviceObjects()
235 float colmat
[20]= {0.0f
};
236 colmat
[0] = colmat
[5] = colmat
[10] = 1.0f
;
237 D3D11_BUFFER_DESC cbdesc
= CD3D11_BUFFER_DESC(20*sizeof(float), D3D11_BIND_CONSTANT_BUFFER
, D3D11_USAGE_DEFAULT
);
238 D3D11_SUBRESOURCE_DATA data
;
239 data
.pSysMem
= colmat
;
240 hr
= D3D::device
->CreateBuffer(&cbdesc
, &data
, &access_efb_cbuf
);
241 CHECK(hr
==S_OK
, "Create constant buffer for Renderer::AccessEFB");
242 D3D::SetDebugObjectName((ID3D11DeviceChild
*)access_efb_cbuf
, "constant buffer for Renderer::AccessEFB");
244 D3D11_DEPTH_STENCIL_DESC ddesc
;
245 ddesc
.DepthEnable
= FALSE
;
246 ddesc
.DepthWriteMask
= D3D11_DEPTH_WRITE_MASK_ZERO
;
247 ddesc
.DepthFunc
= D3D11_COMPARISON_ALWAYS
;
248 ddesc
.StencilEnable
= FALSE
;
249 ddesc
.StencilReadMask
= D3D11_DEFAULT_STENCIL_READ_MASK
;
250 ddesc
.StencilWriteMask
= D3D11_DEFAULT_STENCIL_WRITE_MASK
;
251 hr
= D3D::device
->CreateDepthStencilState(&ddesc
, &cleardepthstates
[0]);
252 CHECK(hr
==S_OK
, "Create depth state for Renderer::ClearScreen");
253 ddesc
.DepthWriteMask
= D3D11_DEPTH_WRITE_MASK_ALL
;
254 ddesc
.DepthEnable
= TRUE
;
255 hr
= D3D::device
->CreateDepthStencilState(&ddesc
, &cleardepthstates
[1]);
256 CHECK(hr
==S_OK
, "Create depth state for Renderer::ClearScreen");
257 D3D::SetDebugObjectName((ID3D11DeviceChild
*)cleardepthstates
[0], "depth state for Renderer::ClearScreen (depth buffer disabled)");
258 D3D::SetDebugObjectName((ID3D11DeviceChild
*)cleardepthstates
[1], "depth state for Renderer::ClearScreen (depth buffer enabled)");
260 // TODO: once multisampling gets implemented, this might need to be changed
261 D3D11_RASTERIZER_DESC rdesc
= CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID
, D3D11_CULL_NONE
, false, 0, 0.f
, 0.f
, false, true, false, false);
262 hr
= D3D::device
->CreateRasterizerState(&rdesc
, &clearraststate
);
263 CHECK(hr
==S_OK
, "Create rasterizer state for Renderer::ClearScreen");
264 D3D::SetDebugObjectName((ID3D11DeviceChild
*)clearraststate
, "rasterizer state for Renderer::ClearScreen");
266 D3D11_BLEND_DESC blenddesc
;
267 blenddesc
.AlphaToCoverageEnable
= FALSE
;
268 blenddesc
.IndependentBlendEnable
= FALSE
;
269 blenddesc
.RenderTarget
[0].BlendEnable
= FALSE
;
270 blenddesc
.RenderTarget
[0].RenderTargetWriteMask
= D3D11_COLOR_WRITE_ENABLE_ALL
;
271 blenddesc
.RenderTarget
[0].SrcBlend
= D3D11_BLEND_ONE
;
272 blenddesc
.RenderTarget
[0].DestBlend
= D3D11_BLEND_ZERO
;
273 blenddesc
.RenderTarget
[0].BlendOp
= D3D11_BLEND_OP_ADD
;
274 blenddesc
.RenderTarget
[0].SrcBlendAlpha
= D3D11_BLEND_ONE
;
275 blenddesc
.RenderTarget
[0].DestBlendAlpha
= D3D11_BLEND_ZERO
;
276 blenddesc
.RenderTarget
[0].BlendOpAlpha
= D3D11_BLEND_OP_ADD
;
277 hr
= D3D::device
->CreateBlendState(&blenddesc
, &resetblendstate
);
278 CHECK(hr
==S_OK
, "Create blend state for Renderer::ResetAPIState");
279 D3D::SetDebugObjectName((ID3D11DeviceChild
*)resetblendstate
, "blend state for Renderer::ResetAPIState");
281 ddesc
.DepthEnable
= FALSE
;
282 ddesc
.DepthWriteMask
= D3D11_DEPTH_WRITE_MASK_ZERO
;
283 ddesc
.DepthFunc
= D3D11_COMPARISON_LESS
;
284 ddesc
.StencilEnable
= FALSE
;
285 ddesc
.StencilReadMask
= D3D11_DEFAULT_STENCIL_READ_MASK
;
286 ddesc
.StencilWriteMask
= D3D11_DEFAULT_STENCIL_WRITE_MASK
;
287 hr
= D3D::device
->CreateDepthStencilState(&ddesc
, &resetdepthstate
);
288 CHECK(hr
==S_OK
, "Create depth state for Renderer::ResetAPIState");
289 D3D::SetDebugObjectName((ID3D11DeviceChild
*)resetdepthstate
, "depth stencil state for Renderer::ResetAPIState");
291 // this might need to be changed once multisampling support gets added
292 D3D11_RASTERIZER_DESC rastdesc
= CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID
, D3D11_CULL_NONE
, false, 0, 0.f
, 0.f
, false, false, false, false);
293 hr
= D3D::device
->CreateRasterizerState(&rastdesc
, &resetraststate
);
294 CHECK(hr
==S_OK
, "Create rasterizer state for Renderer::ClearScreen");
295 D3D::SetDebugObjectName((ID3D11DeviceChild
*)resetraststate
, "rasterizer state for Renderer::ResetAPIState");
298 void TeardownDeviceObjects()
301 SAFE_RELEASE(access_efb_cbuf
);
302 SAFE_RELEASE(cleardepthstates
[0]);
303 SAFE_RELEASE(cleardepthstates
[1]);
304 SAFE_RELEASE(clearraststate
);
305 SAFE_RELEASE(resetblendstate
);
306 SAFE_RELEASE(resetdepthstate
);
307 SAFE_RELEASE(resetraststate
);
310 bool Renderer::Init()
312 UpdateActiveConfig();
313 int x
, y
, w_temp
, h_temp
;
316 g_VideoInitialize
.pRequestWindowSize(x
, y
, w_temp
, h_temp
);
318 D3D::Create(EmuWindow::GetWnd());
320 s_backbuffer_width
= D3D::GetBackBufferWidth();
321 s_backbuffer_height
= D3D::GetBackBufferHeight();
323 s_XFB_width
= MAX_XFB_WIDTH
;
324 s_XFB_height
= MAX_XFB_HEIGHT
;
326 TargetRectangle dst_rect
;
327 ComputeDrawRectangle(s_backbuffer_width
, s_backbuffer_height
, false, &dst_rect
);
329 xScale
= (float)(dst_rect
.right
- dst_rect
.left
) / (float)s_XFB_width
;
330 yScale
= (float)(dst_rect
.bottom
- dst_rect
.top
) / (float)s_XFB_height
;
332 s_target_width
= (int)(EFB_WIDTH
* xScale
);
333 s_target_height
= (int)(EFB_HEIGHT
* yScale
);
335 s_Fulltarget_width
= s_target_width
;
336 s_Fulltarget_height
= s_target_height
;
338 SetupDeviceObjects();
340 for (unsigned int stage
= 0; stage
< 8; stage
++)
341 D3D::gfxstate
->samplerdesc
[stage
].MaxAnisotropy
= g_ActiveConfig
.iMaxAnisotropy
;
343 float ClearColor
[4] = { 0.f
, 0.f
, 0.f
, 0.f
};
344 D3D::context
->ClearRenderTargetView(FBManager
.GetEFBColorTexture()->GetRTV(), ClearColor
);
345 D3D::context
->ClearDepthStencilView(FBManager
.GetEFBDepthTexture()->GetDSV(), D3D11_CLEAR_DEPTH
, 1.f
, 0);
347 D3D11_VIEWPORT vp
= CD3D11_VIEWPORT((float)(s_Fulltarget_width
- s_target_width
) / 2.f
,
348 (float)(s_Fulltarget_height
- s_target_height
) / 2.f
,
349 (float)s_target_width
, (float)s_target_height
);
350 D3D::context
->RSSetViewports(1, &vp
);
351 D3D::context
->OMSetRenderTargets(1, &FBManager
.GetEFBColorTexture()->GetRTV(), FBManager
.GetEFBDepthTexture()->GetDSV());
353 D3D::gfxstate
->rastdesc
.ScissorEnable
= TRUE
;
355 reset_called
= false;
359 void Renderer::Shutdown()
361 TeardownDeviceObjects();
367 int Renderer::GetTargetWidth() { return s_target_width
; }
368 int Renderer::GetTargetHeight() { return s_target_height
; }
369 int Renderer::GetFullTargetWidth() { return s_Fulltarget_width
; }
370 int Renderer::GetFullTargetHeight() { return s_Fulltarget_height
; }
371 float Renderer::GetTargetScaleX() { return xScale
; }
372 float Renderer::GetTargetScaleY() { return yScale
; }
374 int Renderer::GetFrameBufferWidth()
376 return s_backbuffer_width
;
378 int Renderer::GetFrameBufferHeight()
380 return s_backbuffer_height
;
383 // create On-Screen-Messages
384 void Renderer::DrawDebugText()
387 if (g_ActiveConfig
.bOSDHotKey
)
391 OSDTime
= Common::Timer::GetTimeMs() + 3000;
392 OSDChoice
= -OSDChoice
;
394 if ((u32
)OSDTime
> Common::Timer::GetTimeMs())
396 std::string T1
= "", T2
= "";
397 std::vector
<std::string
> T0
;
399 std::string OSDM1
= StringFromFormat("%i x %i", OSDInternalW
, OSDInternalH
);
401 switch(g_ActiveConfig
.iAspectRatio
)
406 case ASPECT_FORCE_16_9
:
409 case ASPECT_FORCE_4_3
:
417 g_ActiveConfig
.bCrop
? " (crop)" : "";
418 std::string OSDM3
= "Disabled";
420 // if there is more text than this we will have a collission
421 if (g_ActiveConfig
.bShowFPS
)
422 { T1
+= "\n\n"; T2
+= "\n\n"; }
424 T0
.push_back(StringFromFormat("3: Internal Resolution: %s\n", OSDM1
.c_str()));
425 T0
.push_back(StringFromFormat("4: Aspect Ratio: %s%s\n", OSDM21
.c_str(), OSDM22
.c_str()));
426 T0
.push_back(StringFromFormat("5: Copy EFB: %s\n", OSDM3
.c_str()));
427 T0
.push_back(StringFromFormat("6: Fog: %s\n", g_ActiveConfig
.bDisableFog
? "Disabled" : "Enabled"));
428 T0
.push_back(StringFromFormat("7: Material Lighting: %s\n", g_ActiveConfig
.bDisableLighting
? "Disabled" : "Enabled"));
430 // latest changed setting in yellow
431 T1
+= (OSDChoice
== -1) ? T0
.at(0) : "\n";
432 T1
+= (OSDChoice
== -2) ? T0
.at(1) : "\n";
433 T1
+= (OSDChoice
== -3) ? T0
.at(2) : "\n";
434 T1
+= (OSDChoice
== -4) ? T0
.at(3) : "\n";
435 T1
+= (OSDChoice
== -5) ? T0
.at(4) : "\n";
437 // other settings in cyan
438 T2
+= (OSDChoice
!= -1) ? T0
.at(0) : "\n";
439 T2
+= (OSDChoice
!= -2) ? T0
.at(1) : "\n";
440 T2
+= (OSDChoice
!= -3) ? T0
.at(2) : "\n";
441 T2
+= (OSDChoice
!= -4) ? T0
.at(3) : "\n";
442 T2
+= (OSDChoice
!= -5) ? T0
.at(4) : "\n";
444 // render a shadow, and then the text
445 Renderer::RenderText(T1
.c_str(), 21, 21, 0xDD000000);
446 Renderer::RenderText(T1
.c_str(), 20, 20, 0xFFffff00);
447 Renderer::RenderText(T2
.c_str(), 21, 21, 0xDD000000);
448 Renderer::RenderText(T2
.c_str(), 20, 20, 0xFF00FFFF);
453 void Renderer::RenderText(const char* text
, int left
, int top
, u32 color
)
455 D3D::font
.DrawTextScaled((float)left
, (float)top
, 20.f
, 0.0f
, color
, text
, false);
458 TargetRectangle
Renderer::ConvertEFBRectangle(const EFBRectangle
& rc
)
460 int Xstride
= (s_Fulltarget_width
- s_target_width
) / 2;
461 int Ystride
= (s_Fulltarget_height
- s_target_height
) / 2;
462 TargetRectangle result
;
463 result
.left
= (int)(rc
.left
* xScale
) + Xstride
;
464 result
.top
= (int)(rc
.top
* yScale
) + Ystride
;
465 result
.right
= (int)(rc
.right
* xScale
) + Xstride
;
466 result
.bottom
= (int)(rc
.bottom
* yScale
) + Ystride
;
470 void CheckForResize()
472 while (EmuWindow::IsSizing())
475 if (EmuWindow::GetParentWnd())
477 // re-stretch window to parent window size again, if it has a parent window.
479 GetWindowRect(EmuWindow::GetParentWnd(), &rcParentWindow
);
480 int width
= rcParentWindow
.right
- rcParentWindow
.left
;
481 int height
= rcParentWindow
.bottom
- rcParentWindow
.top
;
482 if (width
!= s_backbuffer_width
|| height
!= s_backbuffer_height
)
483 ::MoveWindow(EmuWindow::GetWnd(), 0, 0, width
, height
, FALSE
);
486 GetClientRect(EmuWindow::GetWnd(), &rcWindow
);
487 int client_width
= rcWindow
.right
- rcWindow
.left
;
488 int client_height
= rcWindow
.bottom
- rcWindow
.top
;
491 if ((client_width
!= s_backbuffer_width
|| client_height
!= s_backbuffer_height
) &&
492 client_width
>= 4 && client_height
>= 4)
494 WindowResized
= true;
498 void Renderer::RenderToXFB(u32 xfbAddr
, u32 fbWidth
, u32 fbHeight
, const EFBRectangle
& sourceRc
)
500 if (!fbWidth
|| !fbHeight
)
502 VideoFifo_CheckEFBAccess();
503 VideoFifo_CheckSwapRequestAt(xfbAddr
, fbWidth
, fbHeight
);
505 // XXX: Without the VI, how would we know what kind of field this is? So
506 // just use progressive.
507 if (g_ActiveConfig
.bUseXFB
)
509 FBManager
.CopyToXFB(xfbAddr
, fbWidth
, fbHeight
, sourceRc
);
513 Renderer::Swap(xfbAddr
, FIELD_PROGRESSIVE
, fbWidth
, fbHeight
,sourceRc
);
514 Common::AtomicStoreRelease(s_swapRequested
, FALSE
);
518 bool Renderer::SetScissorRect()
520 int xoff
= bpmem
.scissorOffset
.x
* 2 - 342;
521 int yoff
= bpmem
.scissorOffset
.y
* 2 - 342;
522 D3D11_RECT rc
= CD3D11_RECT(bpmem
.scissorTL
.x
- xoff
- 342,
523 bpmem
.scissorTL
.y
- yoff
- 342,
524 bpmem
.scissorBR
.x
- xoff
- 341,
525 bpmem
.scissorBR
.y
- yoff
- 341);
527 int Xstride
= (s_Fulltarget_width
- s_target_width
) / 2;
528 int Ystride
= (s_Fulltarget_height
- s_target_height
) / 2;
530 rc
.left
= (int)(rc
.left
* xScale
);
531 rc
.top
= (int)(rc
.top
* yScale
);
532 rc
.right
= (int)(rc
.right
* xScale
);
533 rc
.bottom
= (int)(rc
.bottom
* yScale
);
535 if (rc
.left
< 0) rc
.left
= 0;
536 if (rc
.right
< 0) rc
.right
= 0;
537 if (rc
.left
> s_target_width
) rc
.left
= s_target_width
;
538 if (rc
.right
> s_target_width
) rc
.right
= s_target_width
;
539 if (rc
.top
< 0) rc
.top
= 0;
540 if (rc
.bottom
< 0) rc
.bottom
= 0;
541 if (rc
.top
> s_target_height
) rc
.top
= s_target_height
;
542 if (rc
.bottom
> s_target_height
) rc
.bottom
= s_target_height
;
547 rc
.bottom
+= Ystride
;
549 if (rc
.left
> rc
.right
)
555 if (rc
.top
> rc
.bottom
)
557 int temp
= rc
.bottom
;
562 if (rc
.right
>= rc
.left
&& rc
.bottom
>= rc
.top
)
564 D3D::context
->RSSetScissorRects(1, &rc
);
569 //WARN_LOG(VIDEO, "Bad scissor rectangle: %i %i %i %i", rc.left, rc.top, rc.right, rc.bottom);
570 rc
= CD3D11_RECT(Xstride
, Ystride
, Xstride
+ s_target_width
, Ystride
+ s_target_height
);
571 D3D::context
->RSSetScissorRects(1, &rc
);
577 void Renderer::SetColorMask()
579 UINT8 color_mask
= 0;
580 if (bpmem
.blendmode
.alphaupdate
) color_mask
|= D3D11_COLOR_WRITE_ENABLE_ALPHA
;
581 if (bpmem
.blendmode
.colorupdate
) color_mask
|= D3D11_COLOR_WRITE_ENABLE_RED
| D3D11_COLOR_WRITE_ENABLE_GREEN
| D3D11_COLOR_WRITE_ENABLE_BLUE
;
582 D3D::gfxstate
->SetRenderTargetWriteMask(color_mask
);
585 u32
Renderer::AccessEFB(EFBAccessType type
, int x
, int y
)
587 ID3D11Texture2D
* read_tex
;
589 if (!g_ActiveConfig
.bEFBAccessEnable
)
592 if (type
== POKE_Z
|| type
== POKE_COLOR
)
594 static bool alert_only_once
= true;
595 if (!alert_only_once
) return 0;
596 PanicAlert("Poke EFB not implemented");
597 alert_only_once
= false;
601 // get the rectangular target region covered by the EFB pixel
602 EFBRectangle efbPixelRc
;
605 efbPixelRc
.right
= x
+ 1;
606 efbPixelRc
.bottom
= y
+ 1;
608 TargetRectangle targetPixelRc
= Renderer::ConvertEFBRectangle(efbPixelRc
);
612 D3D11_RECT RectToLock
= CD3D11_RECT(targetPixelRc
.left
, targetPixelRc
.top
, targetPixelRc
.right
, targetPixelRc
.bottom
);
615 // depth buffers can only be completely CopySubresourceRegion'ed, so we're using drawShadedTexQuad instead
617 RectToLock
.bottom
+=2;
621 if ((RectToLock
.bottom
- RectToLock
.top
) > 4)
623 if ((RectToLock
.right
- RectToLock
.left
) > 4)
626 ResetAPIState(); // reset any game specific settings
628 // Stretch picture with increased internal resolution
629 D3D11_VIEWPORT vp
= CD3D11_VIEWPORT(0.f
, 0.f
, 4.f
, 4.f
);
630 D3D::context
->RSSetViewports(1, &vp
);
631 D3D::context
->PSSetConstantBuffers(0, 1, &access_efb_cbuf
);
632 D3D::context
->OMSetRenderTargets(1, &FBManager
.GetEFBDepthReadTexture()->GetRTV(), NULL
);
633 D3D::SetPointCopySampler();
634 D3D::drawShadedTexQuad(FBManager
.GetEFBDepthTexture()->GetSRV(),
636 Renderer::GetFullTargetWidth(),
637 Renderer::GetFullTargetHeight(),
638 PixelShaderCache::GetDepthMatrixProgram(),
639 VertexShaderCache::GetSimpleVertexShader(),
640 VertexShaderCache::GetSimpleInputLayout());
642 D3D::context
->OMSetRenderTargets(1, &FBManager
.GetEFBColorTexture()->GetRTV(), FBManager
.GetEFBDepthTexture()->GetDSV());
644 RectToLock
= CD3D11_RECT(0, 0, 4, 4);
646 // copy to system memory
647 D3D11_BOX box
= CD3D11_BOX(0, 0, 0, 4, 4, 1);
648 read_tex
= FBManager
.GetEFBDepthStagingBuffer();
649 D3D::context
->CopySubresourceRegion(read_tex
, 0, 0, 0, 0, FBManager
.GetEFBDepthReadTexture()->GetTex(), 0, &box
);
653 // we can directly copy to system memory here
654 read_tex
= FBManager
.GetEFBColorStagingBuffer();
655 D3D11_BOX box
= CD3D11_BOX(RectToLock
.left
, RectToLock
.top
, 0, RectToLock
.right
, RectToLock
.bottom
, 1);
656 D3D::context
->CopySubresourceRegion(read_tex
, 0, 0, 0, 0, FBManager
.GetEFBColorTexture()->GetTex(), 0, &box
);
657 RectToLock
= CD3D11_RECT(0, 0, 1, 1);
660 // read the data from system memory
661 D3D11_MAPPED_SUBRESOURCE map
;
662 D3D::context
->Map(read_tex
, 0, D3D11_MAP_READ
, 0, &map
);
666 val
= ((float*)map
.pData
)[0];
667 z
= ((u32
)(val
* 0xffffff));
671 z
= ((u32
*)map
.pData
)[0];
674 // TODO: Implement POKE_Z and POKE_COLOR
678 D3D::context
->Unmap(read_tex
, 0);
682 // Called from VertexShaderManager
683 void UpdateViewport()
685 // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
688 // [2] = 16777215 * (farz - nearz)
689 // [3] = xorig + width/2 + 342
690 // [4] = yorig + height/2 + 342
691 // [5] = 16777215 * farz
692 const int old_fulltarget_w
= s_Fulltarget_width
;
693 const int old_fulltarget_h
= s_Fulltarget_height
;
695 int scissorXOff
= bpmem
.scissorOffset
.x
* 2;
696 int scissorYOff
= bpmem
.scissorOffset
.y
* 2;
698 float MValueX
= Renderer::GetTargetScaleX();
699 float MValueY
= Renderer::GetTargetScaleY();
701 int Xstride
= (s_Fulltarget_width
- s_target_width
) / 2;
702 int Ystride
= (s_Fulltarget_height
- s_target_height
) / 2;
704 // Stretch picture with increased internal resolution
705 int X
= (int)(ceil(xfregs
.rawViewport
[3] - xfregs
.rawViewport
[0] - (scissorXOff
)) * MValueX
) + Xstride
;
706 int Y
= (int)(ceil(xfregs
.rawViewport
[4] + xfregs
.rawViewport
[1] - (scissorYOff
)) * MValueY
) + Ystride
;
707 int Width
= (int)ceil((int)(2 * xfregs
.rawViewport
[0]) * MValueX
);
708 int Height
= (int)ceil((int)(-2 * xfregs
.rawViewport
[1]) * MValueY
);
719 bool sizeChanged
= false;
722 s_Fulltarget_width
-= 2 * X
;
728 s_Fulltarget_height
-= 2 * Y
;
733 float newx
= (float)X
;
734 float newy
= (float)Y
;
735 float newwidth
= (float)Width
;
736 float newheight
= (float)Height
;
739 // Make sure that the requested size is actually supported by the GFX driver
740 if (s_Fulltarget_width
> (int)D3D::GetMaxTextureSize() || s_Fulltarget_height
> (int)D3D::GetMaxTextureSize())
742 // Skip EFB recreation and viewport setting. Most likely causes glitches in this case, but prevents crashes at least
743 ERROR_LOG(VIDEO
, "Tried to set a viewport which is too wide to emulate with Direct3D11. Requested EFB size is %dx%d\n", s_Fulltarget_width
, s_Fulltarget_height
);
745 // Fix the viewport to fit to the old EFB size, TODO: Check this for off-by-one errors
746 newx
*= (float)old_fulltarget_w
/ (float)s_Fulltarget_width
;
747 newy
*= (float)old_fulltarget_h
/ (float)s_Fulltarget_height
;
748 newwidth
*= (float)old_fulltarget_w
/ (float)s_Fulltarget_width
;
749 newheight
*= (float)old_fulltarget_h
/ (float)s_Fulltarget_height
;
751 s_Fulltarget_width
= old_fulltarget_w
;
752 s_Fulltarget_height
= old_fulltarget_h
;
756 D3D::context
->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), NULL
);
759 D3D::context
->OMSetRenderTargets(1, &FBManager
.GetEFBColorTexture()->GetRTV(), FBManager
.GetEFBDepthTexture()->GetDSV());
763 // some games set invalids values MinDepth and MaxDepth so fix them to the max an min allowed and let the shaders do this work
764 D3D11_VIEWPORT vp
= CD3D11_VIEWPORT(newx
, newy
, newwidth
, newheight
,
765 0.f
, // (xfregs.rawViewport[5] - xfregs.rawViewport[2]) / 16777216.0f;
766 1.f
); // xfregs.rawViewport[5] / 16777216.0f;
767 D3D::context
->RSSetViewports(1, &vp
);
769 // Tino: color is passed in bgra mode so need to convert it to rgba
770 void Renderer::ClearScreen(const EFBRectangle
& rc
, bool colorEnable
, bool alphaEnable
, bool zEnable
, u32 color
, u32 z
)
772 TargetRectangle targetRc
= Renderer::ConvertEFBRectangle(rc
);
773 // update the view port for clearing the picture
774 D3D11_VIEWPORT vp
= CD3D11_VIEWPORT((float)targetRc
.left
, (float)targetRc
.top
, (float)targetRc
.GetWidth(), (float)targetRc
.GetHeight(),
777 D3D::context
->RSSetViewports(1, &vp
);
779 // always set the scissor in case it was set by the game and has not been reset
780 D3D11_RECT sirc
= CD3D11_RECT(targetRc
.left
, targetRc
.top
, targetRc
.right
, targetRc
.bottom
);
781 D3D::context
->RSSetScissorRects(1, &sirc
);
782 u32 rgbaColor
= (color
& 0xFF00FF00) | ((color
>> 16) & 0xFF) | ((color
<< 16) & 0xFF0000);
783 D3D::stateman
->PushDepthState(cleardepthstates
[zEnable
]);
784 D3D::stateman
->PushRasterizerState(clearraststate
);
785 //D3D::stateman->PushBlendState(resetblendstate); temporarily commented until I find the cause of the blending issue in mkwii (see next line)
786 D3D::gfxstate
->ApplyState(); // TODO (neobrain): find out whether this breaks/fixes anything or can just be dropped. Might obsolete the comment above this line
787 D3D::drawClearQuad(rgbaColor
, (z
& 0xFFFFFF) / float(0xFFFFFF), PixelShaderCache::GetClearProgram(), VertexShaderCache::GetClearVertexShader(), VertexShaderCache::GetClearInputLayout());
788 D3D::gfxstate
->Reset();
789 D3D::stateman
->PopDepthState();
790 D3D::stateman
->PopRasterizerState();
791 // D3D::stateman->PopBlendState();
796 void Renderer::SetBlendMode(bool forceUpdate
)
798 if (bpmem
.blendmode
.logicopenable
)
801 if (bpmem
.blendmode
.subtract
) // enable blending src 1 dst 1
803 D3D::gfxstate
->SetAlphaBlendEnable(true);
804 D3D::gfxstate
->SetBlendOp(D3D11_BLEND_OP_REV_SUBTRACT
);
805 D3D::gfxstate
->SetSrcBlend(d3dSrcFactors
[1]);
806 D3D::gfxstate
->SetDestBlend(d3dDestFactors
[1]);
810 D3D::gfxstate
->SetAlphaBlendEnable(bpmem
.blendmode
.blendenable
&& (!( bpmem
.blendmode
.srcfactor
== 1 && bpmem
.blendmode
.dstfactor
== 0)));
811 if (bpmem
.blendmode
.blendenable
&& (!( bpmem
.blendmode
.srcfactor
== 1 && bpmem
.blendmode
.dstfactor
== 0)))
813 D3D::gfxstate
->SetBlendOp(D3D11_BLEND_OP_ADD
);
814 D3D::gfxstate
->SetSrcBlend(d3dSrcFactors
[bpmem
.blendmode
.srcfactor
]);
815 D3D::gfxstate
->SetDestBlend(d3dDestFactors
[bpmem
.blendmode
.dstfactor
]);
821 void Renderer::Swap(u32 xfbAddr
, FieldType field
, u32 fbWidth
, u32 fbHeight
,const EFBRectangle
& rc
)
823 if (g_bSkipCurrentFrame
|| (!XFBWrited
&& !g_ActiveConfig
.bUseRealXFB
) || !fbWidth
|| !fbHeight
)
825 g_VideoInitialize
.pCopiedToXFB(false);
828 // this function is called after the XFB field is changed, not after
829 // EFB is copied to XFB. In this way, flickering is reduced in games
830 // and seems to also give more FPS in ZTP
832 if (field
== FIELD_LOWER
) xfbAddr
-= fbWidth
* 2;
834 const XFBSource
** xfbSourceList
= FBManager
.GetXFBSource(xfbAddr
, fbWidth
, fbHeight
, xfbCount
);
835 if ((!xfbSourceList
|| xfbCount
== 0) && g_ActiveConfig
.bUseXFB
&& !g_ActiveConfig
.bUseRealXFB
)
837 g_VideoInitialize
.pCopiedToXFB(false);
841 Renderer::ResetAPIState();
843 // prepare copying the XFBs to our backbuffer
844 TargetRectangle dst_rect
;
845 ComputeDrawRectangle(s_backbuffer_width
, s_backbuffer_height
, false, &dst_rect
);
846 D3D11_VIEWPORT vp
= CD3D11_VIEWPORT(0.f
, 0.f
, (float)s_backbuffer_width
, (float)s_backbuffer_height
);
847 D3D::context
->RSSetViewports(1, &vp
);
848 float ClearColor
[4] = { 0.f
, 0.f
, 0.f
, 1.f
};
849 D3D::context
->ClearRenderTargetView(D3D::GetBackBuffer()->GetRTV(), ClearColor
);
851 int X
= dst_rect
.left
;
852 int Y
= dst_rect
.top
;
853 int Width
= dst_rect
.right
- dst_rect
.left
;
854 int Height
= dst_rect
.bottom
- dst_rect
.top
;
858 if (X
> s_backbuffer_width
) X
= s_backbuffer_width
;
859 if (Y
> s_backbuffer_height
) Y
= s_backbuffer_height
;
860 if (Width
< 0) Width
= 0;
861 if (Height
< 0) Height
= 0;
862 if (Width
> (s_backbuffer_width
- X
)) Width
= s_backbuffer_width
- X
;
863 if (Height
> (s_backbuffer_height
- Y
)) Height
= s_backbuffer_height
- Y
;
864 vp
= CD3D11_VIEWPORT((float)X
, (float)Y
, (float)Width
, (float)Height
);
865 D3D::context
->RSSetViewports(1, &vp
);
866 D3D::context
->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), NULL
);
868 // activate linear filtering for the buffer copies
869 D3D::SetLinearCopySampler();
871 if(g_ActiveConfig
.bUseXFB
)
873 const XFBSource
* xfbSource
;
875 // draw each xfb source
876 for (u32 i
= 0; i
< xfbCount
; ++i
)
878 xfbSource
= xfbSourceList
[i
];
879 MathUtil::Rectangle
<float> sourceRc
;
883 sourceRc
.right
= xfbSource
->texWidth
;
884 sourceRc
.bottom
= xfbSource
->texHeight
;
886 MathUtil::Rectangle
<float> drawRc
;
888 if (g_ActiveConfig
.bUseXFB
&& !g_ActiveConfig
.bUseRealXFB
)
890 // use virtual xfb with offset
891 int xfbHeight
= xfbSource
->srcHeight
;
892 int xfbWidth
= xfbSource
->srcWidth
;
893 int hOffset
= ((s32
)xfbSource
->srcAddr
- (s32
)xfbAddr
) / ((s32
)fbWidth
* 2);
895 drawRc
.bottom
= 1.0f
- 2.0f
* ((hOffset
) / (float)fbHeight
);
896 drawRc
.top
= 1.0f
- 2.0f
* ((hOffset
+ xfbHeight
) / (float)fbHeight
);
897 drawRc
.left
= -(xfbWidth
/ (float)fbWidth
);
898 drawRc
.right
= (xfbWidth
/ (float)fbWidth
);
901 if (!g_ActiveConfig
.bAutoScale
)
903 // scale draw area for a 1 to 1 pixel mapping with the draw target
904 float vScale
= (float)fbHeight
/ (float)s_backbuffer_height
;
905 float hScale
= (float)fbWidth
/ (float)s_backbuffer_width
;
907 drawRc
.top
*= vScale
;
908 drawRc
.bottom
*= vScale
;
909 drawRc
.left
*= hScale
;
910 drawRc
.right
*= hScale
;
920 D3D::drawShadedTexSubQuad(xfbSource
->tex
->GetSRV(), &sourceRc
, xfbSource
->texWidth
, xfbSource
->texHeight
, &drawRc
, PixelShaderCache::GetColorCopyProgram(),VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout());
925 TargetRectangle targetRc
= Renderer::ConvertEFBRectangle(rc
);
926 D3DTexture2D
* read_texture
= FBManager
.GetEFBColorTexture();
927 D3D::drawShadedTexQuad(read_texture
->GetSRV(), targetRc
.AsRECT(), Renderer::GetFullTargetWidth(), Renderer::GetFullTargetHeight(), PixelShaderCache::GetColorCopyProgram(),VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout());
929 // done with drawing the game stuff, good moment to save a screenshot
932 // copy back buffer to system memory
933 ID3D11Texture2D
* buftex
;
934 D3D11_TEXTURE2D_DESC tex_desc
= CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM
, D3D::GetBackBufferWidth(), D3D::GetBackBufferHeight(), 1, 1, 0, D3D11_USAGE_STAGING
, D3D11_CPU_ACCESS_READ
|D3D11_CPU_ACCESS_WRITE
);
935 HRESULT hr
= D3D::device
->CreateTexture2D(&tex_desc
, NULL
, &buftex
);
936 if (FAILED(hr
)) PanicAlert("Failed to create screenshot buffer texture");
937 D3D::context
->CopyResource(buftex
, (ID3D11Resource
*)D3D::GetBackBuffer()->GetTex());
939 // D3DX11SaveTextureToFileA doesn't allow us to ignore the alpha channel, so we need to strip it out ourselves
940 D3D11_MAPPED_SUBRESOURCE map
;
941 D3D::context
->Map(buftex
, 0, D3D11_MAP_READ_WRITE
, 0, &map
);
942 for (unsigned int y
= 0; y
< D3D::GetBackBufferHeight(); ++y
)
944 u8
* ptr
= (u8
*)map
.pData
+ y
* map
.RowPitch
+ 3;
945 for (unsigned int x
= 0; x
< D3D::GetBackBufferWidth(); ++x
)
951 D3D::context
->Unmap(buftex
, 0);
954 hr
= PD3DX11SaveTextureToFileA(D3D::context
, buftex
, D3DX11_IFF_PNG
, s_sScreenshotName
);
955 if (FAILED(hr
)) PanicAlert("Failed to save screenshot");
957 s_bScreenshot
= false;
960 // finally present some information
961 if (g_ActiveConfig
.bShowFPS
)
964 StringCchPrintfA(fps
, 20, "FPS: %d\n", s_fps
);
965 D3D::font
.DrawTextScaled(0,30,20,0.0f
,0xFF00FFFF,fps
,false);
967 Renderer::DrawDebugText();
969 if (g_ActiveConfig
.bOverlayStats
)
972 Statistics::ToString(buf
);
973 D3D::font
.DrawTextScaled(0,30,20,0.0f
,0xFF00FFFF,buf
,false);
975 else if (g_ActiveConfig
.bOverlayProjStats
)
978 Statistics::ToStringProj(buf
);
979 D3D::font
.DrawTextScaled(0,30,20,0.0f
,0xFF00FFFF,buf
,false);
985 TextureCache::Cleanup();
987 // enable any configuration changes
988 UpdateActiveConfig();
989 WindowResized
= false;
992 bool xfbchanged
= false;
994 if (s_XFB_width
!= fbWidth
|| s_XFB_height
!= fbHeight
)
997 s_XFB_width
= fbWidth
;
998 s_XFB_height
= fbHeight
;
999 if (s_XFB_width
< 1) s_XFB_width
= MAX_XFB_WIDTH
;
1000 if (s_XFB_width
> MAX_XFB_WIDTH
) s_XFB_width
= MAX_XFB_WIDTH
;
1001 if (s_XFB_height
< 1) s_XFB_height
= MAX_XFB_HEIGHT
;
1002 if (s_XFB_height
> MAX_XFB_HEIGHT
) s_XFB_height
= MAX_XFB_HEIGHT
;
1005 // update FPS counter
1006 static int fpscount
= 0;
1007 static unsigned long lasttime
= 0;
1008 if (Common::Timer::GetTimeMs() - lasttime
>= 1000)
1010 lasttime
= Common::Timer::GetTimeMs();
1014 if (XFBWrited
) ++fpscount
;
1016 // set default viewport and scissor, for the clear to work correctly
1019 // done. Show our work ;)
1022 // resize the back buffers NOW to avoid flickering when resizing windows
1023 if (xfbchanged
|| WindowResized
)
1025 // TODO: Aren't we still holding a reference to the back buffer right now?
1027 s_backbuffer_width
= D3D::GetBackBufferWidth();
1028 s_backbuffer_height
= D3D::GetBackBufferHeight();
1030 ComputeDrawRectangle(s_backbuffer_width
, s_backbuffer_height
, false, &dst_rect
);
1032 xScale
= (float)(dst_rect
.right
- dst_rect
.left
) / (float)s_XFB_width
;
1033 yScale
= (float)(dst_rect
.bottom
- dst_rect
.top
) / (float)s_XFB_height
;
1035 s_target_width
= (int)(EFB_WIDTH
* xScale
);
1036 s_target_height
= (int)(EFB_HEIGHT
* yScale
);
1038 D3D::context
->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), NULL
);
1039 FBManager
.Destroy();
1044 Renderer::RestoreAPIState();
1046 D3D::context
->OMSetRenderTargets(1, &FBManager
.GetEFBColorTexture()->GetRTV(), FBManager
.GetEFBDepthTexture()->GetDSV());
1048 VertexShaderManager::SetViewportChanged();
1049 g_VideoInitialize
.pCopiedToXFB(XFBWrited
|| g_ActiveConfig
.bUseRealXFB
);
1053 // ALWAYS call RestoreAPIState for each ResetAPIState call you're doing
1054 void Renderer::ResetAPIState()
1056 D3D::gfxstate
->Reset();
1057 D3D::stateman
->PushBlendState(resetblendstate
);
1058 D3D::stateman
->PushDepthState(resetdepthstate
);
1059 D3D::stateman
->PushRasterizerState(resetraststate
);
1060 D3D::stateman
->Apply();
1061 reset_called
= true;
1064 void Renderer::RestoreAPIState()
1066 // gets us back into a more game-like state.
1069 D3D::stateman
->PopBlendState();
1070 D3D::stateman
->PopDepthState();
1071 D3D::stateman
->PopRasterizerState();
1075 D3D::gfxstate
->ApplyState();
1076 reset_called
= false;
1079 void Renderer::SetGenerationMode()
1081 // rastdesc.FrontCounterClockwise must be false for this to work
1082 D3D::gfxstate
->rastdesc
.CullMode
= d3dCullModes
[bpmem
.genMode
.cullmode
];
1085 void Renderer::SetDepthMode()
1087 if (bpmem
.zmode
.testenable
)
1089 D3D::gfxstate
->depthdesc
.DepthEnable
= TRUE
;
1090 D3D::gfxstate
->depthdesc
.DepthWriteMask
= bpmem
.zmode
.updateenable
? D3D11_DEPTH_WRITE_MASK_ALL
: D3D11_DEPTH_WRITE_MASK_ZERO
;
1091 D3D::gfxstate
->depthdesc
.DepthFunc
= d3dCmpFuncs
[bpmem
.zmode
.func
];
1095 D3D::gfxstate
->depthdesc
.DepthEnable
= FALSE
;
1096 D3D::gfxstate
->depthdesc
.DepthWriteMask
= D3D11_DEPTH_WRITE_MASK_ZERO
;
1100 void Renderer::SetLogicOpMode()
1102 if (bpmem
.blendmode
.logicopenable
&& bpmem
.blendmode
.logicmode
!= 3)
1105 D3D::gfxstate
->SetAlphaBlendEnable(true);
1106 D3D::gfxstate
->SetBlendOp(d3dLogicOps
[bpmem
.blendmode
.logicmode
]);
1107 D3D::gfxstate
->SetSrcBlend(d3dLogicOpSrcFactors
[bpmem
.blendmode
.logicmode
]);
1108 D3D::gfxstate
->SetDestBlend(d3dLogicOpDestFactors
[bpmem
.blendmode
.logicmode
]);
1116 void Renderer::SetDitherMode()
1118 // TODO: Set dither mode to bpmem.blendmode.dither
1121 void Renderer::SetLineWidth()
1126 void Renderer::SetSamplerState(int stage
, int texindex
)
1128 const FourTexUnits
&tex
= bpmem
.tex
[texindex
];
1129 const TexMode0
&tm0
= tex
.texMode0
[stage
];
1130 const TexMode1
&tm1
= tex
.texMode1
[stage
];
1133 mip
= (tm0
.min_filter
== 8) ? TEXF_NONE
:d3dMipFilters
[tm0
.min_filter
& 3];
1134 if ((tm0
.min_filter
& 3) && (tm0
.min_filter
!= 8) && ((tm1
.max_lod
>> 4) == 0)) mip
= TEXF_NONE
;
1136 if (texindex
) stage
+= 4;
1138 // TODO: Clarify whether these values are correct
1139 // NOTE: since there's no "no filter" in DX11 we're using point filters in these cases
1140 if (tm0
.min_filter
& 4) // linear min filter
1142 if (tm0
.mag_filter
) // linear mag filter
1144 if (mip
== TEXF_NONE
) D3D::gfxstate
->SetSamplerFilter(stage
, D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT
);
1145 else if (mip
== TEXF_POINT
) D3D::gfxstate
->SetSamplerFilter(stage
, D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT
);
1146 else if (mip
== TEXF_LINEAR
) D3D::gfxstate
->SetSamplerFilter(stage
, D3D11_FILTER_MIN_MAG_MIP_LINEAR
);
1148 else // point mag filter
1150 if (mip
== TEXF_NONE
) D3D::gfxstate
->SetSamplerFilter(stage
, D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT
);
1151 else if (mip
== TEXF_POINT
) D3D::gfxstate
->SetSamplerFilter(stage
, D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT
);
1152 else if (mip
== TEXF_LINEAR
) D3D::gfxstate
->SetSamplerFilter(stage
, D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR
);
1155 else // point min filter
1157 if (tm0
.mag_filter
) // linear mag filter
1159 if (mip
== TEXF_NONE
) D3D::gfxstate
->SetSamplerFilter(stage
, D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT
);
1160 else if (mip
== TEXF_POINT
) D3D::gfxstate
->SetSamplerFilter(stage
, D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT
);
1161 else if (mip
== TEXF_LINEAR
) D3D::gfxstate
->SetSamplerFilter(stage
, D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR
);
1163 else // point mag filter
1165 if (mip
== TEXF_NONE
) D3D::gfxstate
->SetSamplerFilter(stage
, D3D11_FILTER_MIN_MAG_MIP_POINT
);
1166 else if (mip
== TEXF_POINT
) D3D::gfxstate
->SetSamplerFilter(stage
, D3D11_FILTER_MIN_MAG_MIP_POINT
);
1167 else if (mip
== TEXF_LINEAR
) D3D::gfxstate
->SetSamplerFilter(stage
, D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR
);
1171 D3D::gfxstate
->samplerdesc
[stage
].AddressU
= d3dClamps
[tm0
.wrap_s
];
1172 D3D::gfxstate
->samplerdesc
[stage
].AddressV
= d3dClamps
[tm0
.wrap_t
];
1174 D3D::gfxstate
->samplerdesc
[stage
].MipLODBias
= (float)tm0
.lod_bias
/32.0f
;
1175 D3D::gfxstate
->samplerdesc
[stage
].MaxLOD
= (float)tm1
.max_lod
/16.f
;
1176 D3D::gfxstate
->samplerdesc
[stage
].MinLOD
= (float)tm1
.min_lod
/16.f
;
1179 void Renderer::SetInterlacingMode()
1185 void Renderer::SetScreenshot(const char* filename
)
1187 s_criticalScreenshot
.Enter();
1188 strcpy_s(s_sScreenshotName
, filename
);
1189 s_bScreenshot
= true;
1190 s_criticalScreenshot
.Leave();