Load the d3dx11 dll at runtime instead of linking directly against it. Should make...
[dolphin.git] / Source / Plugins / Plugin_VideoDX11 / Src / TextureCache.cpp
blobf21313571d795a271ece8206124f37f1daa2fa59
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/
18 #include <d3dx11.h>
20 #include "Globals.h"
21 #include "Statistics.h"
22 #include "MemoryUtil.h"
23 #include "Hash.h"
25 #include "CommonPaths.h"
26 #include "FileUtil.h"
28 #include "D3DBase.h"
29 #include "D3DTexture.h"
30 #include "D3DUtil.h"
31 #include "FBManager.h"
32 #include "PixelShaderCache.h"
33 #include "PixelShaderManager.h"
34 #include "VertexShaderManager.h"
35 #include "VertexShaderCache.h"
37 #include "Render.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)
64 *ptr = oldpixel;
68 void TextureCache::Init()
70 HRESULT hr;
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);
122 textures.clear();
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++);
136 else
138 ++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;
147 return true;
150 void TextureCache::Shutdown()
152 Invalidate(true);
153 FreeMemoryPages(temp, TEMP_SIZE);
154 temp = NULL;
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);
174 else
176 ++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++;
186 return 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);
200 u64 hash_value;
201 u32 texID = address;
202 u64 texHash;
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);
221 texHash ^= tlutHash;
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());
246 return &entry;
248 else
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;
259 else
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;
289 HRESULT hr;
290 D3D11_SUBRESOURCE_DATA data;
291 data.pSysMem = temp;
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");
301 pTexture->Release();
303 if (TexLevels != 1) D3D::ReplaceRGBATexture2D(entry.texture->GetTex(), temp, width, height, expandedWidth, 0, usage);
305 else
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;
331 ptr += size;
332 mipWidth >>= 1;
333 mipHeight >>= 1;
334 level++;
337 entry.frameCount = frameCount;
338 entry.w = width;
339 entry.h = height;
340 entry.fmt = FullFormat;
342 INCSTAT(stats.numTexturesCreated);
343 SETSTAT(stats.numTexturesAlive, (int)textures.size());
345 D3D::gfxstate->SetShaderResource(stage, entry.texture->GetSRV());
347 return &entry;
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;
371 else
373 // remove it and recreate it as a render target
374 SAFE_RELEASE(iter->second.texture);
375 textures.erase(iter);
379 if (!tex)
381 TCacheEntry entry;
382 entry.isRenderTarget = true;
383 entry.hash = 0;
384 entry.frameCount = frameCount;
385 entry.w = tex_w;
386 entry.h = tex_h;
387 entry.Scaledw = Scaledtex_w;
388 entry.Scaledh = Scaledtex_h;
389 entry.fmt = copyfmt;
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;
394 tex = entry.texture;
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()
401 if (bFromZBuffer)
403 switch(copyfmt)
405 case 0: // Z4
406 case 1: // Z8
407 colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1.0f;
408 cbufid = 12;
409 break;
410 case 3: // Z16 //?
411 colmat[1] = colmat[5] = colmat[9] = colmat[12] = 1.0f;
412 cbufid = 13;
413 case 11: // Z16 (reverse order)
414 colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f;
415 cbufid = 14;
416 break;
417 case 6: // Z24X8
418 colmat[0] = colmat[5] = colmat[10] = 1.0f;
419 cbufid = 15;
420 break;
421 case 9: // Z8M
422 colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f;
423 cbufid = 16;
424 break;
425 case 10: // Z8L
426 colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f;
427 cbufid = 17;
428 break;
429 case 12: // Z16L
430 colmat[2] = colmat[6] = colmat[10] = colmat[13] = 1.0f;
431 cbufid = 18;
432 break;
433 default:
434 ERROR_LOG(VIDEO, "Unknown copy zbuf format: 0x%x", copyfmt);
435 colmat[2] = colmat[5] = colmat[8] = 1.0f;
436 cbufid = 19;
437 break;
440 else if (bIsIntensityFmt)
442 colmat[16] = colmat[17] = colmat[18] = 16.0f/255.0f;
443 switch (copyfmt)
445 case 0: // I4
446 case 1: // I8
447 case 2: // IA4
448 case 3: // IA8
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;
454 if (copyfmt < 2)
456 colmat[19] = 16.0f / 255.0f;
457 colmat[12] = 0.257f; colmat[13] = 0.504f; colmat[14] = 0.098f;
458 cbufid = 0;
460 else// alpha
462 colmat[15] = 1;
463 cbufid = 1;
466 break;
467 default:
468 ERROR_LOG(VIDEO, "Unknown copy intensity format: 0x%x", copyfmt);
469 colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1;
470 break;
473 else
475 switch (copyfmt)
477 case 0: // R4
478 case 8: // R8
479 colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1;
480 cbufid = 2;
481 break;
482 case 2: // RA4
483 case 3: // RA8
484 colmat[0] = colmat[4] = colmat[8] = colmat[15] = 1;
485 cbufid = 3;
486 break;
488 case 7: // A8
489 colmat[3] = colmat[7] = colmat[11] = colmat[15] = 1;
490 cbufid = 4;
491 break;
492 case 9: // G8
493 colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1;
494 cbufid = 5;
495 break;
496 case 10: // B8
497 colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1;
498 cbufid = 6;
499 break;
500 case 11: // RG8
501 colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1;
502 cbufid = 7;
503 break;
504 case 12: // GB8
505 colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1;
506 cbufid = 8;
507 break;
509 case 4: // RGB565
510 colmat[0] = colmat[5] = colmat[10] = 1;
511 colmat[19] = 1; // set alpha to 1
512 cbufid = 9;
513 break;
514 case 5: // RGB5A3
515 case 6: // RGBA8
516 colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1;
517 cbufid = 10;
518 break;
520 default:
521 ERROR_LOG(VIDEO, "Unknown copy color format: 0x%x", copyfmt);
522 colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1;
523 cbufid = 11;
524 break;
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(),
558 &sourcerect,
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();