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/
21 #include "Statistics.h"
22 #include "MemoryUtil.h"
25 #include "CommonPaths.h"
29 #include "D3DTexture.h"
31 #include "FBManager.h"
32 #include "PixelShaderCache.h"
33 #include "PixelShaderManager.h"
34 #include "VertexShaderManager.h"
35 #include "VertexShaderCache.h"
39 #include "TextureDecoder.h"
40 #include "TextureCache.h"
41 #include "HiresTextures.h"
43 ID3D11BlendState
* efbcopyblendstate
= NULL
;
44 ID3D11RasterizerState
* efbcopyraststate
= NULL
;
45 ID3D11DepthStencilState
* efbcopydepthstate
= NULL
;
46 ID3D11Buffer
* efbcopycbuf
[20] = { NULL
};
48 u8
* TextureCache::temp
= NULL
;
49 TextureCache::TexCache
TextureCache::textures
;
51 extern int frameCount
;
53 #define TEMP_SIZE (1024*1024*4)
54 #define TEXTURE_KILL_THRESHOLD 200
56 void TextureCache::TCacheEntry::Destroy(bool shutdown
)
58 SAFE_RELEASE(texture
);
60 if (!isRenderTarget
&& !shutdown
&& !g_ActiveConfig
.bSafeTextureCache
)
62 u32
* ptr
= (u32
*)g_VideoInitialize
.pGetMemoryPointer(addr
);
63 if (ptr
&& *ptr
== hash
)
68 void TextureCache::Init()
72 temp
= (u8
*)AllocateMemoryPages(TEMP_SIZE
);
73 TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig
.bTexFmtOverlayEnable
, g_ActiveConfig
.bTexFmtOverlayCenter
);
74 HiresTextures::Init(globals
->unique_id
);
76 D3D11_BLEND_DESC blenddesc
;
77 blenddesc
.AlphaToCoverageEnable
= FALSE
;
78 blenddesc
.IndependentBlendEnable
= FALSE
;
79 blenddesc
.RenderTarget
[0].BlendEnable
= FALSE
;
80 blenddesc
.RenderTarget
[0].RenderTargetWriteMask
= D3D11_COLOR_WRITE_ENABLE_ALL
;
81 blenddesc
.RenderTarget
[0].SrcBlend
= D3D11_BLEND_ONE
;
82 blenddesc
.RenderTarget
[0].DestBlend
= D3D11_BLEND_ZERO
;
83 blenddesc
.RenderTarget
[0].BlendOp
= D3D11_BLEND_OP_ADD
;
84 blenddesc
.RenderTarget
[0].SrcBlendAlpha
= D3D11_BLEND_ONE
;
85 blenddesc
.RenderTarget
[0].DestBlendAlpha
= D3D11_BLEND_ZERO
;
86 blenddesc
.RenderTarget
[0].BlendOpAlpha
= D3D11_BLEND_OP_ADD
;
87 hr
= D3D::device
->CreateBlendState(&blenddesc
, &efbcopyblendstate
);
88 CHECK(hr
==S_OK
, "Create blend state for TextureCache::CopyRenderTargetToTexture");
89 D3D::SetDebugObjectName((ID3D11DeviceChild
*)efbcopyblendstate
, "blend state used in TextureCache::CopyRenderTargetToTexture");
91 D3D11_DEPTH_STENCIL_DESC depthdesc
;
92 depthdesc
.DepthEnable
= FALSE
;
93 depthdesc
.DepthWriteMask
= D3D11_DEPTH_WRITE_MASK_ALL
;
94 depthdesc
.DepthFunc
= D3D11_COMPARISON_LESS
;
95 depthdesc
.StencilEnable
= FALSE
;
96 depthdesc
.StencilReadMask
= D3D11_DEFAULT_STENCIL_READ_MASK
;
97 depthdesc
.StencilWriteMask
= D3D11_DEFAULT_STENCIL_WRITE_MASK
;
98 hr
= D3D::device
->CreateDepthStencilState(&depthdesc
, &efbcopydepthstate
);
99 CHECK(hr
==S_OK
, "Create depth state for TextureCache::CopyRenderTargetToTexture");
100 D3D::SetDebugObjectName((ID3D11DeviceChild
*)efbcopydepthstate
, "depth stencil state used in TextureCache::CopyRenderTargetToTexture");
102 D3D11_RASTERIZER_DESC rastdesc
;
103 rastdesc
.CullMode
= D3D11_CULL_NONE
;
104 rastdesc
.FillMode
= D3D11_FILL_SOLID
;
105 rastdesc
.FrontCounterClockwise
= false;
106 rastdesc
.DepthBias
= false;
107 rastdesc
.DepthBiasClamp
= 0;
108 rastdesc
.SlopeScaledDepthBias
= 0;
109 rastdesc
.DepthClipEnable
= false;
110 rastdesc
.ScissorEnable
= false;
111 rastdesc
.MultisampleEnable
= false;
112 rastdesc
.AntialiasedLineEnable
= false;
113 hr
= D3D::device
->CreateRasterizerState(&rastdesc
, &efbcopyraststate
);
114 CHECK(hr
==S_OK
, "Create rasterizer state for TextureCache::CopyRenderTargetToTexture");
115 D3D::SetDebugObjectName((ID3D11DeviceChild
*)efbcopyraststate
, "rasterizer state used in TextureCache::CopyRenderTargetToTexture");
118 void TextureCache::Invalidate(bool shutdown
)
120 for (TexCache::iterator iter
= textures
.begin(); iter
!= textures
.end(); ++iter
)
121 iter
->second
.Destroy(shutdown
);
123 HiresTextures::Shutdown();
126 void TextureCache::InvalidateRange(u32 start_address
, u32 size
)
128 TexCache::iterator iter
= textures
.begin();
129 while (iter
!= textures
.end())
131 if (iter
->second
.IntersectsMemoryRange(start_address
, size
))
133 iter
->second
.Destroy(false);
134 textures
.erase(iter
++);
143 bool TextureCache::TCacheEntry::IntersectsMemoryRange(u32 range_address
, u32 range_size
)
145 if (addr
+ size_in_bytes
< range_address
) return false;
146 if (addr
>= range_address
+ range_size
) return false;
150 void TextureCache::Shutdown()
153 FreeMemoryPages(temp
, TEMP_SIZE
);
156 SAFE_RELEASE(efbcopyblendstate
);
157 SAFE_RELEASE(efbcopyraststate
);
158 SAFE_RELEASE(efbcopydepthstate
);
160 for (unsigned int k
= 0; k
< 20;k
++)
161 SAFE_RELEASE(efbcopycbuf
[k
]);
164 void TextureCache::Cleanup()
166 TexCache::iterator iter
= textures
.begin();
167 while (iter
!= textures
.end())
169 if (frameCount
> TEXTURE_KILL_THRESHOLD
+ iter
->second
.frameCount
)
171 iter
->second
.Destroy(false);
172 iter
= textures
.erase(iter
);
181 // returns the exponent of the smallest power of two which is greater than val
182 unsigned int GetPow2(unsigned int val
)
184 unsigned int ret
= 0;
185 for (;val
;val
>>=1) ret
++;
189 TextureCache::TCacheEntry
* TextureCache::Load(unsigned int stage
, u32 address
, unsigned int width
, unsigned int height
, unsigned int tex_format
, unsigned int tlutaddr
, unsigned int tlutfmt
, bool UseNativeMips
, unsigned int maxlevel
)
191 if (address
== 0) return NULL
;
193 u8
* ptr
= g_VideoInitialize
.pGetMemoryPointer(address
);
194 unsigned int bsw
= TexDecoder_GetBlockWidthInTexels(tex_format
) - 1; // TexelSizeInNibbles(format)*width*height/16;
195 unsigned int bsh
= TexDecoder_GetBlockHeightInTexels(tex_format
) - 1; // TexelSizeInNibbles(format)*width*height/16;
196 unsigned int bsdepth
= TexDecoder_GetTexelSizeInNibbles(tex_format
);
197 unsigned int expandedWidth
= (width
+ bsw
) & (~bsw
);
198 unsigned int expandedHeight
= (height
+ bsh
) & (~bsh
);
203 u32 FullFormat
= tex_format
;
204 if ((tex_format
== GX_TF_C4
) || (tex_format
== GX_TF_C8
) || (tex_format
== GX_TF_C14X2
))
205 u32 FullFormat
= (tex_format
| (tlutfmt
<< 16));
207 // hires textures and texture dumping not supported, yet
208 if (g_ActiveConfig
.bSafeTextureCache
/* || g_ActiveConfig.bHiresTextures || g_ActiveConfig.bDumpTextures*/)
210 texHash
= TexDecoder_GetHash64(ptr
,TexDecoder_GetTextureSizeInBytes(expandedWidth
, expandedHeight
, tex_format
),g_ActiveConfig
.iSafeTextureCache_ColorSamples
);
211 if ((tex_format
== GX_TF_C4
) || (tex_format
== GX_TF_C8
) || (tex_format
== GX_TF_C14X2
))
213 // WARNING! texID != address now => may break CopyRenderTargetToTexture (cf. TODO up)
214 // tlut size can be up to 32768B (GX_TF_C14X2) but Safer == Slower.
215 // This trick (to change the texID depending on the TLUT addr) is a trick to get around
216 // an issue with metroid prime's fonts, where it has multiple sets of fonts on top of
217 // each other stored in a single texture, and uses the palette to make different characters
218 // visible or invisible. Thus, unless we want to recreate the textures for every drawn character,
219 // we must make sure that texture with different tluts get different IDs.
220 u64 tlutHash
= TexDecoder_GetHash64(&texMem
[tlutaddr
], TexDecoder_GetPaletteSize(tex_format
),g_ActiveConfig
.iSafeTextureCache_ColorSamples
);
222 if (g_ActiveConfig
.bSafeTextureCache
)
224 texID
= texID
^ ((u32
)(tlutHash
& 0xFFFFFFFF)) ^ ((u32
)((tlutHash
>> 32) & 0xFFFFFFFF));
227 if (g_ActiveConfig
.bSafeTextureCache
)
228 hash_value
= texHash
;
231 bool skip_texture_create
= false;
232 TexCache::iterator iter
= textures
.find(texID
);
234 if (iter
!= textures
.end())
236 TCacheEntry
&entry
= iter
->second
;
238 if (!g_ActiveConfig
.bSafeTextureCache
)
239 hash_value
= ((u32
*)ptr
)[0];
241 // TODO: Is the (entry.MipLevels == maxlevel) check needed?
242 if (entry
.isRenderTarget
|| ((address
== entry
.addr
) && (hash_value
== entry
.hash
) && FullFormat
== entry
.fmt
&& entry
.MipLevels
== maxlevel
))
244 entry
.frameCount
= frameCount
;
245 D3D::gfxstate
->SetShaderResource(stage
, entry
.texture
->GetSRV());
250 // Let's reload the new texture data into the same texture,
251 // instead of destroying it and having to create a new one.
252 // Might speed up movie playback very, very slightly.
254 // TODO: Is the (entry.MipLevels < maxlevel) check needed?
255 if (width
== entry
.w
&& height
==entry
.h
&& FullFormat
== entry
.fmt
&& entry
.MipLevels
< maxlevel
)
257 skip_texture_create
= true;
261 entry
.Destroy(false);
262 textures
.erase(iter
);
267 // make an entry in the table
268 TCacheEntry
& entry
= textures
[texID
];
269 PC_TexFormat pcfmt
= PC_TEX_FMT_NONE
;
271 pcfmt
= TexDecoder_Decode(temp
, ptr
, expandedWidth
, expandedHeight
, tex_format
, tlutaddr
, tlutfmt
, true);
273 entry
.oldpixel
= ((u32
*)ptr
)[0];
274 if (g_ActiveConfig
.bSafeTextureCache
) entry
.hash
= hash_value
;
275 else entry
.hash
= ((u32
*)ptr
)[0] = (u32
)(((double)rand() / RAND_MAX
) * 0xFFFFFFFF);
277 bool isPow2
= !((width
& (width
- 1)) || (height
& (height
- 1)));
278 unsigned int TexLevels
= (isPow2
&& UseNativeMips
&& maxlevel
) ? GetPow2(max(width
, height
)) : ((isPow2
)? 0 : 1);
279 if (TexLevels
> (maxlevel
+ 1) && maxlevel
)
280 TexLevels
= maxlevel
+ 1;
282 D3D11_USAGE usage
= (TexLevels
== 1) ? D3D11_USAGE_DYNAMIC
: D3D11_USAGE_DEFAULT
;
284 if (!skip_texture_create
)
286 // TODO: A little more verbosity in the debug names would be quite helpful..
287 D3D11_CPU_ACCESS_FLAG cpu_access
= (TexLevels
== 1) ? D3D11_CPU_ACCESS_WRITE
: (D3D11_CPU_ACCESS_FLAG
)0;
288 ID3D11Texture2D
* pTexture
= NULL
;
290 D3D11_SUBRESOURCE_DATA data
;
292 data
.SysMemPitch
= 4*expandedWidth
;
294 D3D11_TEXTURE2D_DESC texdesc
= CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM
, width
, height
, 1, TexLevels
, D3D11_BIND_SHADER_RESOURCE
, usage
, cpu_access
);
295 hr
= D3D::device
->CreateTexture2D(&texdesc
, (TexLevels
==1)?&data
:NULL
, &pTexture
);
296 CHECK(hr
==S_OK
, "Create texture of the TextureCache");
297 entry
.texture
= new D3DTexture2D(pTexture
, D3D11_BIND_SHADER_RESOURCE
);
298 CHECK(entry
.texture
!=NULL
, "Create texture of the TextureCache");
299 D3D::SetDebugObjectName((ID3D11DeviceChild
*)entry
.texture
->GetTex(), "a texture of the TextureCache");
300 D3D::SetDebugObjectName((ID3D11DeviceChild
*)entry
.texture
->GetSRV(), "shader resource view of a texture of the TextureCache");
303 if (TexLevels
!= 1) D3D::ReplaceRGBATexture2D(entry
.texture
->GetTex(), temp
, width
, height
, expandedWidth
, 0, usage
);
307 D3D::ReplaceRGBATexture2D(entry
.texture
->GetTex(), temp
, width
, height
, expandedWidth
, 0, usage
);
309 entry
.addr
= address
;
310 entry
.size_in_bytes
= TexDecoder_GetTextureSizeInBytes(expandedWidth
, expandedHeight
, tex_format
);
311 entry
.isRenderTarget
= false;
312 entry
.isNonPow2
= false;
313 entry
.MipLevels
= maxlevel
;
315 if (TexLevels
== 0) PD3DX11FilterTexture(D3D::context
, entry
.texture
->GetTex(), 0, D3DX11_DEFAULT
);
316 else if (TexLevels
> 1 && pcfmt
!= PC_TEX_FMT_NONE
)
318 unsigned int level
= 1;
319 unsigned int mipWidth
= (width
+ 1) >> 1;
320 unsigned int mipHeight
= (height
+ 1) >> 1;
321 ptr
+= entry
.size_in_bytes
;
322 while ((mipHeight
|| mipWidth
) && (level
< TexLevels
))
324 unsigned int currentWidth
= (mipWidth
> 0) ? mipWidth
: 1;
325 unsigned int currentHeight
= (mipHeight
> 0) ? mipHeight
: 1;
326 expandedWidth
= (currentWidth
+ bsw
) & (~bsw
);
327 expandedHeight
= (currentHeight
+ bsh
) & (~bsh
);
328 TexDecoder_Decode(temp
, ptr
, expandedWidth
, expandedHeight
, tex_format
, tlutaddr
, tlutfmt
, true);
329 D3D::ReplaceRGBATexture2D(entry
.texture
->GetTex(), temp
, currentWidth
, currentHeight
, expandedWidth
, level
, usage
);
330 u32 size
= (max(mipWidth
, bsw
) * max(mipHeight
, bsh
) * bsdepth
) >> 1;
337 entry
.frameCount
= frameCount
;
340 entry
.fmt
= FullFormat
;
342 INCSTAT(stats
.numTexturesCreated
);
343 SETSTAT(stats
.numTexturesAlive
, (int)textures
.size());
345 D3D::gfxstate
->SetShaderResource(stage
, entry
.texture
->GetSRV());
350 void TextureCache::CopyRenderTargetToTexture(u32 address
, bool bFromZBuffer
, bool bIsIntensityFmt
, u32 copyfmt
, unsigned int bScaleByHalf
, const EFBRectangle
&source_rect
)
352 int efb_w
= source_rect
.GetWidth();
353 int efb_h
= source_rect
.GetHeight();
355 int tex_w
= (abs(source_rect
.GetWidth()) >> bScaleByHalf
);
356 int tex_h
= (abs(source_rect
.GetHeight()) >> bScaleByHalf
);
358 int Scaledtex_w
= (g_ActiveConfig
.bCopyEFBScaled
) ? ((int)(Renderer::GetTargetScaleX() * tex_w
)) : tex_w
;
359 int Scaledtex_h
= (g_ActiveConfig
.bCopyEFBScaled
) ? ((int)(Renderer::GetTargetScaleY() * tex_h
)) : tex_h
;
361 TexCache::iterator iter
;
362 D3DTexture2D
* tex
= NULL
;
363 iter
= textures
.find(address
);
364 if (iter
!= textures
.end())
366 if (iter
->second
.isRenderTarget
&& iter
->second
.Scaledw
== Scaledtex_w
&& iter
->second
.Scaledh
== Scaledtex_h
)
368 tex
= iter
->second
.texture
;
369 iter
->second
.frameCount
= frameCount
;
373 // remove it and recreate it as a render target
374 SAFE_RELEASE(iter
->second
.texture
);
375 textures
.erase(iter
);
382 entry
.isRenderTarget
= true;
384 entry
.frameCount
= frameCount
;
387 entry
.Scaledw
= Scaledtex_w
;
388 entry
.Scaledh
= Scaledtex_h
;
390 entry
.isNonPow2
= true;
391 entry
.texture
= D3DTexture2D::Create(Scaledtex_w
, Scaledtex_h
, (D3D11_BIND_FLAG
)((int)D3D11_BIND_RENDER_TARGET
|(int)D3D11_BIND_SHADER_RESOURCE
), D3D11_USAGE_DEFAULT
, DXGI_FORMAT_R8G8B8A8_UNORM
);
392 if (entry
.texture
== NULL
) PanicAlert("CopyRenderTargetToTexture failed to create entry.texture at %s %d\n", __FILE__
, __LINE__
);
393 textures
[address
] = entry
;
397 float colmat
[20]= {0.0f
}; // last four floats for fConstAdd
398 unsigned int cbufid
= (unsigned int)-1;
400 // TODO: Move this to TextureCache::Init()
407 colmat
[0] = colmat
[4] = colmat
[8] = colmat
[12] = 1.0f
;
411 colmat
[1] = colmat
[5] = colmat
[9] = colmat
[12] = 1.0f
;
413 case 11: // Z16 (reverse order)
414 colmat
[0] = colmat
[4] = colmat
[8] = colmat
[13] = 1.0f
;
418 colmat
[0] = colmat
[5] = colmat
[10] = 1.0f
;
422 colmat
[1] = colmat
[5] = colmat
[9] = colmat
[13] = 1.0f
;
426 colmat
[2] = colmat
[6] = colmat
[10] = colmat
[14] = 1.0f
;
430 colmat
[2] = colmat
[6] = colmat
[10] = colmat
[13] = 1.0f
;
434 ERROR_LOG(VIDEO
, "Unknown copy zbuf format: 0x%x", copyfmt
);
435 colmat
[2] = colmat
[5] = colmat
[8] = 1.0f
;
440 else if (bIsIntensityFmt
)
442 colmat
[16] = colmat
[17] = colmat
[18] = 16.0f
/255.0f
;
449 // TODO - verify these coefficients
450 colmat
[0] = 0.257f
; colmat
[1] = 0.504f
; colmat
[2] = 0.098f
;
451 colmat
[4] = 0.257f
; colmat
[5] = 0.504f
; colmat
[6] = 0.098f
;
452 colmat
[8] = 0.257f
; colmat
[9] = 0.504f
; colmat
[10] = 0.098f
;
456 colmat
[19] = 16.0f
/ 255.0f
;
457 colmat
[12] = 0.257f
; colmat
[13] = 0.504f
; colmat
[14] = 0.098f
;
468 ERROR_LOG(VIDEO
, "Unknown copy intensity format: 0x%x", copyfmt
);
469 colmat
[0] = colmat
[5] = colmat
[10] = colmat
[15] = 1;
479 colmat
[0] = colmat
[4] = colmat
[8] = colmat
[12] = 1;
484 colmat
[0] = colmat
[4] = colmat
[8] = colmat
[15] = 1;
489 colmat
[3] = colmat
[7] = colmat
[11] = colmat
[15] = 1;
493 colmat
[1] = colmat
[5] = colmat
[9] = colmat
[13] = 1;
497 colmat
[2] = colmat
[6] = colmat
[10] = colmat
[14] = 1;
501 colmat
[0] = colmat
[4] = colmat
[8] = colmat
[13] = 1;
505 colmat
[1] = colmat
[5] = colmat
[9] = colmat
[14] = 1;
510 colmat
[0] = colmat
[5] = colmat
[10] = 1;
511 colmat
[19] = 1; // set alpha to 1
516 colmat
[0] = colmat
[5] = colmat
[10] = colmat
[15] = 1;
521 ERROR_LOG(VIDEO
, "Unknown copy color format: 0x%x", copyfmt
);
522 colmat
[0] = colmat
[5] = colmat
[10] = colmat
[15] = 1;
528 Renderer::ResetAPIState(); // reset any game specific settings
530 // stretch picture with increased internal resolution
531 D3D11_VIEWPORT vp
= CD3D11_VIEWPORT(0.f
, 0.f
, (float)Scaledtex_w
, (float)Scaledtex_h
);
532 D3D::context
->RSSetViewports(1, &vp
);
533 D3D11_RECT destrect
= CD3D11_RECT(0, 0, Scaledtex_w
, Scaledtex_h
);
535 // set transformation
536 if (efbcopycbuf
[cbufid
] == NULL
)
538 D3D11_BUFFER_DESC cbdesc
= CD3D11_BUFFER_DESC(20*sizeof(float), D3D11_BIND_CONSTANT_BUFFER
, D3D11_USAGE_DEFAULT
);
539 D3D11_SUBRESOURCE_DATA data
;
540 data
.pSysMem
= colmat
;
541 HRESULT hr
= D3D::device
->CreateBuffer(&cbdesc
, &data
, &efbcopycbuf
[cbufid
]);
542 CHECK(hr
==S_OK
, "Create efb copy constant buffer %d", cbufid
);
543 D3D::SetDebugObjectName((ID3D11DeviceChild
*)efbcopycbuf
[cbufid
], "a constant buffer used in TextureCache::CopyRenderTargetToTexture");
545 D3D::context
->PSSetConstantBuffers(0, 1, &efbcopycbuf
[cbufid
]);
547 TargetRectangle targetSource
= Renderer::ConvertEFBRectangle(source_rect
);
548 D3D11_RECT sourcerect
= CD3D11_RECT(targetSource
.left
, targetSource
.top
, targetSource
.right
, targetSource
.bottom
);
550 // TODO: Use linear filtering if (bScaleByHalf), else use point filtering
552 D3D::stateman
->PushBlendState(efbcopyblendstate
);
553 D3D::stateman
->PushRasterizerState(efbcopyraststate
);
554 D3D::stateman
->PushDepthState(efbcopydepthstate
);
555 D3D::context
->OMSetRenderTargets(1, &tex
->GetRTV(), NULL
);
556 D3D::drawShadedTexQuad(
557 (bFromZBuffer
) ? FBManager
.GetEFBDepthTexture()->GetSRV() : FBManager
.GetEFBColorTexture()->GetSRV(),
559 Renderer::GetFullTargetWidth(),
560 Renderer::GetFullTargetHeight(),
561 (bFromZBuffer
) ? PixelShaderCache::GetDepthMatrixProgram() : PixelShaderCache::GetColorMatrixProgram(), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout());
563 D3D::context
->OMSetRenderTargets(1, &FBManager
.GetEFBColorTexture()->GetRTV(), FBManager
.GetEFBDepthTexture()->GetDSV());
564 D3D::stateman
->PopBlendState();
565 D3D::stateman
->PopDepthState();
566 D3D::stateman
->PopRasterizerState();
567 Renderer::RestoreAPIState();