1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
22 #include "CommonPaths.h"
23 #include "StringUtil.h"
26 #define _interlockedbittestandset workaround_ms_header_bug_platform_sdk6_set
27 #define _interlockedbittestandreset workaround_ms_header_bug_platform_sdk6_reset
28 #define _interlockedbittestandset64 workaround_ms_header_bug_platform_sdk6_set64
29 #define _interlockedbittestandreset64 workaround_ms_header_bug_platform_sdk6_reset64
31 #undef _interlockedbittestandset
32 #undef _interlockedbittestandreset
33 #undef _interlockedbittestandset64
34 #undef _interlockedbittestandreset64
37 #include "VideoConfig.h"
39 #include "Statistics.h"
41 #include "ImageWrite.h"
45 #include "MemoryUtil.h"
46 #include "BPStructs.h"
47 #include "TextureDecoder.h"
48 #include "TextureMngr.h"
49 #include "PixelShaderCache.h"
50 #include "PixelShaderManager.h"
51 #include "VertexShaderManager.h"
52 #include "FramebufferManager.h"
54 #include "HiresTextures.h"
56 u8
*TextureMngr::temp
= NULL
;
57 TextureMngr::TexCache
TextureMngr::textures
;
59 extern int frameCount
;
60 static u32 s_TempFramebuffer
= 0;
62 #define TEMP_SIZE (1024*1024*4)
63 #define TEXTURE_KILL_THRESHOLD 200
65 static const GLint c_MinLinearFilter
[8] = {
67 GL_NEAREST_MIPMAP_NEAREST
,
68 GL_NEAREST_MIPMAP_LINEAR
,
71 GL_LINEAR_MIPMAP_NEAREST
,
72 GL_LINEAR_MIPMAP_LINEAR
,
76 static const GLint c_WrapSettings
[4] = {
83 bool SaveTexture(const char* filename
, u32 textarget
, u32 tex
, int width
, int height
)
85 std::vector
<u32
> data(width
* height
);
86 glBindTexture(textarget
, tex
);
87 glGetTexImage(textarget
, 0, GL_BGRA
, GL_UNSIGNED_BYTE
, &data
[0]);
88 GLenum err
= GL_REPORT_ERROR();
89 if (err
!= GL_NO_ERROR
)
91 PanicAlert("Can't save texture, GL Error: %s", gluErrorString(err
));
95 return SaveTGA(filename
, width
, height
, &data
[0]);
98 bool TextureMngr::TCacheEntry::IntersectsMemoryRange(u32 range_address
, u32 range_size
)
100 if (addr
+ size_in_bytes
< range_address
)
102 if (addr
>= range_address
+ range_size
)
107 void TextureMngr::TCacheEntry::SetTextureParameters(TexMode0
&newmode
,TexMode1
&newmode1
)
114 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB
, GL_TEXTURE_MAG_FILTER
,
115 (newmode
.mag_filter
|| g_ActiveConfig
.bForceFiltering
) ? GL_LINEAR
: GL_NEAREST
);
116 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB
, GL_TEXTURE_MIN_FILTER
,
117 (g_ActiveConfig
.bForceFiltering
|| newmode
.min_filter
>= 4) ? GL_LINEAR
: GL_NEAREST
);
119 if (newmode
.wrap_s
== 2 || newmode
.wrap_t
== 2)
120 DEBUG_LOG(VIDEO
, "cannot support mirrorred repeat mode");
122 if (newmode
.wrap_s
== 1 || newmode
.wrap_t
== 1)
123 DEBUG_LOG(VIDEO
, "cannot support repeat mode");
127 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
,
128 (newmode
.mag_filter
|| g_Config
.bForceFiltering
) ? GL_LINEAR
: GL_NEAREST
);
132 if (g_ActiveConfig
.bForceFiltering
&& newmode
.min_filter
< 4)
133 mode
.min_filter
+= 4; // take equivalent forced linear
134 int filt
= newmode
.min_filter
;
135 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, c_MinLinearFilter
[filt
& (((newmode1
.max_lod
>> 4) > 0)?7:4)]);
136 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_BASE_LEVEL
, newmode1
.min_lod
>> 4);
137 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAX_LEVEL
, newmode1
.max_lod
>> 4);
138 //glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, (newmode.lod_bias/2.0f));
142 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
,
143 (g_ActiveConfig
.bForceFiltering
|| newmode
.min_filter
>= 4) ? GL_LINEAR
: GL_NEAREST
);
144 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, c_WrapSettings
[newmode
.wrap_s
]);
145 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, c_WrapSettings
[newmode
.wrap_t
]);
148 if (g_Config
.iMaxAnisotropy
>= 1)
149 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MAX_ANISOTROPY_EXT
, (float)(1 << g_ActiveConfig
.iMaxAnisotropy
));
152 void TextureMngr::TCacheEntry::Destroy(bool shutdown
)
156 glDeleteTextures(1, &texture
);
157 if (!isRenderTarget
&& !shutdown
&& !g_ActiveConfig
.bSafeTextureCache
) {
158 u32
*ptr
= (u32
*)g_VideoInitialize
.pGetMemoryPointer(addr
);
159 if (ptr
&& *ptr
== hash
)
165 void TextureMngr::Init()
167 temp
= (u8
*)AllocateMemoryPages(TEMP_SIZE
);
168 TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig
.bTexFmtOverlayEnable
, g_ActiveConfig
.bTexFmtOverlayCenter
);
169 HiresTextures::Init(globals
->unique_id
);
172 void TextureMngr::Invalidate(bool shutdown
)
174 for (TexCache::iterator iter
= textures
.begin(); iter
!= textures
.end(); ++iter
)
175 iter
->second
.Destroy(shutdown
);
177 HiresTextures::Shutdown();
180 void TextureMngr::Shutdown()
184 if (s_TempFramebuffer
) {
185 glDeleteFramebuffersEXT(1, (GLuint
*)&s_TempFramebuffer
);
186 s_TempFramebuffer
= 0;
189 FreeMemoryPages(temp
, TEMP_SIZE
);
193 void TextureMngr::ProgressiveCleanup()
195 TexCache::iterator iter
= textures
.begin();
196 while (iter
!= textures
.end())
198 if (frameCount
> TEXTURE_KILL_THRESHOLD
+ iter
->second
.frameCount
)
200 if (!iter
->second
.isRenderTarget
) {
201 iter
->second
.Destroy(false);
202 ERASE_THROUGH_ITERATOR(textures
, iter
);
205 iter
->second
.Destroy(false);
206 ERASE_THROUGH_ITERATOR(textures
, iter
);
214 void TextureMngr::InvalidateRange(u32 start_address
, u32 size
)
216 TexCache::iterator iter
= textures
.begin();
217 while (iter
!= textures
.end())
219 if (iter
->second
.IntersectsMemoryRange(start_address
, size
))
221 iter
->second
.Destroy(false);
222 ERASE_THROUGH_ITERATOR(textures
, iter
);
230 TextureMngr::TCacheEntry
* TextureMngr::Load(int texstage
, u32 address
, int width
, int height
, u32 tex_format
, int tlutaddr
, int tlutfmt
)
232 // notes (about "UNsafe texture cache"):
233 // Have to be removed soon.
234 // But we keep it until the "safe" way became rock solid
235 // pros: it has an unique ID held by the texture data itself (@address) once cached.
236 // cons: it writes this unique ID in the gc RAM <- very dangerous (break MP1) and ugly
238 // notes (about "safe texture cache"):
239 // Metroids text issue (character table):
240 // Same addr, same GX_TF_C4 texture data but different TLUT (hence different outputs).
241 // 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).
242 // And since the address and tex data don't change, the key index in the cacheEntry map can't be the address but
243 // have to be a real unique ID.
244 // DONE but not satifiying yet -> may break copyEFBToTexture sometimes.
246 // Pokemon Colosseum text issue (plain text):
247 // Use a GX_TF_I4 512x512 text-flush-texture at a const address.
248 // The problem here was just the sparse hash on the texture. This texture is partly overwrited (what is needed only)
249 // so lot's of remaning old text. Thin white chars on black bg too.
251 // TODO: - clean this up when ready to kill old "unsafe texture cache"
252 // - fix the key index situation with CopyRenderTargetToTexture.
253 // Could happen only for GX_TF_C4, GX_TF_C8 and GX_TF_C14X2 fmt.
254 // Wonder if we can't use tex width&height to know if EFB might be copied to it...
255 // raw idea: TOCHECK if addresses are aligned we have few bits left...
260 TexMode0
&tm0
= bpmem
.tex
[texstage
>> 2].texMode0
[texstage
& 3];
261 TexMode1
&tm1
= bpmem
.tex
[texstage
>> 2].texMode1
[texstage
& 3];
263 bool UseNativeMips
= (tm0
.min_filter
& 3) && (tm0
.min_filter
!= 8);
264 int maxlevel
= ((tm1
.max_lod
>> 4));
266 u8
*ptr
= g_VideoInitialize
.pGetMemoryPointer(address
);
267 int bsw
= TexDecoder_GetBlockWidthInTexels(tex_format
) - 1;
268 int bsh
= TexDecoder_GetBlockHeightInTexels(tex_format
) - 1;
269 int bsdepth
= TexDecoder_GetTexelSizeInNibbles(tex_format
);
270 int expandedWidth
= (width
+ bsw
) & (~bsw
);
271 int expandedHeight
= (height
+ bsh
) & (~bsh
);
276 u32 FullFormat
= tex_format
;
277 if ((tex_format
== GX_TF_C4
) || (tex_format
== GX_TF_C8
) || (tex_format
== GX_TF_C14X2
))
278 FullFormat
= (tex_format
| (tlutfmt
<< 16));
279 if (g_ActiveConfig
.bSafeTextureCache
|| g_ActiveConfig
.bHiresTextures
|| g_ActiveConfig
.bDumpTextures
)
281 texHash
= TexDecoder_GetHash64(ptr
,TexDecoder_GetTextureSizeInBytes(expandedWidth
, expandedHeight
, tex_format
),g_ActiveConfig
.iSafeTextureCache_ColorSamples
);
282 if ((tex_format
== GX_TF_C4
) || (tex_format
== GX_TF_C8
) || (tex_format
== GX_TF_C14X2
))
284 // WARNING! texID != address now => may break CopyRenderTargetToTexture (cf. TODO up)
285 // tlut size can be up to 32768B (GX_TF_C14X2) but Safer == Slower.
286 // This trick (to change the texID depending on the TLUT addr) is a trick to get around
287 // an issue with metroid prime's fonts, where it has multiple sets of fonts on top of
288 // each other stored in a single texture, and uses the palette to make different characters
289 // visible or invisible. Thus, unless we want to recreate the textures for every drawn character,
290 // we must make sure that texture with different tluts get different IDs.
291 u64 tlutHash
= TexDecoder_GetHash64(&texMem
[tlutaddr
], TexDecoder_GetPaletteSize(tex_format
),g_ActiveConfig
.iSafeTextureCache_ColorSamples
);
293 if (g_ActiveConfig
.bSafeTextureCache
)
295 texID
= texID
^ ((u32
)(tlutHash
& 0xFFFFFFFF)) ^ ((u32
)((tlutHash
>> 32) & 0xFFFFFFFF));
298 if (g_ActiveConfig
.bSafeTextureCache
)
299 hash_value
= texHash
;
302 bool skip_texture_create
= false;
303 TexCache::iterator iter
= textures
.find(texID
);
305 if (iter
!= textures
.end())
307 TCacheEntry
&entry
= iter
->second
;
309 if (!g_ActiveConfig
.bSafeTextureCache
)
310 hash_value
= ((u32
*)ptr
)[0];
312 if (entry
.isRenderTarget
|| ((address
== entry
.addr
) && (hash_value
== entry
.hash
) && (int) FullFormat
== entry
.fmt
))
314 entry
.frameCount
= frameCount
;
315 glEnable(entry
.isRectangle
? GL_TEXTURE_RECTANGLE_ARB
: GL_TEXTURE_2D
);
316 // entry.isRectangle ? TextureMngr::EnableTex2D(texstage) : TextureMngr::EnableTexRECT(texstage);
317 glBindTexture(entry
.isRectangle
? GL_TEXTURE_RECTANGLE_ARB
: GL_TEXTURE_2D
, entry
.texture
);
319 if (entry
.mode
.hex
!= tm0
.hex
|| entry
.mode1
.hex
!= tm1
.hex
)
320 entry
.SetTextureParameters(tm0
,tm1
);
321 //DebugLog("%cC addr: %08x | fmt: %i | e.hash: %08x | w:%04i h:%04i", g_ActiveConfig.bSafeTextureCache ? 'S' : 'U'
322 // , address, tex_format, entry.hash, width, height);
327 // Let's reload the new texture data into the same texture,
328 // instead of destroying it and having to create a new one.
329 // Might speed up movie playback very, very slightly.
330 if (width
== entry
.w
&& height
== entry
.h
&& (int) FullFormat
== entry
.fmt
)
332 glBindTexture(entry
.isRectangle
? GL_TEXTURE_RECTANGLE_ARB
: GL_TEXTURE_2D
, entry
.texture
);
334 if (entry
.mode
.hex
!= tm0
.hex
|| entry
.mode1
.hex
!= tm1
.hex
)
335 entry
.SetTextureParameters(tm0
,tm1
);
336 skip_texture_create
= true;
340 entry
.Destroy(false);
341 textures
.erase(iter
);
346 //Make an entry in the table
347 TCacheEntry
& entry
= textures
[texID
];
348 PC_TexFormat dfmt
= PC_TEX_FMT_NONE
;
350 if (g_ActiveConfig
.bHiresTextures
)
352 //Load Custom textures
353 char texPathTemp
[MAX_PATH
];
354 int oldWidth
= width
;
355 int oldHeight
= height
;
357 sprintf(texPathTemp
, "%s_%08x_%i", globals
->unique_id
, (unsigned int) texHash
, tex_format
);
358 dfmt
= HiresTextures::GetHiresTex(texPathTemp
, &width
, &height
, tex_format
, temp
);
360 if (dfmt
!= PC_TEX_FMT_NONE
)
362 expandedWidth
= width
;
363 expandedHeight
= height
;
364 entry
.scaleX
= (float) width
/ oldWidth
;
365 entry
.scaleY
= (float) height
/ oldHeight
;
369 if (dfmt
== PC_TEX_FMT_NONE
)
370 dfmt
= TexDecoder_Decode(temp
, ptr
, expandedWidth
, expandedHeight
, tex_format
, tlutaddr
, tlutfmt
);
372 entry
.oldpixel
= ((u32
*)ptr
)[0];
374 if (g_ActiveConfig
.bSafeTextureCache
)
375 entry
.hash
= hash_value
;
378 entry
.hash
= (u32
)(((double)rand() / RAND_MAX
) * 0xFFFFFFFF);
379 ((u32
*)ptr
)[0] = entry
.hash
;
382 entry
.addr
= address
;
383 entry
.size_in_bytes
= TexDecoder_GetTextureSizeInBytes(expandedWidth
, expandedHeight
, tex_format
);
384 entry
.isRenderTarget
= false;
386 // For static textures, we use NPOT.
387 entry
.isRectangle
= false;
388 // old code: entry.isRectangle = ((width & (width - 1)) || (height & (height - 1)));
390 GLenum target
= entry
.isRectangle
? GL_TEXTURE_RECTANGLE_ARB
: GL_TEXTURE_2D
;
391 if (!skip_texture_create
) {
392 glGenTextures(1, (GLuint
*)&entry
.texture
);
393 glBindTexture(target
, entry
.texture
);
396 bool isPow2
= !((width
& (width
- 1)) || (height
& (height
- 1)));
397 int TexLevels
= (width
> height
)?width
:height
;
398 TexLevels
= (isPow2
&& UseNativeMips
&& (maxlevel
> 0)) ? (int)(log((double)TexLevels
)/log((double)2)) + 1 : 1;
399 if(TexLevels
> maxlevel
&& maxlevel
> 0)
400 TexLevels
= maxlevel
;
404 entry
.bHaveMipMaps
= UseNativeMips
;
405 if (dfmt
!= PC_TEX_FMT_DXT1
)
410 case PC_TEX_FMT_NONE
:
411 PanicAlert("Invalid PC texture format %i", dfmt
);
412 case PC_TEX_FMT_BGRA32
:
415 gl_type
= GL_UNSIGNED_BYTE
;
417 case PC_TEX_FMT_RGBA32
:
420 gl_type
= GL_UNSIGNED_BYTE
;
422 case PC_TEX_FMT_I4_AS_I8
:
423 gl_format
= GL_LUMINANCE
;
424 gl_iformat
= GL_INTENSITY4
;
425 gl_type
= GL_UNSIGNED_BYTE
;
427 case PC_TEX_FMT_IA4_AS_IA8
:
428 gl_format
= GL_LUMINANCE_ALPHA
;
429 gl_iformat
= GL_LUMINANCE4_ALPHA4
;
430 gl_type
= GL_UNSIGNED_BYTE
;
433 gl_format
= GL_LUMINANCE
;
434 gl_iformat
= GL_INTENSITY8
;
435 gl_type
= GL_UNSIGNED_BYTE
;
438 gl_format
= GL_LUMINANCE_ALPHA
;
439 gl_iformat
= GL_LUMINANCE8_ALPHA8
;
440 gl_type
= GL_UNSIGNED_BYTE
;
442 case PC_TEX_FMT_RGB565
:
445 gl_type
= GL_UNSIGNED_SHORT_5_6_5
;
448 if (expandedWidth
!= width
)
449 glPixelStorei(GL_UNPACK_ROW_LENGTH
, expandedWidth
);
450 //generate mipmaps even if we use native mips to suport textures with less levels
451 bool GenerateMipmaps
= isPow2
&& UseNativeMips
&& (maxlevel
> 0);
452 entry
.bHaveMipMaps
= GenerateMipmaps
;
453 if(skip_texture_create
)
455 glTexSubImage2D(target
, 0,0,0,width
, height
, gl_format
, gl_type
, temp
);
461 gluBuild2DMipmaps(target
, gl_iformat
, width
, height
, gl_format
, gl_type
, temp
);
465 glTexImage2D(target
, 0, gl_iformat
, width
, height
, 0, gl_format
, gl_type
, temp
);
469 if (expandedWidth
!= width
) // reset
470 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
474 if(skip_texture_create
)
476 glCompressedTexSubImage2D(target
, 0,0,0,width
, height
,
477 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
,expandedWidth
*expandedHeight
/2, temp
);
481 glCompressedTexImage2D(target
, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
,
482 width
, height
, 0, expandedWidth
*expandedHeight
/2, temp
);
485 if(TexLevels
> 1 && dfmt
!= PC_TEX_FMT_NONE
)
488 int mipWidth
= width
>> 1;
489 int mipHeight
= height
>> 1;
490 ptr
+= entry
.size_in_bytes
;
491 while((mipHeight
|| mipWidth
) && (level
< TexLevels
))
493 u32 currentWidth
= (mipWidth
> 0)? mipWidth
: 1;
494 u32 currentHeight
= (mipHeight
> 0)? mipHeight
: 1;
495 expandedWidth
= (currentWidth
+ bsw
) & (~bsw
);
496 expandedHeight
= (currentHeight
+ bsh
) & (~bsh
);
497 TexDecoder_Decode(temp
, ptr
, expandedWidth
, expandedHeight
, tex_format
, tlutaddr
, tlutfmt
);
498 if (dfmt
!= PC_TEX_FMT_DXT1
)
500 if (expandedWidth
!= (int)currentWidth
)
501 glPixelStorei(GL_UNPACK_ROW_LENGTH
, expandedWidth
);
503 glTexSubImage2D(target
, level
,0,0,currentWidth
, currentHeight
, gl_format
, gl_type
, temp
);
505 if (expandedWidth
!= (int)currentWidth
)
506 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
510 if(skip_texture_create
)
512 glCompressedTexSubImage2D(target
, level
,0,0,currentWidth
, currentHeight
, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
,expandedWidth
*expandedHeight
/2, temp
);
516 glCompressedTexImage2D(target
, level
, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
, currentWidth
, currentHeight
, 0, expandedWidth
*expandedHeight
/2, temp
);
520 u32 size
= (max(mipWidth
, bsw
) * max(mipHeight
, bsh
) * bsdepth
) >> 1;
527 entry
.frameCount
= frameCount
;
530 entry
.fmt
= FullFormat
;
531 entry
.SetTextureParameters(tm0
,tm1
);
532 if (g_ActiveConfig
.bDumpTextures
) // dump texture to file
535 char szTemp
[MAX_PATH
];
536 char szDir
[MAX_PATH
];
537 const char* uniqueId
= globals
->unique_id
;
538 bool bCheckedDumpDir
= false;
540 sprintf(szDir
,"%s%s",File::GetUserPath(D_DUMPTEXTURES_IDX
), uniqueId
);
544 if (!File::Exists(szDir
) || !File::IsDirectory(szDir
))
545 File::CreateDir(szDir
);
547 bCheckedDumpDir
= true;
550 sprintf(szTemp
, "%s/%s_%08x_%i.tga",szDir
, uniqueId
, (unsigned int) texHash
, tex_format
);
551 if (!File::Exists(szTemp
))
553 SaveTexture(szTemp
, target
, entry
.texture
, expandedWidth
, expandedHeight
);
557 INCSTAT(stats
.numTexturesCreated
);
558 SETSTAT(stats
.numTexturesAlive
, textures
.size());
563 void TextureMngr::CopyRenderTargetToTexture(u32 address
, bool bFromZBuffer
, bool bIsIntensityFmt
, u32 copyfmt
, int bScaleByHalf
, const EFBRectangle
&source_rect
)
568 // for intensity values, use Y of YUV format!
569 // for all purposes, treat 4bit equivalents as 8bit (probably just used for compression)
575 // Z8M,G8,I8,A8,Z8,R8,B8,Z8L - I8
576 // Z16,GB8,RG8,Z16L,IA8,RA8 - IA8
577 GLenum gl_format
= GL_RGBA
;
578 GLenum gl_iformat
= 4;
579 GLenum gl_type
= GL_UNSIGNED_BYTE
;
581 float fConstAdd
[4] = {0};
582 memset(colmat
, 0, sizeof(colmat
));
590 colmat
[2] = colmat
[6] = colmat
[10] = colmat
[14] = 1;
593 colmat
[1] = colmat
[5] = colmat
[9] = colmat
[14] = 1;
595 case 11: // Z16 (reverse order)
596 colmat
[2] = colmat
[6] = colmat
[10] = colmat
[13] = 1;
599 colmat
[2] = colmat
[5] = colmat
[8] = colmat
[15] = 1;
602 colmat
[1] = colmat
[5] = colmat
[9] = colmat
[13] = 1;
605 colmat
[0] = colmat
[4] = colmat
[8] = colmat
[12] = 1;
608 colmat
[0] = colmat
[4] = colmat
[8] = colmat
[13] = 1;
611 ERROR_LOG(VIDEO
, "Unknown copy zbuf format: 0x%x", copyfmt
);
612 colmat
[0] = colmat
[5] = colmat
[10] = colmat
[15] = 1;
616 else if (bIsIntensityFmt
)
618 // TODO - verify these coefficients
619 fConstAdd
[0] = fConstAdd
[1] = fConstAdd
[2] = 16.0f
/255.0f
;
620 colmat
[0] = 0.257f
; colmat
[1] = 0.504f
; colmat
[2] = 0.098f
;
621 colmat
[4] = 0.257f
; colmat
[5] = 0.504f
; colmat
[6] = 0.098f
;
622 colmat
[8] = 0.257f
; colmat
[9] = 0.504f
; colmat
[10] = 0.098f
;
625 fConstAdd
[3] = 16.0f
/ 255.0f
;
626 colmat
[12] = 0.257f
; colmat
[13] = 0.504f
; colmat
[14] = 0.098f
;
636 colmat
[0] = colmat
[4] = colmat
[8] = colmat
[12] = 1;
639 colmat
[0] = colmat
[4] = colmat
[8] = colmat
[12] = 1;
642 colmat
[0] = colmat
[4] = colmat
[8] = colmat
[15] = 1;
645 colmat
[0] = colmat
[4] = colmat
[8] = colmat
[15] = 1;
648 colmat
[3] = colmat
[7] = colmat
[11] = colmat
[15] = 1;
651 colmat
[1] = colmat
[5] = colmat
[9] = colmat
[13] = 1;
654 colmat
[2] = colmat
[6] = colmat
[10] = colmat
[14] = 1;
657 colmat
[0] = colmat
[4] = colmat
[8] = colmat
[13] = 1;
660 colmat
[1] = colmat
[5] = colmat
[9] = colmat
[14] = 1;
663 colmat
[0] = colmat
[5] = colmat
[10] = 1;
664 fConstAdd
[3] = 1; // set alpha to 1
667 colmat
[0] = colmat
[5] = colmat
[10] = colmat
[15] = 1;
670 colmat
[0] = colmat
[5] = colmat
[10] = colmat
[15] = 1;
673 ERROR_LOG(VIDEO
, "Unknown copy color format: 0x%x", copyfmt
);
674 colmat
[0] = colmat
[5] = colmat
[10] = colmat
[15] = 1;
679 bool bIsInit
= textures
.find(address
) != textures
.end();
681 PRIM_LOG("copytarg: addr=0x%x, fromz=%d, intfmt=%d, copyfmt=%d", address
, (int)bFromZBuffer
, (int)bIsIntensityFmt
,copyfmt
);
683 TCacheEntry
& entry
= textures
[address
];
685 entry
.frameCount
= frameCount
;
687 int w
= (abs(source_rect
.GetWidth()) >> bScaleByHalf
);
688 int h
= (abs(source_rect
.GetHeight()) >> bScaleByHalf
);
696 glGenTextures(1, (GLuint
*)&entry
.texture
);
697 glBindTexture(GL_TEXTURE_RECTANGLE_ARB
, entry
.texture
);
699 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB
, 0, gl_iformat
, w
, h
, 0, gl_format
, gl_type
, NULL
);
704 _assert_(entry
.texture
);
706 if (entry
.w
== w
&& entry
.h
== h
&& entry
.isRectangle
&& entry
.fmt
== (int) copyfmt
)
708 glBindTexture(GL_TEXTURE_RECTANGLE_ARB
, entry
.texture
);
709 // for some reason mario sunshine errors here...
710 // Beyond Good and Evil does too, occasionally.
713 // Delete existing texture.
714 glDeleteTextures(1,(GLuint
*)&entry
.texture
);
715 glGenTextures(1, (GLuint
*)&entry
.texture
);
716 glBindTexture(GL_TEXTURE_RECTANGLE_ARB
, entry
.texture
);
717 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB
, 0, gl_iformat
, w
, h
, 0, gl_format
, gl_type
, NULL
);
722 if (!bIsInit
|| !entry
.isRenderTarget
)
724 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
725 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
727 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
728 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
729 if (glGetError() != GL_NO_ERROR
) {
730 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
731 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
738 entry
.isRectangle
= true;
739 entry
.isRenderTarget
= true;
742 // Make sure to resolve anything we need to read from.
743 GLuint read_texture
= bFromZBuffer
? g_framebufferManager
.ResolveAndGetDepthTarget(source_rect
) : g_framebufferManager
.ResolveAndGetRenderTarget(source_rect
);
747 // We have to run a pixel shader, for color conversion.
748 Renderer::ResetAPIState(); // reset any game specific settings
750 if (s_TempFramebuffer
== 0)
751 glGenFramebuffersEXT(1, (GLuint
*)&s_TempFramebuffer
);
753 g_framebufferManager
.SetFramebuffer(s_TempFramebuffer
);
754 // Bind texture to temporary framebuffer
755 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
, GL_TEXTURE_RECTANGLE_ARB
, entry
.texture
, 0);
756 GL_REPORT_FBO_ERROR();
759 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT
);
760 glActiveTexture(GL_TEXTURE0
);
761 glEnable(GL_TEXTURE_RECTANGLE_ARB
);
762 glBindTexture(GL_TEXTURE_RECTANGLE_ARB
, read_texture
);
764 glViewport(0, 0, w
, h
);
766 PixelShaderCache::EnableShader(bFromZBuffer
? PixelShaderCache::GetDepthMatrixProgram() : PixelShaderCache::GetColorMatrixProgram());
767 PixelShaderManager::SetColorMatrix(colmat
, fConstAdd
); // set transformation
770 TargetRectangle targetSource
= Renderer::ConvertEFBRectangle(source_rect
);
773 glTexCoord2f((GLfloat
)targetSource
.left
, (GLfloat
)targetSource
.bottom
); glVertex2f(-1, 1);
774 glTexCoord2f((GLfloat
)targetSource
.left
, (GLfloat
)targetSource
.top
); glVertex2f(-1, -1);
775 glTexCoord2f((GLfloat
)targetSource
.right
, (GLfloat
)targetSource
.top
); glVertex2f( 1, -1);
776 glTexCoord2f((GLfloat
)targetSource
.right
, (GLfloat
)targetSource
.bottom
); glVertex2f( 1, 1);
781 // Unbind texture from temporary framebuffer
782 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
, GL_TEXTURE_RECTANGLE_ARB
, 0, 0);
784 // Return to the EFB.
785 g_framebufferManager
.SetFramebuffer(0);
786 Renderer::RestoreAPIState();
787 VertexShaderManager::SetViewportChanged();
788 TextureMngr::DisableStage(0);
792 if (g_ActiveConfig
.bDumpEFBTarget
)
794 static int count
= 0;
795 SaveTexture(StringFromFormat("%sefb_frame_%i.tga", File::GetUserPath(D_DUMPTEXTURES_IDX
), count
++).c_str(), GL_TEXTURE_RECTANGLE_ARB
, entry
.texture
, entry
.w
, entry
.h
);
799 void TextureMngr::DisableStage(int stage
)
801 glActiveTexture(GL_TEXTURE0
+ stage
);
802 glDisable(GL_TEXTURE_2D
);
803 glDisable(GL_TEXTURE_RECTANGLE_ARB
);
806 void TextureMngr::ClearRenderTargets()
808 for (TexCache::iterator iter
= textures
.begin(); iter
!= textures
.end(); iter
++)
809 iter
->second
.isRenderTarget
= false;