DX11: Add texture dumping and hires texture loading support.
[dolphin.git] / Source / Plugins / Plugin_VideoDX11 / Src / TextureCache.cpp
blob448d7a6975ff6a437c9543dba7762ad81035973e
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 "FramebufferManager.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 (2048*2048*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::Shutdown()
128 Invalidate(true);
129 FreeMemoryPages(temp, TEMP_SIZE);
130 temp = NULL;
132 SAFE_RELEASE(efbcopyblendstate);
133 SAFE_RELEASE(efbcopyraststate);
134 SAFE_RELEASE(efbcopydepthstate);
136 for (unsigned int k = 0; k < 20;k++)
137 SAFE_RELEASE(efbcopycbuf[k]);
140 void TextureCache::Cleanup()
142 TexCache::iterator iter = textures.begin();
143 while (iter != textures.end())
145 if (frameCount > TEXTURE_KILL_THRESHOLD + iter->second.frameCount)
147 iter->second.Destroy(false);
148 iter = textures.erase(iter);
150 else
152 ++iter;
157 void TextureCache::InvalidateRange(u32 start_address, u32 size)
159 TexCache::iterator iter = textures.begin();
160 while (iter != textures.end())
162 if (iter->second.IntersectsMemoryRange(start_address, size))
164 iter->second.Destroy(false);
165 textures.erase(iter++);
167 else
169 ++iter;
174 bool TextureCache::TCacheEntry::IntersectsMemoryRange(u32 range_address, u32 range_size)
176 if (addr + size_in_bytes < range_address) return false;
177 if (addr >= range_address + range_size) return false;
178 return true;
182 // returns the exponent of the smallest power of two which is greater than val
183 unsigned int GetPow2(unsigned int val)
185 unsigned int ret = 0;
186 for (;val;val>>=1) ret++;
187 return ret;
190 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)
192 // notes (about "UNsafe texture cache"):
193 // Have to be removed soon.
194 // But we keep it until the "safe" way became rock solid
195 // pros: it has an unique ID held by the texture data itself (@address) once cached.
196 // cons: it writes this unique ID in the gc RAM <- very dangerous (break MP1) and ugly
198 // notes (about "safe texture cache"):
199 // Metroids text issue (character table):
200 // Same addr, same GX_TF_C4 texture data but different TLUT (hence different outputs).
201 // That's why we have to hash the TLUT too for TLUT tex_format dependent textures (ie. GX_TF_C4, GX_TF_C8, GX_TF_C14X2).
202 // And since the address and tex data don't change, the key index in the cacheEntry map can't be the address but
203 // have to be a real unique ID.
204 // DONE but not satifiying yet -> may break copyEFBToTexture sometimes.
206 // Pokemon Colosseum text issue (plain text):
207 // Use a GX_TF_I4 512x512 text-flush-texture at a const address.
208 // The problem here was just the sparse hash on the texture. This texture is partly overwrited (what is needed only)
209 // so lot's of remaning old text. Thin white chars on black bg too.
211 // TODO: - clean this up when ready to kill old "unsafe texture cache"
212 // - fix the key index situation with CopyRenderTargetToTexture.
213 // Could happen only for GX_TF_C4, GX_TF_C8 and GX_TF_C14X2 fmt.
214 // Wonder if we can't use tex width&height to know if EFB might be copied to it...
215 // raw idea: TOCHECK if addresses are aligned we have few bits left...
217 if (address == 0)
218 return NULL;
220 u8 *ptr = g_VideoInitialize.pGetMemoryPointer(address);
221 unsigned int bsw = TexDecoder_GetBlockWidthInTexels(tex_format) - 1; // TexelSizeInNibbles(format)*width*height/16;
222 unsigned int bsh = TexDecoder_GetBlockHeightInTexels(tex_format) - 1; // TexelSizeInNibbles(format)*width*height/16;
223 unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(tex_format);
224 unsigned int expandedWidth = (width + bsw) & (~bsw);
225 unsigned int expandedHeight = (height + bsh) & (~bsh);
227 u64 hash_value = 0;
228 u32 texID = address;
229 u64 texHash = 0;
230 u32 FullFormat = tex_format;
231 if ((tex_format == GX_TF_C4) || (tex_format == GX_TF_C8) || (tex_format == GX_TF_C14X2))
232 FullFormat = (tex_format | (tlutfmt << 16));
234 // hires texture loading and texture dumping require accurate hashes
235 if (g_ActiveConfig.bSafeTextureCache || g_ActiveConfig.bHiresTextures || g_ActiveConfig.bDumpTextures)
237 texHash = GetHash64(ptr,TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, tex_format),g_ActiveConfig.iSafeTextureCache_ColorSamples);
238 if ((tex_format == GX_TF_C4) || (tex_format == GX_TF_C8) || (tex_format == GX_TF_C14X2))
240 // WARNING! texID != address now => may break CopyRenderTargetToTexture (cf. TODO up)
241 // tlut size can be up to 32768B (GX_TF_C14X2) but Safer == Slower.
242 // This trick (to change the texID depending on the TLUT addr) is a trick to get around
243 // an issue with metroid prime's fonts, where it has multiple sets of fonts on top of
244 // each other stored in a single texture, and uses the palette to make different characters
245 // visible or invisible. Thus, unless we want to recreate the textures for every drawn character,
246 // we must make sure that texture with different tluts get different IDs.
247 u64 tlutHash = GetHash64(&texMem[tlutaddr], TexDecoder_GetPaletteSize(tex_format),g_ActiveConfig.iSafeTextureCache_ColorSamples);
248 texHash ^= tlutHash;
249 if (g_ActiveConfig.bSafeTextureCache)
251 texID = texID ^ ((u32)(tlutHash & 0xFFFFFFFF)) ^ ((u32)((tlutHash >> 32) & 0xFFFFFFFF));
254 if (g_ActiveConfig.bSafeTextureCache)
255 hash_value = texHash;
258 bool skip_texture_create = false;
259 TexCache::iterator iter = textures.find(texID);
261 if (iter != textures.end())
263 TCacheEntry &entry = iter->second;
265 if (!g_ActiveConfig.bSafeTextureCache)
266 hash_value = ((u32*)ptr)[0];
268 // TODO: Is the (entry.MipLevels == maxlevel) check needed?
269 if (entry.isRenderTarget || ((address == entry.addr) && (hash_value == entry.hash) && FullFormat == entry.fmt && entry.MipLevels == maxlevel))
271 entry.frameCount = frameCount;
272 D3D::gfxstate->SetShaderResource(stage, entry.texture->GetSRV());
273 return &entry;
275 else
277 // Let's reload the new texture data into the same texture,
278 // instead of destroying it and having to create a new one.
279 // Might speed up movie playback very, very slightly.
281 // TODO: Is the (entry.MipLevels < maxlevel) check needed?
282 if (width == entry.w && height==entry.h && FullFormat == entry.fmt && entry.MipLevels < maxlevel)
284 skip_texture_create = true;
286 else
288 entry.Destroy(false);
289 textures.erase(iter);
294 // Make an entry in the table
295 TCacheEntry& entry = textures[texID];
296 entry.Realw = width;
297 entry.Realh = height;
298 PC_TexFormat pcfmt = PC_TEX_FMT_NONE;
300 pcfmt = TexDecoder_Decode(temp, ptr, expandedWidth, expandedHeight, tex_format, tlutaddr, tlutfmt, true);
301 if (g_ActiveConfig.bHiresTextures)
303 // Load Custom textures
304 char texPathTemp[MAX_PATH];
305 int newWidth = width;
306 int newHeight = height;
308 sprintf(texPathTemp, "%s_%08x_%i", globals->unique_id, texHash, tex_format);
309 pcfmt = HiresTextures::GetHiresTex(texPathTemp, &newWidth, &newHeight, GX_TF_RGBA8, temp);
310 if (pcfmt != PC_TEX_FMT_NONE)
312 expandedWidth = width = newWidth;
313 expandedHeight = height = newHeight;
317 if (pcfmt == PC_TEX_FMT_NONE)
318 pcfmt = TexDecoder_Decode(temp, ptr, expandedWidth, expandedHeight, tex_format, tlutaddr, tlutfmt, true);
320 entry.oldpixel = ((u32*)ptr)[0];
321 if (g_ActiveConfig.bSafeTextureCache) entry.hash = hash_value;
322 else entry.hash = ((u32*)ptr)[0] = (u32)(((double)rand() / RAND_MAX) * 0xFFFFFFFF);
324 bool isPow2 = !((width & (width - 1)) || (height & (height - 1)));
325 unsigned int TexLevels = (isPow2 && UseNativeMips && maxlevel) ? GetPow2(max(width, height)) : ((isPow2)? 0 : 1);
326 if (TexLevels > (maxlevel + 1) && maxlevel)
327 TexLevels = maxlevel + 1;
329 D3D11_USAGE usage = (TexLevels == 1) ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
331 if (!skip_texture_create)
333 // TODO: A little more verbosity in the debug names would be quite helpful..
334 D3D11_CPU_ACCESS_FLAG cpu_access = (TexLevels == 1) ? D3D11_CPU_ACCESS_WRITE : (D3D11_CPU_ACCESS_FLAG)0;
335 ID3D11Texture2D* pTexture = NULL;
336 HRESULT hr;
337 D3D11_SUBRESOURCE_DATA data;
338 data.pSysMem = temp;
339 data.SysMemPitch = 4*expandedWidth;
341 D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, width, height, 1, TexLevels, D3D11_BIND_SHADER_RESOURCE, usage, cpu_access);
342 hr = D3D::device->CreateTexture2D(&texdesc, (TexLevels==1)?&data:NULL, &pTexture);
343 CHECK(hr==S_OK, "Create texture of the TextureCache");
344 entry.texture = new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE);
345 CHECK(entry.texture!=NULL, "Create texture of the TextureCache");
346 D3D::SetDebugObjectName((ID3D11DeviceChild*)entry.texture->GetTex(), "a texture of the TextureCache");
347 D3D::SetDebugObjectName((ID3D11DeviceChild*)entry.texture->GetSRV(), "shader resource view of a texture of the TextureCache");
348 SAFE_RELEASE(pTexture);
350 // if (TexLevels == 1), we already loaded the data into our texture upon creation
351 if (TexLevels != 1) D3D::ReplaceRGBATexture2D(entry.texture->GetTex(), temp, width, height, expandedWidth, 0, usage);
353 else
355 D3D::ReplaceRGBATexture2D(entry.texture->GetTex(), temp, width, height, expandedWidth, 0, usage);
358 entry.addr = address;
359 entry.size_in_bytes = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, tex_format);
360 entry.isRenderTarget = false;
361 entry.isNonPow2 = false;
362 entry.MipLevels = maxlevel;
364 if (TexLevels == 0) PD3DX11FilterTexture(D3D::context, entry.texture->GetTex(), 0, D3DX11_DEFAULT);
365 else if (TexLevels > 1 && pcfmt != PC_TEX_FMT_NONE)
367 unsigned int level = 1;
368 unsigned int mipWidth = (width + 1) >> 1;
369 unsigned int mipHeight = (height + 1) >> 1;
370 ptr += entry.size_in_bytes;
371 while ((mipHeight || mipWidth) && (level < TexLevels))
373 unsigned int currentWidth = (mipWidth > 0) ? mipWidth : 1;
374 unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1;
375 expandedWidth = (currentWidth + bsw) & (~bsw);
376 expandedHeight = (currentHeight + bsh) & (~bsh);
377 TexDecoder_Decode(temp, ptr, expandedWidth, expandedHeight, tex_format, tlutaddr, tlutfmt, true);
378 D3D::ReplaceRGBATexture2D(entry.texture->GetTex(), temp, currentWidth, currentHeight, expandedWidth, level, usage);
379 u32 size = (max(mipWidth, bsw) * max(mipHeight, bsh) * bsdepth) >> 1;
380 ptr += size;
381 mipWidth >>= 1;
382 mipHeight >>= 1;
383 level++;
386 entry.frameCount = frameCount;
387 entry.w = width;
388 entry.h = height;
389 entry.Scaledw = width;
390 entry.Scaledh = height;
391 entry.fmt = FullFormat;
393 // dump texture to file
394 if (g_ActiveConfig.bDumpTextures)
396 char szTemp[MAX_PATH];
397 char szDir[MAX_PATH];
399 // make sure that the directory exists
400 sprintf(szDir, "%s%s", File::GetUserPath(D_DUMPTEXTURES_IDX), globals->unique_id);
401 if (!File::Exists(szDir) || !File::IsDirectory(szDir))
402 File::CreateDir(szDir);
404 sprintf(szTemp, "%s/%s_%08x_%i.png", szDir, globals->unique_id, texHash, tex_format);
405 if (!File::Exists(szTemp))
406 if(FAILED(PD3DX11SaveTextureToFileA(D3D::context, entry.texture->GetTex(), D3DX11_IFF_PNG, szTemp))) PanicAlert("!!!");
409 INCSTAT(stats.numTexturesCreated);
410 SETSTAT(stats.numTexturesAlive, textures.size());
412 D3D::gfxstate->SetShaderResource(stage, entry.texture->GetSRV());
414 return &entry;
417 void TextureCache::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, unsigned int bScaleByHalf, const EFBRectangle &source_rect)
419 int efb_w = source_rect.GetWidth();
420 int efb_h = source_rect.GetHeight();
422 int tex_w = (abs(source_rect.GetWidth()) >> bScaleByHalf);
423 int tex_h = (abs(source_rect.GetHeight()) >> bScaleByHalf);
425 int Scaledtex_w = (g_ActiveConfig.bCopyEFBScaled) ? ((int)(Renderer::GetTargetScaleX() * tex_w)) : tex_w;
426 int Scaledtex_h = (g_ActiveConfig.bCopyEFBScaled) ? ((int)(Renderer::GetTargetScaleY() * tex_h)) : tex_h;
428 TexCache::iterator iter;
429 D3DTexture2D* tex = NULL;
430 iter = textures.find(address);
431 if (iter != textures.end())
433 if (iter->second.isRenderTarget && iter->second.Scaledw == Scaledtex_w && iter->second.Scaledh == Scaledtex_h)
435 tex = iter->second.texture;
436 iter->second.frameCount = frameCount;
438 else
440 // Remove it and recreate it as a render target
441 SAFE_RELEASE(iter->second.texture);
442 textures.erase(iter);
446 if (!tex)
448 TCacheEntry entry;
449 entry.isRenderTarget = true;
450 entry.hash = 0;
451 entry.frameCount = frameCount;
452 entry.w = entry.Realw = tex_w;
453 entry.h = entry.Realh = tex_h;
454 entry.Scaledw = Scaledtex_w;
455 entry.Scaledh = Scaledtex_h;
456 entry.fmt = copyfmt;
457 entry.isNonPow2 = true;
458 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);
459 if (entry.texture == NULL) PanicAlert("CopyRenderTargetToTexture failed to create entry.texture at %s %d\n", __FILE__, __LINE__);
460 textures[address] = entry;
461 tex = entry.texture;
464 float colmat[20]= {0.0f}; // last four floats for fConstAdd
465 unsigned int cbufid = (unsigned int)-1;
467 // TODO: Move this to TextureCache::Init()
468 if (bFromZBuffer)
470 switch(copyfmt)
472 case 0: // Z4
473 case 1: // Z8
474 colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1.0f;
475 cbufid = 12;
476 break;
477 case 3: // Z16 //?
478 colmat[1] = colmat[5] = colmat[9] = colmat[12] = 1.0f;
479 cbufid = 13;
480 break;
481 case 11: // Z16 (reverse order)
482 colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f;
483 cbufid = 14;
484 break;
485 case 6: // Z24X8
486 colmat[0] = colmat[5] = colmat[10] = 1.0f;
487 cbufid = 15;
488 break;
489 case 9: // Z8M
490 colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f;
491 cbufid = 16;
492 break;
493 case 10: // Z8L
494 colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f;
495 cbufid = 17;
496 break;
497 case 12: // Z16L
498 colmat[2] = colmat[6] = colmat[10] = colmat[13] = 1.0f;
499 cbufid = 18;
500 break;
501 default:
502 ERROR_LOG(VIDEO, "Unknown copy zbuf format: 0x%x", copyfmt);
503 colmat[2] = colmat[5] = colmat[8] = 1.0f;
504 cbufid = 19;
505 break;
508 else if (bIsIntensityFmt)
510 colmat[16] = colmat[17] = colmat[18] = 16.0f/255.0f;
511 switch (copyfmt)
513 case 0: // I4
514 case 1: // I8
515 case 2: // IA4
516 case 3: // IA8
517 // TODO - verify these coefficients
518 colmat[0] = 0.257f; colmat[1] = 0.504f; colmat[2] = 0.098f;
519 colmat[4] = 0.257f; colmat[5] = 0.504f; colmat[6] = 0.098f;
520 colmat[8] = 0.257f; colmat[9] = 0.504f; colmat[10] = 0.098f;
522 if (copyfmt < 2)
524 colmat[19] = 16.0f / 255.0f;
525 colmat[12] = 0.257f; colmat[13] = 0.504f; colmat[14] = 0.098f;
526 cbufid = 0;
528 else// alpha
530 colmat[15] = 1;
531 cbufid = 1;
534 break;
535 default:
536 ERROR_LOG(VIDEO, "Unknown copy intensity format: 0x%x", copyfmt);
537 colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1;
538 break;
541 else
543 switch (copyfmt)
545 case 0: // R4
546 case 8: // R8
547 colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1;
548 cbufid = 2;
549 break;
550 case 2: // RA4
551 case 3: // RA8
552 colmat[0] = colmat[4] = colmat[8] = colmat[15] = 1;
553 cbufid = 3;
554 break;
556 case 7: // A8
557 colmat[3] = colmat[7] = colmat[11] = colmat[15] = 1;
558 cbufid = 4;
559 break;
560 case 9: // G8
561 colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1;
562 cbufid = 5;
563 break;
564 case 10: // B8
565 colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1;
566 cbufid = 6;
567 break;
568 case 11: // RG8
569 colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1;
570 cbufid = 7;
571 break;
572 case 12: // GB8
573 colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1;
574 cbufid = 8;
575 break;
577 case 4: // RGB565
578 colmat[0] = colmat[5] = colmat[10] = 1;
579 colmat[19] = 1; // set alpha to 1
580 cbufid = 9;
581 break;
582 case 5: // RGB5A3
583 case 6: // RGBA8
584 colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1;
585 cbufid = 10;
586 break;
588 default:
589 ERROR_LOG(VIDEO, "Unknown copy color format: 0x%x", copyfmt);
590 colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1;
591 cbufid = 11;
592 break;
596 Renderer::ResetAPIState(); // reset any game specific settings
598 // stretch picture with increased internal resolution
599 D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)Scaledtex_w, (float)Scaledtex_h);
600 D3D::context->RSSetViewports(1, &vp);
601 D3D11_RECT destrect = CD3D11_RECT(0, 0, Scaledtex_w, Scaledtex_h);
603 // set transformation
604 if (efbcopycbuf[cbufid] == NULL)
606 D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(20*sizeof(float), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT);
607 D3D11_SUBRESOURCE_DATA data;
608 data.pSysMem = colmat;
609 HRESULT hr = D3D::device->CreateBuffer(&cbdesc, &data, &efbcopycbuf[cbufid]);
610 CHECK(hr==S_OK, "Create efb copy constant buffer %d", cbufid);
611 D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopycbuf[cbufid], "a constant buffer used in TextureCache::CopyRenderTargetToTexture");
613 D3D::context->PSSetConstantBuffers(0, 1, &efbcopycbuf[cbufid]);
615 TargetRectangle targetSource = Renderer::ConvertEFBRectangle(source_rect);
616 D3D11_RECT sourcerect = CD3D11_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom);
618 // Use linear filtering if (bScaleByHalf), use point filtering otherwise
619 if (bScaleByHalf) D3D::SetLinearCopySampler();
620 else D3D::SetPointCopySampler();
622 D3D::stateman->PushBlendState(efbcopyblendstate);
623 D3D::stateman->PushRasterizerState(efbcopyraststate);
624 D3D::stateman->PushDepthState(efbcopydepthstate);
625 D3D::context->OMSetRenderTargets(1, &tex->GetRTV(), NULL);
626 D3D::drawShadedTexQuad(
627 (bFromZBuffer) ? g_framebufferManager.GetEFBDepthTexture()->GetSRV() : g_framebufferManager.GetEFBColorTexture()->GetSRV(),
628 &sourcerect,
629 Renderer::GetFullTargetWidth(),
630 Renderer::GetFullTargetHeight(),
631 (bFromZBuffer) ? PixelShaderCache::GetDepthMatrixProgram() : PixelShaderCache::GetColorMatrixProgram(), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout());
633 D3D::context->OMSetRenderTargets(1, &g_framebufferManager.GetEFBColorTexture()->GetRTV(), g_framebufferManager.GetEFBDepthTexture()->GetDSV());
634 D3D::stateman->PopBlendState();
635 D3D::stateman->PopDepthState();
636 D3D::stateman->PopRasterizerState();
637 Renderer::RestoreAPIState();