diff options
| author | skidau <skidau@gmail.com> | 2013-03-27 13:19:23 +1100 |
|---|---|---|
| committer | skidau <skidau@gmail.com> | 2013-03-27 13:19:23 +1100 |
| commit | 7784fa4c67cc8d2545f45694d83805e7e89cd583 (patch) | |
| tree | 7724133aabe971ec417d1dea0977a525bb8debfb /Source/Core/VideoCommon/Src | |
| parent | d33c19b0cd2bae982c8d35e86a9d3551f9e5c72f (diff) | |
| parent | 5cea0d9defeaa23e7af94adf7615a44fb2c9c173 (diff) | |
Merge branch 'master' into wii-network
# By Ryan Houdek (185) and others
# Via degasus (12) and others
* master: (625 commits)
Revert "Don't open/close file for every file operation." as it was crashing PokePark in Windows builds.
Array overrun fixed in VertexShaderCache for the DX11 plugin.
Fixed DSPTool build.
Windows build fix
Go back to assuming every HID device is a wiimote on Windows. Fixed issue 6117. Unfixed issue 6031.
VideoSoftware: Improve fog range adjustment by using less magic and more comments.
revert RasterFont for VideoSoftware
ogl: fix virtual xfb
Windows build fix from web interface...
Adjusted the audio loop criteria, using >= on the Wii and == on GC. This fixes the audio static that occurred in Wii games after hours of play.
Forced the exception check only for ARAM DMA transfers. Removed the Eternal Darkness boot hack and replaced it with an exception check.
VideoSoftware: Implement fog range adjustment, fixing issue 6147.
implement 4xSSAA for OGL
move ogl-only settings into backend
Fix description of disable fog, and move it to enhancements tab.
Reverted rd76ca5783743 as it was made obsolete by r1d550f4496e4.
Removed the tracking of the FIFO Writes as it was made obsolete by r1d550f4496e4.
Forced the external exception check to occur sooner by changing the downcount.
Mark the Direct3D9 backend deprecated.
Prefer D3D11 and OpenGL over D3D9 by default.
...
Conflicts:
CMakeLists.txt
Source/Core/Common/Common.vcxproj.filters
Source/Core/Common/Src/CommonPaths.h
Source/Core/Core/Core.vcxproj.filters
Source/Core/Core/Src/Core.cpp
Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp
Source/VSProps/Dolphin.Win32.props
Source/VSProps/Dolphin.x64.props
Diffstat (limited to 'Source/Core/VideoCommon/Src')
65 files changed, 5657 insertions, 3949 deletions
diff --git a/Source/Core/VideoCommon/Src/AVIDump.cpp b/Source/Core/VideoCommon/Src/AVIDump.cpp index c172903b5d..fefb09fecb 100644 --- a/Source/Core/VideoCommon/Src/AVIDump.cpp +++ b/Source/Core/VideoCommon/Src/AVIDump.cpp @@ -157,9 +157,21 @@ void AVIDump::Stop() NOTICE_LOG(VIDEO, "Stop"); } -void AVIDump::AddFrame(char *data) +void AVIDump::AddFrame(const u8* data, int w, int h) { - AVIStreamWrite(m_streamCompressed, ++m_frameCount, 1, (LPVOID) data, m_bitmap.biSizeImage, AVIIF_KEYFRAME, NULL, &m_byteBuffer); + static bool shown_error = false; + if ((w != m_bitmap.biWidth || h != m_bitmap.biHeight) && !shown_error) + { + PanicAlert("You have resized the window while dumping frames.\n" + "Nothing sane can be done to handle this.\n" + "Your video will likely be broken."); + shown_error = true; + + m_bitmap.biWidth = w; + m_bitmap.biHeight = h; + } + + AVIStreamWrite(m_streamCompressed, ++m_frameCount, 1, const_cast<u8*>(data), m_bitmap.biSizeImage, AVIIF_KEYFRAME, NULL, &m_byteBuffer); m_totalBytes += m_byteBuffer; // Close the recording if the file is more than 2gb // VfW can't properly save files over 2gb in size, but can keep writing to them up to 4gb. @@ -298,9 +310,9 @@ bool AVIDump::CreateFile() return true; } -void AVIDump::AddFrame(uint8_t *data, int width, int height) +void AVIDump::AddFrame(const u8* data, int width, int height) { - avpicture_fill((AVPicture *)s_BGRFrame, data, PIX_FMT_BGR24, width, height); + avpicture_fill((AVPicture *)s_BGRFrame, const_cast<u8*>(data), PIX_FMT_BGR24, width, height); // Convert image from BGR24 to desired pixel format, and scale to initial // width and height diff --git a/Source/Core/VideoCommon/Src/AVIDump.h b/Source/Core/VideoCommon/Src/AVIDump.h index e74df05db4..08ab6be254 100644 --- a/Source/Core/VideoCommon/Src/AVIDump.h +++ b/Source/Core/VideoCommon/Src/AVIDump.h @@ -24,6 +24,8 @@ #include <stdint.h> #endif +#include "CommonTypes.h" + class AVIDump { private: @@ -36,11 +38,11 @@ class AVIDump public: #ifdef _WIN32 static bool Start(HWND hWnd, int w, int h); - static void AddFrame(char *data); #else static bool Start(int w, int h); - static void AddFrame(uint8_t *data, int width, int height); #endif + static void AddFrame(const u8* data, int width, int height); + static void Stop(); }; diff --git a/Source/Core/VideoCommon/Src/BPFunctions.cpp b/Source/Core/VideoCommon/Src/BPFunctions.cpp index cddeae3000..8dd24f4ed1 100644 --- a/Source/Core/VideoCommon/Src/BPFunctions.cpp +++ b/Source/Core/VideoCommon/Src/BPFunctions.cpp @@ -236,7 +236,7 @@ bool GetConfig(const int &type) case CONFIG_DISABLEFOG: return g_ActiveConfig.bDisableFog; case CONFIG_SHOWEFBREGIONS: - return false; + return g_ActiveConfig.bShowEFBCopyRegions; default: PanicAlert("GetConfig Error: Unknown Config Type!"); return false; @@ -248,6 +248,7 @@ u8 *GetPointer(const u32 &address) return Memory::GetPointer(address); } +// Never used. All backends call SetSamplerState in VertexManager::Flush void SetTextureMode(const BPCmd &bp) { g_renderer->SetSamplerState(bp.address & 3, (bp.address & 0xE0) == 0xA0); diff --git a/Source/Core/VideoCommon/Src/BPMemory.h b/Source/Core/VideoCommon/Src/BPMemory.h index 85e95f4f8b..1a29439b36 100644 --- a/Source/Core/VideoCommon/Src/BPMemory.h +++ b/Source/Core/VideoCommon/Src/BPMemory.h @@ -62,7 +62,7 @@ #define BPMEM_COPYFILTER1 0x54 #define BPMEM_CLEARBBOX1 0x55 #define BPMEM_CLEARBBOX2 0x56 -#define BPMEM_UNKNOWN_57 0x57 +#define BPMEM_CLEAR_PIXEL_PERF 0x57 #define BPMEM_REVBITS 0x58 #define BPMEM_SCISSOROFFSET 0x59 #define BPMEM_PRELOAD_ADDR 0x60 @@ -93,7 +93,7 @@ #define BPMEM_TEV_ALPHA_ENV 0xC1 // 0xC1 + (2 * 16) #define BPMEM_TEV_REGISTER_L 0xE0 // 0xE0 + (2 * 4) #define BPMEM_TEV_REGISTER_H 0xE1 // 0xE1 + (2 * 4) -#define BPMEM_FOGRANGE 0xE8 +#define BPMEM_FOGRANGE 0xE8 // 0xE8 + 6 #define BPMEM_FOGPARAM0 0xEE #define BPMEM_FOGBMAGNITUDE 0xEF #define BPMEM_FOGBEXPONENT 0xF0 @@ -197,55 +197,55 @@ enum AlphaOp union IND_MTXA { - struct - { - s32 ma : 11; - s32 mb : 11; - u32 s0 : 2; // bits 0-1 of scale factor - u32 rid : 8; - }; - u32 hex; + struct + { + s32 ma : 11; + s32 mb : 11; + u32 s0 : 2; // bits 0-1 of scale factor + u32 rid : 8; + }; + u32 hex; }; union IND_MTXB { - struct - { - s32 mc : 11; - s32 md : 11; - u32 s1 : 2; // bits 2-3 of scale factor - u32 rid : 8; - }; - u32 hex; + struct + { + s32 mc : 11; + s32 md : 11; + u32 s1 : 2; // bits 2-3 of scale factor + u32 rid : 8; + }; + u32 hex; }; union IND_MTXC { - struct - { - s32 me : 11; - s32 mf : 11; - u32 s2 : 2; // bits 4-5 of scale factor - u32 rid : 8; - }; - u32 hex; + struct + { + s32 me : 11; + s32 mf : 11; + u32 s2 : 2; // bits 4-5 of scale factor + u32 rid : 8; + }; + u32 hex; }; struct IND_MTX { - IND_MTXA col0; - IND_MTXB col1; - IND_MTXC col2; + IND_MTXA col0; + IND_MTXB col1; + IND_MTXC col2; }; union IND_IMASK { - struct - { - u32 mask : 24; - u32 rid : 8; - }; - u32 hex; + struct + { + u32 mask : 24; + u32 rid : 8; + }; + u32 hex; }; #define TEVSELCC_CPREV 0 @@ -276,48 +276,48 @@ union IND_IMASK struct TevStageCombiner { - union ColorCombiner - { - struct //abc=8bit,d=10bit - { - u32 d : 4; // TEVSELCC_X - u32 c : 4; // TEVSELCC_X - u32 b : 4; // TEVSELCC_X - u32 a : 4; // TEVSELCC_X - - u32 bias : 2; - u32 op : 1; - u32 clamp : 1; - - u32 shift : 2; - u32 dest : 2; //1,2,3 - - }; - u32 hex; - }; - union AlphaCombiner - { - struct - { - u32 rswap : 2; - u32 tswap : 2; - u32 d : 3; // TEVSELCA_ - u32 c : 3; // TEVSELCA_ - u32 b : 3; // TEVSELCA_ - u32 a : 3; // TEVSELCA_ - - u32 bias : 2; //GXTevBias - u32 op : 1; - u32 clamp : 1; - - u32 shift : 2; - u32 dest : 2; //1,2,3 - }; - u32 hex; - }; - - ColorCombiner colorC; - AlphaCombiner alphaC; + union ColorCombiner + { + struct //abc=8bit,d=10bit + { + u32 d : 4; // TEVSELCC_X + u32 c : 4; // TEVSELCC_X + u32 b : 4; // TEVSELCC_X + u32 a : 4; // TEVSELCC_X + + u32 bias : 2; + u32 op : 1; + u32 clamp : 1; + + u32 shift : 2; + u32 dest : 2; //1,2,3 + + }; + u32 hex; + }; + union AlphaCombiner + { + struct + { + u32 rswap : 2; + u32 tswap : 2; + u32 d : 3; // TEVSELCA_ + u32 c : 3; // TEVSELCA_ + u32 b : 3; // TEVSELCA_ + u32 a : 3; // TEVSELCA_ + + u32 bias : 2; //GXTevBias + u32 op : 1; + u32 clamp : 1; + + u32 shift : 2; + u32 dest : 2; //1,2,3 + }; + u32 hex; + }; + + ColorCombiner colorC; + AlphaCombiner alphaC; }; #define ITF_8 0 @@ -356,93 +356,93 @@ struct TevStageCombiner // GXSetTevIndirect(tevstage+1, indstage, 0, 3, realmat+4, 6, 6, 1, 0, 0) // GXSetTevIndirect(tevstage+2, indstage, 0, 0, 0, 0, 0, 1, 0, 0) -union TevStageIndirect -{ - // if mid, sw, tw, and addprev are 0, then no indirect stage is used, mask = 0x17fe00 - struct - { - u32 bt : 2; // indirect tex stage ID - u32 fmt : 2; // format: ITF_X - u32 bias : 3; // ITB_X - u32 bs : 2; // ITBA_X, indicates which coordinate will become the 'bump alpha' - u32 mid : 4; // matrix id to multiply offsets with - u32 sw : 3; // ITW_X, wrapping factor for S of regular coord - u32 tw : 3; // ITW_X, wrapping factor for T of regular coord - u32 lb_utclod : 1; // use modified or unmodified texture coordinates for LOD computation - u32 fb_addprev : 1; // 1 if the texture coordinate results from the previous TEV stage should be added - u32 pad0 : 3; - u32 rid : 8; - }; - struct - { - u32 hex : 21; - u32 unused : 11; - }; - - bool IsActive() { return (hex&0x17fe00)!=0; } -}; - -union TwoTevStageOrders -{ - struct - { - u32 texmap0 : 3; // indirect tex stage texmap - u32 texcoord0 : 3; - u32 enable0 : 1; // 1 if should read from texture - u32 colorchan0 : 3; // RAS1_CC_X - - u32 pad0 : 2; - - u32 texmap1 : 3; - u32 texcoord1 : 3; - u32 enable1 : 1; // 1 if should read from texture - u32 colorchan1 : 3; // RAS1_CC_X - - u32 pad1 : 2; - u32 rid : 8; - }; - u32 hex; - int getTexMap(int i){return i?texmap1:texmap0;} - int getTexCoord(int i){return i?texcoord1:texcoord0;} - int getEnable(int i){return i?enable1:enable0;} - int getColorChan(int i){return i?colorchan1:colorchan0;} -}; + union TevStageIndirect + { + // if mid, sw, tw, and addprev are 0, then no indirect stage is used, mask = 0x17fe00 + struct + { + u32 bt : 2; // indirect tex stage ID + u32 fmt : 2; // format: ITF_X + u32 bias : 3; // ITB_X + u32 bs : 2; // ITBA_X, indicates which coordinate will become the 'bump alpha' + u32 mid : 4; // matrix id to multiply offsets with + u32 sw : 3; // ITW_X, wrapping factor for S of regular coord + u32 tw : 3; // ITW_X, wrapping factor for T of regular coord + u32 lb_utclod : 1; // use modified or unmodified texture coordinates for LOD computation + u32 fb_addprev : 1; // 1 if the texture coordinate results from the previous TEV stage should be added + u32 pad0 : 3; + u32 rid : 8; + }; + struct + { + u32 hex : 21; + u32 unused : 11; + }; + + bool IsActive() { return (hex&0x17fe00)!=0; } + }; + + union TwoTevStageOrders + { + struct + { + u32 texmap0 : 3; // indirect tex stage texmap + u32 texcoord0 : 3; + u32 enable0 : 1; // 1 if should read from texture + u32 colorchan0 : 3; // RAS1_CC_X + + u32 pad0 : 2; + + u32 texmap1 : 3; + u32 texcoord1 : 3; + u32 enable1 : 1; // 1 if should read from texture + u32 colorchan1 : 3; // RAS1_CC_X + + u32 pad1 : 2; + u32 rid : 8; + }; + u32 hex; + int getTexMap(int i){return i?texmap1:texmap0;} + int getTexCoord(int i){return i?texcoord1:texcoord0;} + int getEnable(int i){return i?enable1:enable0;} + int getColorChan(int i){return i?colorchan1:colorchan0;} + }; union TEXSCALE { - struct - { - u32 ss0 : 4; // indirect tex stage 0, 2^(-ss0) - u32 ts0 : 4; // indirect tex stage 0 - u32 ss1 : 4; // indirect tex stage 1 - u32 ts1 : 4; // indirect tex stage 1 - u32 pad : 8; - u32 rid : 8; - }; - u32 hex; + struct + { + u32 ss0 : 4; // indirect tex stage 0, 2^(-ss0) + u32 ts0 : 4; // indirect tex stage 0 + u32 ss1 : 4; // indirect tex stage 1 + u32 ts1 : 4; // indirect tex stage 1 + u32 pad : 8; + u32 rid : 8; + }; + u32 hex; - float getScaleS(int i){return 1.0f/(float)(1<<(i?ss1:ss0));} - float getScaleT(int i){return 1.0f/(float)(1<<(i?ts1:ts0));} + float getScaleS(int i){return 1.0f/(float)(1<<(i?ss1:ss0));} + float getScaleT(int i){return 1.0f/(float)(1<<(i?ts1:ts0));} }; union RAS1_IREF { - struct - { - u32 bi0 : 3; // indirect tex stage 0 ntexmap - u32 bc0 : 3; // indirect tex stage 0 ntexcoord - u32 bi1 : 3; - u32 bc1 : 3; - u32 bi2 : 3; - u32 bc3 : 3; - u32 bi4 : 3; - u32 bc4 : 3; - u32 rid : 8; - }; - u32 hex; + struct + { + u32 bi0 : 3; // indirect tex stage 0 ntexmap + u32 bc0 : 3; // indirect tex stage 0 ntexcoord + u32 bi1 : 3; + u32 bc1 : 3; + u32 bi2 : 3; + u32 bc3 : 3; + u32 bi4 : 3; + u32 bc4 : 3; + u32 rid : 8; + }; + u32 hex; - u32 getTexCoord(int i) { return (hex>>(6*i+3))&3; } - u32 getTexMap(int i) { return (hex>>(6*i))&3; } + u32 getTexCoord(int i) { return (hex>>(6*i+3))&3; } + u32 getTexMap(int i) { return (hex>>(6*i))&3; } }; @@ -450,97 +450,97 @@ union RAS1_IREF union TexMode0 { - struct - { - u32 wrap_s : 2; - u32 wrap_t : 2; - u32 mag_filter : 1; - u32 min_filter : 3; - u32 diag_lod : 1; - s32 lod_bias : 8; + struct + { + u32 wrap_s : 2; + u32 wrap_t : 2; + u32 mag_filter : 1; + u32 min_filter : 3; + u32 diag_lod : 1; + s32 lod_bias : 8; u32 pad0 : 2; - u32 max_aniso : 2; - u32 lod_clamp : 1; - }; - u32 hex; + u32 max_aniso : 2; + u32 lod_clamp : 1; + }; + u32 hex; }; union TexMode1 { - struct - { - u32 min_lod : 8; - u32 max_lod : 8; - }; - u32 hex; + struct + { + u32 min_lod : 8; + u32 max_lod : 8; + }; + u32 hex; }; union TexImage0 { - struct - { - u32 width : 10; //actually w-1 - u32 height : 10; //actually h-1 - u32 format : 4; - }; - u32 hex; + struct + { + u32 width : 10; //actually w-1 + u32 height : 10; //actually h-1 + u32 format : 4; + }; + u32 hex; }; union TexImage1 { - struct - { - u32 tmem_even : 15; // tmem line index for even LODs - u32 cache_width : 3; - u32 cache_height : 3; - u32 image_type : 1; // 1 if this texture is managed manually (0 means we'll autofetch the texture data whenever it changes) - }; - u32 hex; + struct + { + u32 tmem_even : 15; // tmem line index for even LODs + u32 cache_width : 3; + u32 cache_height : 3; + u32 image_type : 1; // 1 if this texture is managed manually (0 means we'll autofetch the texture data whenever it changes) + }; + u32 hex; }; union TexImage2 { - struct - { - u32 tmem_odd : 15; // tmem line index for odd LODs - u32 cache_width : 3; - u32 cache_height : 3; - }; - u32 hex; + struct + { + u32 tmem_odd : 15; // tmem line index for odd LODs + u32 cache_width : 3; + u32 cache_height : 3; + }; + u32 hex; }; union TexImage3 { - struct - { - u32 image_base: 24; //address in memory >> 5 (was 20 for GC) - }; - u32 hex; + struct + { + u32 image_base: 24; //address in memory >> 5 (was 20 for GC) + }; + u32 hex; }; union TexTLUT { - struct - { - u32 tmem_offset : 10; - u32 tlut_format : 2; - }; - u32 hex; + struct + { + u32 tmem_offset : 10; + u32 tlut_format : 2; + }; + u32 hex; }; union ZTex1 { - struct - { - u32 bias : 24; - }; - u32 hex; + struct + { + u32 bias : 24; + }; + u32 hex; }; union ZTex2 { - struct - { - u32 type : 2; // TEV_Z_TYPE_X - u32 op : 2; // GXZTexOp - }; - u32 hex; + struct + { + u32 type : 2; // TEV_Z_TYPE_X + u32 op : 2; // GXZTexOp + }; + u32 hex; }; // Z-texture types (formats) @@ -555,14 +555,14 @@ union ZTex2 struct FourTexUnits { - TexMode0 texMode0[4]; - TexMode1 texMode1[4]; - TexImage0 texImage0[4]; - TexImage1 texImage1[4]; - TexImage2 texImage2[4]; - TexImage3 texImage3[4]; - TexTLUT texTlut[4]; - u32 unknown[4]; + TexMode0 texMode0[4]; + TexMode1 texMode1[4]; + TexImage0 texImage0[4]; + TexImage1 texImage1[4]; + TexImage2 texImage2[4]; + TexImage3 texImage3[4]; + TexTLUT texTlut[4]; + u32 unknown[4]; }; @@ -571,51 +571,51 @@ struct FourTexUnits union GenMode { - struct - { - u32 numtexgens : 4; // 0xF - u32 numcolchans : 5; // 0x1E0 - u32 ms_en : 1; // 0x200 - u32 numtevstages : 4; // 0x3C00 - u32 cullmode : 2; // 0xC000 - u32 numindstages : 3; // 0x30000 - u32 zfreeze : 5; //0x3C0000 - }; - u32 hex; + struct + { + u32 numtexgens : 4; // 0xF + u32 numcolchans : 5; // 0x1E0 + u32 ms_en : 1; // 0x200 + u32 numtevstages : 4; // 0x3C00 + u32 cullmode : 2; // 0xC000 + u32 numindstages : 3; // 0x30000 + u32 zfreeze : 5; //0x3C0000 + }; + u32 hex; }; union LPSize { - struct - { - u32 linesize : 8; // in 1/6th pixels - u32 pointsize : 8; // in 1/6th pixels - u32 lineoff : 3; - u32 pointoff : 3; - u32 lineaspect : 1; // interlacing: adjust for pixels having AR of 1/2 - u32 padding : 1; - }; - u32 hex; + struct + { + u32 linesize : 8; // in 1/6th pixels + u32 pointsize : 8; // in 1/6th pixels + u32 lineoff : 3; + u32 pointoff : 3; + u32 lineaspect : 1; // interlacing: adjust for pixels having AR of 1/2 + u32 padding : 1; + }; + u32 hex; }; union X12Y12 { - struct - { - u32 y : 12; - u32 x : 12; - }; - u32 hex; + struct + { + u32 y : 12; + u32 x : 12; + }; + u32 hex; }; union X10Y10 { - struct - { - u32 x : 10; - u32 y : 10; - }; - u32 hex; + struct + { + u32 x : 10; + u32 y : 10; + }; + u32 hex; }; @@ -623,59 +623,59 @@ union X10Y10 union BlendMode { - struct - { - u32 blendenable : 1; - u32 logicopenable : 1; - u32 dither : 1; - u32 colorupdate : 1; - u32 alphaupdate : 1; - u32 dstfactor : 3; //BLEND_ONE, BLEND_INV_SRc etc - u32 srcfactor : 3; - u32 subtract : 1; - u32 logicmode : 4; - }; - u32 hex; + struct + { + u32 blendenable : 1; + u32 logicopenable : 1; + u32 dither : 1; + u32 colorupdate : 1; + u32 alphaupdate : 1; + u32 dstfactor : 3; //BLEND_ONE, BLEND_INV_SRc etc + u32 srcfactor : 3; + u32 subtract : 1; + u32 logicmode : 4; + }; + u32 hex; }; union FogParam0 { - struct - { - u32 mantissa : 11; - u32 exponent : 8; - u32 sign : 1; - }; + struct + { + u32 mantissa : 11; + u32 exponent : 8; + u32 sign : 1; + }; - float GetA() { + float GetA() { union { u32 i; float f; } dummy; - dummy.i = ((u32)sign << 31) | ((u32)exponent << 23) | ((u32)mantissa << 12); // scale mantissa from 11 to 23 bits + dummy.i = ((u32)sign << 31) | ((u32)exponent << 23) | ((u32)mantissa << 12); // scale mantissa from 11 to 23 bits return dummy.f; } - u32 hex; + u32 hex; }; union FogParam3 { - struct - { - u32 c_mant : 11; - u32 c_exp : 8; - u32 c_sign : 1; - u32 proj : 1; // 0 - perspective, 1 - orthographic - u32 fsel : 3; // 0 - off, 2 - linear, 4 - exp, 5 - exp2, 6 - backward exp, 7 - backward exp2 - }; - - // amount to subtract from eyespacez after range adjustment - float GetC() { + struct + { + u32 c_mant : 11; + u32 c_exp : 8; + u32 c_sign : 1; + u32 proj : 1; // 0 - perspective, 1 - orthographic + u32 fsel : 3; // 0 - off, 2 - linear, 4 - exp, 5 - exp2, 6 - backward exp, 7 - backward exp2 + }; + + // amount to subtract from eyespacez after range adjustment + float GetC() { union { u32 i; float f; } dummy; dummy.i = ((u32)c_sign << 31) | ((u32)c_exp << 23) | ((u32)c_mant << 12); // scale mantissa from 11 to 23 bits return dummy.f; } - u32 hex; + u32 hex; }; union FogRangeKElement @@ -686,6 +686,9 @@ union FogRangeKElement u32 LO : 12; u32 regid : 8; }; + + // TODO: Which scaling coefficient should we use here? This is just a guess! + float GetValue(int i) { return (i ? HI : LO) / 256.f; } u32 HEX; }; @@ -695,7 +698,7 @@ struct FogRangeParams { struct { - u32 Center : 10; + u32 Center : 10; // viewport center + 342 u32 Enabled : 1; u32 unused : 13; u32 regid : 8; @@ -708,44 +711,44 @@ struct FogRangeParams // final eq: ze = A/(B_MAG - (Zs>>B_SHF)); struct FogParams { - FogParam0 a; - u32 b_magnitude; - u32 b_shift; // b's exp + 1? - FogParam3 c_proj_fsel; + FogParam0 a; + u32 b_magnitude; + u32 b_shift; // b's exp + 1? + FogParam3 c_proj_fsel; - union FogColor - { - struct - { - u32 b : 8; - u32 g : 8; - u32 r : 8; - }; - u32 hex; - }; + union FogColor + { + struct + { + u32 b : 8; + u32 g : 8; + u32 r : 8; + }; + u32 hex; + }; - FogColor color; //0:b 8:g 16:r - nice! + FogColor color; //0:b 8:g 16:r - nice! }; union ZMode { - struct - { - u32 testenable : 1; - u32 func : 3; - u32 updateenable : 1; //size? - }; - u32 hex; + struct + { + u32 testenable : 1; + u32 func : 3; + u32 updateenable : 1; //size? + }; + u32 hex; }; union ConstantAlpha { - struct - { - u32 alpha : 8; - u32 enable : 1; - }; - u32 hex; + struct + { + u32 alpha : 8; + u32 enable : 1; + }; + u32 hex; }; union FieldMode @@ -789,15 +792,15 @@ union FieldMask union PE_CONTROL { - struct - { - u32 pixel_format : 3; // PIXELFMT_X - u32 zformat : 3; // Z Compression for 16bit Z format - u32 early_ztest : 1; // 1: before tex stage - u32 unused : 17; - u32 rid : 8; - }; - u32 hex; + struct + { + u32 pixel_format : 3; // PIXELFMT_X + u32 zformat : 3; // Z Compression for 16bit Z format + u32 early_ztest : 1; // 1: before tex stage + u32 unused : 17; + u32 rid : 8; + }; + u32 hex; }; @@ -805,69 +808,69 @@ union PE_CONTROL union TCInfo { - struct - { - u32 scale_minus_1 : 16; - u32 range_bias : 1; - u32 cylindric_wrap : 1; + struct + { + u32 scale_minus_1 : 16; + u32 range_bias : 1; + u32 cylindric_wrap : 1; // These bits only have effect in the s field of TCoordInfo u32 line_offset : 1; u32 point_offset : 1; - }; - u32 hex; + }; + u32 hex; }; struct TCoordInfo { - TCInfo s; - TCInfo t; + TCInfo s; + TCInfo t; }; union ColReg { - u32 hex; - struct - { - s32 a : 11; - u32 : 1; - s32 b : 11; - u32 type : 1; - }; + u32 hex; + struct + { + s32 a : 11; + u32 : 1; + s32 b : 11; + u32 type : 1; + }; }; struct TevReg { - ColReg low; - ColReg high; + ColReg low; + ColReg high; }; union TevKSel { - struct { - u32 swap1 : 2; - u32 swap2 : 2; - u32 kcsel0 : 5; - u32 kasel0 : 5; - u32 kcsel1 : 5; - u32 kasel1 : 5; - }; - u32 hex; + struct { + u32 swap1 : 2; + u32 swap2 : 2; + u32 kcsel0 : 5; + u32 kasel0 : 5; + u32 kcsel1 : 5; + u32 kasel1 : 5; + }; + u32 hex; - int getKC(int i) {return i?kcsel1:kcsel0;} - int getKA(int i) {return i?kasel1:kasel0;} + int getKC(int i) {return i?kcsel1:kcsel0;} + int getKA(int i) {return i?kasel1:kasel0;} }; union AlphaTest { - struct - { - u32 ref0 : 8; - u32 ref1 : 8; - u32 comp0 : 3; - u32 comp1 : 3; - u32 logic : 2; - }; - u32 hex; + struct + { + u32 ref0 : 8; + u32 ref1 : 8; + u32 comp0 : 3; + u32 comp1 : 3; + u32 logic : 2; + }; + u32 hex; enum TEST_RESULT { @@ -881,22 +884,22 @@ union AlphaTest union UPE_Copy { - u32 Hex; - struct - { - u32 clamp0 : 1; // if set clamp top + u32 Hex; + struct + { + u32 clamp0 : 1; // if set clamp top u32 clamp1 : 1; // if set clamp bottom - u32 yuv : 1; // if set, color conversion from RGB to YUV - u32 target_pixel_format : 4; // realformat is (fmt/2)+((fmt&1)*8).... for some reason the msb is the lsb (pattern: cycling right shift) - u32 gamma : 2; // gamma correction.. 0 = 1.0 ; 1 = 1.7 ; 2 = 2.2 ; 3 is reserved - u32 half_scale : 1; // "mipmap" filter... 0 = no filter (scale 1:1) ; 1 = box filter (scale 2:1) - u32 scale_invert : 1; // if set vertical scaling is on - u32 clear : 1; + u32 yuv : 1; // if set, color conversion from RGB to YUV + u32 target_pixel_format : 4; // realformat is (fmt/2)+((fmt&1)*8).... for some reason the msb is the lsb (pattern: cycling right shift) + u32 gamma : 2; // gamma correction.. 0 = 1.0 ; 1 = 1.7 ; 2 = 2.2 ; 3 is reserved + u32 half_scale : 1; // "mipmap" filter... 0 = no filter (scale 1:1) ; 1 = box filter (scale 2:1) + u32 scale_invert : 1; // if set vertical scaling is on + u32 clear : 1; u32 frame_to_field : 2; // 0 progressive ; 1 is reserved ; 2 = interlaced (even lines) ; 3 = interlaced 1 (odd lines) - u32 copy_to_xfb : 1; - u32 intensity_fmt : 1; // if set, is an intensity format (I4,I8,IA4,IA8) - u32 auto_conv : 1; // if 0 automatic color conversion by texture format and pixel type - }; + u32 copy_to_xfb : 1; + u32 intensity_fmt : 1; // if set, is an intensity format (I4,I8,IA4,IA8) + u32 auto_conv : 1; // if 0 automatic color conversion by texture format and pixel type + }; u32 tp_realFormat() { return target_pixel_format / 2 + (target_pixel_format & 1) * 8; } @@ -934,68 +937,68 @@ struct BPCmd struct BPMemory { - GenMode genMode; - u32 display_copy_filter[4]; // 01-04 - u32 unknown; // 05 - // indirect matrices (set by GXSetIndTexMtx, selected by TevStageIndirect::mid) - // abc form a 2x3 offset matrix, there's 3 such matrices - // the 3 offset matrices can either be indirect type, S-type, or T-type - // 6bit scale factor s is distributed across IND_MTXA/B/C. - // before using matrices scale by 2^-(s-17) - IND_MTX indmtx[3];//06-0e GXSetIndTexMtx, 2x3 matrices - IND_IMASK imask;//0f - TevStageIndirect tevind[16];//10 GXSetTevIndirect - X12Y12 scissorTL; //20 - X12Y12 scissorBR; //21 - LPSize lineptwidth; //22 line and point width - u32 sucounter; //23 - u32 rascounter; //24 - TEXSCALE texscale[2]; //25-26 GXSetIndTexCoordScale - RAS1_IREF tevindref; //27 GXSetIndTexOrder - TwoTevStageOrders tevorders[8]; //28-2F - TCoordInfo texcoords[8]; //0x30 s,t,s,t,s,t,s,t... - ZMode zmode; //40 - BlendMode blendmode; //41 - ConstantAlpha dstalpha; //42 - PE_CONTROL zcontrol; //43 GXSetZCompLoc, GXPixModeSync - FieldMask fieldmask; //44 - u32 drawdone; //45, bit1=1 if end of list - u32 unknown5; //46 clock? - u32 petoken; //47 - u32 petokenint; // 48 - X10Y10 copyTexSrcXY; // 49 - X10Y10 copyTexSrcWH; // 4a - u32 copyTexDest; //4b// 4b == CopyAddress (GXDispCopy and GXTexCopy use it) - u32 unknown6; //4c - u32 copyMipMapStrideChannels; // 4d usually set to 4 when dest is single channel, 8 when dest is 2 channel, 16 when dest is RGBA - // also, doubles whenever mipmap box filter option is set (excent on RGBA). Probably to do with number of bytes to look at when smoothing - u32 dispcopyyscale; //4e - u32 clearcolorAR; //4f - u32 clearcolorGB; //50 - u32 clearZValue; //51 - UPE_Copy triggerEFBCopy; //52 - u32 copyfilter[2]; //53,54 - u32 boundbox0;//55 - u32 boundbox1;//56 - u32 unknown7[2];//57,58 - X10Y10 scissorOffset; //59 - u32 unknown8[6]; //5a,5b,5c,5d, 5e,5f - BPS_TmemConfig tmem_config; // 60-66 - u32 metric; //67 - FieldMode fieldmode;//68 - u32 unknown10[7];//69-6F - u32 unknown11[16];//70-7F - FourTexUnits tex[2]; //80-bf - TevStageCombiner combiners[16]; //0xC0-0xDF - TevReg tevregs[4]; //0xE0 - FogRangeParams fogRange; - FogParams fog; //0xEE,0xEF,0xF0,0xF1,0xF2 - AlphaTest alpha_test; //0xF3 - ZTex1 ztex1; //0xf4,0xf5 - ZTex2 ztex2; - TevKSel tevksel[8];//0xf6,0xf7,f8,f9,fa,fb,fc,fd - u32 bpMask; //0xFE - u32 unknown18; //ff + GenMode genMode; + u32 display_copy_filter[4]; // 01-04 + u32 unknown; // 05 + // indirect matrices (set by GXSetIndTexMtx, selected by TevStageIndirect::mid) + // abc form a 2x3 offset matrix, there's 3 such matrices + // the 3 offset matrices can either be indirect type, S-type, or T-type + // 6bit scale factor s is distributed across IND_MTXA/B/C. + // before using matrices scale by 2^-(s-17) + IND_MTX indmtx[3];//06-0e GXSetIndTexMtx, 2x3 matrices + IND_IMASK imask;//0f + TevStageIndirect tevind[16];//10 GXSetTevIndirect + X12Y12 scissorTL; //20 + X12Y12 scissorBR; //21 + LPSize lineptwidth; //22 line and point width + u32 sucounter; //23 + u32 rascounter; //24 + TEXSCALE texscale[2]; //25-26 GXSetIndTexCoordScale + RAS1_IREF tevindref; //27 GXSetIndTexOrder + TwoTevStageOrders tevorders[8]; //28-2F + TCoordInfo texcoords[8]; //0x30 s,t,s,t,s,t,s,t... + ZMode zmode; //40 + BlendMode blendmode; //41 + ConstantAlpha dstalpha; //42 + PE_CONTROL zcontrol; //43 GXSetZCompLoc, GXPixModeSync + FieldMask fieldmask; //44 + u32 drawdone; //45, bit1=1 if end of list + u32 unknown5; //46 clock? + u32 petoken; //47 + u32 petokenint; // 48 + X10Y10 copyTexSrcXY; // 49 + X10Y10 copyTexSrcWH; // 4a + u32 copyTexDest; //4b// 4b == CopyAddress (GXDispCopy and GXTexCopy use it) + u32 unknown6; //4c + u32 copyMipMapStrideChannels; // 4d usually set to 4 when dest is single channel, 8 when dest is 2 channel, 16 when dest is RGBA + // also, doubles whenever mipmap box filter option is set (excent on RGBA). Probably to do with number of bytes to look at when smoothing + u32 dispcopyyscale; //4e + u32 clearcolorAR; //4f + u32 clearcolorGB; //50 + u32 clearZValue; //51 + UPE_Copy triggerEFBCopy; //52 + u32 copyfilter[2]; //53,54 + u32 boundbox0;//55 + u32 boundbox1;//56 + u32 unknown7[2];//57,58 + X10Y10 scissorOffset; //59 + u32 unknown8[6]; //5a,5b,5c,5d, 5e,5f + BPS_TmemConfig tmem_config; // 60-66 + u32 metric; //67 + FieldMode fieldmode;//68 + u32 unknown10[7];//69-6F + u32 unknown11[16];//70-7F + FourTexUnits tex[2]; //80-bf + TevStageCombiner combiners[16]; //0xC0-0xDF + TevReg tevregs[4]; //0xE0 + FogRangeParams fogRange; // 0xE8 + FogParams fog; //0xEE,0xEF,0xF0,0xF1,0xF2 + AlphaTest alpha_test; //0xF3 + ZTex1 ztex1; //0xf4,0xf5 + ZTex2 ztex2; + TevKSel tevksel[8];//0xf6,0xf7,f8,f9,fa,fb,fc,fd + u32 bpMask; //0xFE + u32 unknown18; //ff }; #pragma pack() diff --git a/Source/Core/VideoCommon/Src/BPStructs.cpp b/Source/Core/VideoCommon/Src/BPStructs.cpp index 0d7d741a92..9580eea447 100644 --- a/Source/Core/VideoCommon/Src/BPStructs.cpp +++ b/Source/Core/VideoCommon/Src/BPStructs.cpp @@ -31,6 +31,7 @@ #include "VertexShaderManager.h" #include "Thread.h" #include "HW/Memmap.h" +#include "PerfQueryBase.h" using namespace BPFunctions; @@ -62,7 +63,6 @@ void RenderToXFB(const BPCmd &bp, const EFBRectangle &rc, float yScale, float xf { Renderer::RenderToXFB(xfbAddr, dstWidth, dstHeight, rc, gamma); } - void BPWritten(const BPCmd& bp) { /* @@ -144,7 +144,8 @@ void BPWritten(const BPCmd& bp) || bp.address == BPMEM_LOADTLUT0 || bp.address == BPMEM_LOADTLUT1 || bp.address == BPMEM_TEXINVALIDATE - || bp.address == BPMEM_PRELOAD_MODE)) + || bp.address == BPMEM_PRELOAD_MODE + || bp.address == BPMEM_CLEAR_PIXEL_PERF)) { return; } @@ -212,7 +213,7 @@ void BPWritten(const BPCmd& bp) if (bp.changes & 4) SetDitherMode(); // Set Blending Mode - if (bp.changes & 0xFE1) + if (bp.changes & 0xFF1) SetBlendMode(); // Set Color Mask if (bp.changes & 0x18) @@ -224,6 +225,8 @@ void BPWritten(const BPCmd& bp) { PRIM_LOG("constalpha: alp=%d, en=%d", bpmem.dstalpha.alpha, bpmem.dstalpha.enable); PixelShaderManager::SetDestAlpha(bpmem.dstalpha); + if(bp.changes & 0x100) + SetBlendMode(); break; } // This is called when the game is done drawing the new frame (eg: like in DX: Begin(); Draw(); End();) @@ -455,9 +458,11 @@ void BPWritten(const BPCmd& bp) break; case BPMEM_ZCOMPARE: // Set the Z-Compare and EFB pixel format - g_renderer->SetColorMask(); // alpha writing needs to be disabled if the new pixel format doesn't have an alpha channel - g_renderer->SetBlendMode(true); OnPixelFormatChange(); + if(bp.changes & 7) { + SetBlendMode(); // dual source could be activated by changing to PIXELFMT_RGBA6_Z24 + g_renderer->SetColorMask(); // alpha writing needs to be disabled if the new pixel format doesn't have an alpha channel + } break; case BPMEM_MIPMAP_STRIDE: // MipMap Stride Channel @@ -484,9 +489,10 @@ void BPWritten(const BPCmd& bp) case BPMEM_IND_IMASK: // Index Mask ? case BPMEM_REVBITS: // Always set to 0x0F when GX_InitRevBits() is called. break; - - case BPMEM_UNKNOWN_57: // Sunshine alternates this register between values 0x000 and 0xAAA - DEBUG_LOG(VIDEO, "Unknown BP Reg 0x57: %08x", bp.newvalue); + + case BPMEM_CLEAR_PIXEL_PERF: + // GXClearPixMetric writes 0xAAA here, Sunshine alternates this register between values 0x000 and 0xAAA + g_perf_query->ResetQuery(); break; case BPMEM_PRELOAD_ADDR: @@ -574,8 +580,6 @@ void BPWritten(const BPCmd& bp) // ------------------------ case BPMEM_TX_SETMODE0: // (0x90 for linear) case BPMEM_TX_SETMODE0_4: - // Shouldn't need to call this here, we call it for each active texture right before rendering - SetTextureMode(bp); break; case BPMEM_TX_SETMODE1: @@ -718,14 +722,6 @@ void BPReload() SetColorMask(); OnPixelFormatChange(); { - BPCmd bp = {BPMEM_TX_SETMODE0, 0xFFFFFF, static_cast<int>(((u32*)&bpmem)[BPMEM_TX_SETMODE0])}; - SetTextureMode(bp); - } - { - BPCmd bp = {BPMEM_TX_SETMODE0_4, 0xFFFFFF, static_cast<int>(((u32*)&bpmem)[BPMEM_TX_SETMODE0_4])}; - SetTextureMode(bp); - } - { BPCmd bp = {BPMEM_FIELDMASK, 0xFFFFFF, static_cast<int>(((u32*)&bpmem)[BPMEM_FIELDMASK])}; SetInterlacingMode(bp); } diff --git a/Source/Core/VideoCommon/Src/CPMemory.h b/Source/Core/VideoCommon/Src/CPMemory.h index c4a24ba7a4..145f18aca7 100644 --- a/Source/Core/VideoCommon/Src/CPMemory.h +++ b/Source/Core/VideoCommon/Src/CPMemory.h @@ -25,18 +25,18 @@ enum { ARRAY_POSITION = 0, ARRAY_NORMAL = 1, - ARRAY_COLOR = 2, - ARRAY_COLOR2 = 3, - ARRAY_TEXCOORD0 = 4, + ARRAY_COLOR = 2, + ARRAY_COLOR2 = 3, + ARRAY_TEXCOORD0 = 4, }; // Vertex components enum { NOT_PRESENT = 0, - DIRECT = 1, - INDEX8 = 2, - INDEX16 = 3, + DIRECT = 1, + INDEX8 = 2, + INDEX16 = 3, }; enum @@ -74,14 +74,14 @@ union TVtxDesc // 0: not present // 1: present u32 PosMatIdx : 1; - u32 Tex0MatIdx : 1; - u32 Tex1MatIdx : 1; - u32 Tex2MatIdx : 1; - u32 Tex3MatIdx : 1; - u32 Tex4MatIdx : 1; - u32 Tex5MatIdx : 1; - u32 Tex6MatIdx : 1; - u32 Tex7MatIdx : 1; + u32 Tex0MatIdx : 1; + u32 Tex1MatIdx : 1; + u32 Tex2MatIdx : 1; + u32 Tex3MatIdx : 1; + u32 Tex4MatIdx : 1; + u32 Tex5MatIdx : 1; + u32 Tex6MatIdx : 1; + u32 Tex7MatIdx : 1; // 00: not present // 01: direct @@ -89,156 +89,156 @@ union TVtxDesc // 11: 16 bit index u32 Position : 2; u32 Normal : 2; - u32 Color0 : 2; - u32 Color1 : 2; - u32 Tex0Coord : 2; - u32 Tex1Coord : 2; - u32 Tex2Coord : 2; - u32 Tex3Coord : 2; - u32 Tex4Coord : 2; - u32 Tex5Coord : 2; - u32 Tex6Coord : 2; - u32 Tex7Coord : 2; + u32 Color0 : 2; + u32 Color1 : 2; + u32 Tex0Coord : 2; + u32 Tex1Coord : 2; + u32 Tex2Coord : 2; + u32 Tex3Coord : 2; + u32 Tex4Coord : 2; + u32 Tex5Coord : 2; + u32 Tex6Coord : 2; + u32 Tex7Coord : 2; u32 :31; }; - struct { - u32 Hex0, Hex1; - }; + struct { + u32 Hex0, Hex1; + }; }; union UVAT_group0 { - u32 Hex; - struct - { - // 0:8 - u32 PosElements : 1; - u32 PosFormat : 3; - u32 PosFrac : 5; - // 9:12 - u32 NormalElements : 1; - u32 NormalFormat : 3; - // 13:16 - u32 Color0Elements : 1; - u32 Color0Comp : 3; - // 17:20 - u32 Color1Elements : 1; - u32 Color1Comp : 3; - // 21:29 - u32 Tex0CoordElements : 1; - u32 Tex0CoordFormat : 3; - u32 Tex0Frac : 5; - // 30:31 - u32 ByteDequant : 1; - u32 NormalIndex3 : 1; - }; + u32 Hex; + struct + { + // 0:8 + u32 PosElements : 1; + u32 PosFormat : 3; + u32 PosFrac : 5; + // 9:12 + u32 NormalElements : 1; + u32 NormalFormat : 3; + // 13:16 + u32 Color0Elements : 1; + u32 Color0Comp : 3; + // 17:20 + u32 Color1Elements : 1; + u32 Color1Comp : 3; + // 21:29 + u32 Tex0CoordElements : 1; + u32 Tex0CoordFormat : 3; + u32 Tex0Frac : 5; + // 30:31 + u32 ByteDequant : 1; + u32 NormalIndex3 : 1; + }; }; union UVAT_group1 { - u32 Hex; - struct - { - // 0:8 - u32 Tex1CoordElements : 1; - u32 Tex1CoordFormat : 3; - u32 Tex1Frac : 5; - // 9:17 - u32 Tex2CoordElements : 1; - u32 Tex2CoordFormat : 3; - u32 Tex2Frac : 5; - // 18:26 - u32 Tex3CoordElements : 1; - u32 Tex3CoordFormat : 3; - u32 Tex3Frac : 5; - // 27:30 - u32 Tex4CoordElements : 1; - u32 Tex4CoordFormat : 3; - // - u32 : 1; - }; + u32 Hex; + struct + { + // 0:8 + u32 Tex1CoordElements : 1; + u32 Tex1CoordFormat : 3; + u32 Tex1Frac : 5; + // 9:17 + u32 Tex2CoordElements : 1; + u32 Tex2CoordFormat : 3; + u32 Tex2Frac : 5; + // 18:26 + u32 Tex3CoordElements : 1; + u32 Tex3CoordFormat : 3; + u32 Tex3Frac : 5; + // 27:30 + u32 Tex4CoordElements : 1; + u32 Tex4CoordFormat : 3; + // + u32 : 1; + }; }; union UVAT_group2 { - u32 Hex; - struct - { - // 0:4 - u32 Tex4Frac : 5; - // 5:13 - u32 Tex5CoordElements : 1; - u32 Tex5CoordFormat : 3; - u32 Tex5Frac : 5; - // 14:22 - u32 Tex6CoordElements : 1; - u32 Tex6CoordFormat : 3; - u32 Tex6Frac : 5; - // 23:31 - u32 Tex7CoordElements : 1; - u32 Tex7CoordFormat : 3; - u32 Tex7Frac : 5; - }; + u32 Hex; + struct + { + // 0:4 + u32 Tex4Frac : 5; + // 5:13 + u32 Tex5CoordElements : 1; + u32 Tex5CoordFormat : 3; + u32 Tex5Frac : 5; + // 14:22 + u32 Tex6CoordElements : 1; + u32 Tex6CoordFormat : 3; + u32 Tex6Frac : 5; + // 23:31 + u32 Tex7CoordElements : 1; + u32 Tex7CoordFormat : 3; + u32 Tex7Frac : 5; + }; }; struct ColorAttr { - u8 Elements; - u8 Comp; + u8 Elements; + u8 Comp; }; struct TexAttr { - u8 Elements; - u8 Format; - u8 Frac; + u8 Elements; + u8 Format; + u8 Frac; }; struct TVtxAttr -{ - u8 PosElements; - u8 PosFormat; - u8 PosFrac; - u8 NormalElements; - u8 NormalFormat; - ColorAttr color[2]; - TexAttr texCoord[8]; - u8 ByteDequant; - u8 NormalIndex3; +{ + u8 PosElements; + u8 PosFormat; + u8 PosFrac; + u8 NormalElements; + u8 NormalFormat; + ColorAttr color[2]; + TexAttr texCoord[8]; + u8 ByteDequant; + u8 NormalIndex3; }; // Matrix indices union TMatrixIndexA { - struct - { - u32 PosNormalMtxIdx : 6; - u32 Tex0MtxIdx : 6; - u32 Tex1MtxIdx : 6; - u32 Tex2MtxIdx : 6; - u32 Tex3MtxIdx : 6; - }; - struct - { - u32 Hex : 30; - u32 unused : 2; - }; + struct + { + u32 PosNormalMtxIdx : 6; + u32 Tex0MtxIdx : 6; + u32 Tex1MtxIdx : 6; + u32 Tex2MtxIdx : 6; + u32 Tex3MtxIdx : 6; + }; + struct + { + u32 Hex : 30; + u32 unused : 2; + }; }; union TMatrixIndexB { - struct - { - u32 Tex4MtxIdx : 6; - u32 Tex5MtxIdx : 6; - u32 Tex6MtxIdx : 6; - u32 Tex7MtxIdx : 6; - }; - struct - { - u32 Hex : 24; - u32 unused : 8; - }; + struct + { + u32 Tex4MtxIdx : 6; + u32 Tex5MtxIdx : 6; + u32 Tex6MtxIdx : 6; + u32 Tex7MtxIdx : 6; + }; + struct + { + u32 Hex : 24; + u32 unused : 8; + }; }; #pragma pack() diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp index a4dddf537f..dacec67823 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp @@ -32,6 +32,8 @@ #include "HW/GPFifo.h" #include "HW/Memmap.h" #include "DLCache.h" +#include "HW/SystemTimers.h" +#include "Core.h" namespace CommandProcessor { @@ -57,12 +59,15 @@ static bool bProcessFifoAllDistance = false; volatile bool isPossibleWaitingSetDrawDone = false; volatile bool isHiWatermarkActive = false; +volatile bool isLoWatermarkActive = false; volatile bool interruptSet= false; volatile bool interruptWaiting= false; volatile bool interruptTokenWaiting = false; volatile bool interruptFinishWaiting = false; volatile bool waitingForPEInterruptDisable = false; +volatile u32 VITicks = CommandProcessor::m_cpClockOrigin; + bool IsOnThread() { return SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread; @@ -88,6 +93,7 @@ void DoState(PointerWrap &p) p.Do(bProcessFifoToLoWatermark); p.Do(bProcessFifoAllDistance); p.Do(isHiWatermarkActive); + p.Do(isLoWatermarkActive); p.Do(isPossibleWaitingSetDrawDone); p.Do(interruptSet); p.Do(interruptWaiting); @@ -119,7 +125,7 @@ void Init() m_tokenReg = 0; memset(&fifo,0,sizeof(fifo)); - fifo.CPCmdIdle = 1 ; + fifo.CPCmdIdle = 1; fifo.CPReadIdle = 1; fifo.bFF_Breakpoint = 0; fifo.bFF_HiWatermark = 0; @@ -136,8 +142,9 @@ void Init() bProcessFifoAllDistance = false; isPossibleWaitingSetDrawDone = false; isHiWatermarkActive = false; + isLoWatermarkActive = false; - et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper); + et_UpdateInterrupts = CoreTiming::RegisterEvent("CPInterrupt", UpdateInterrupts_Wrapper); } void Read16(u16& _rReturnValue, const u32 _Address) @@ -294,7 +301,6 @@ void Read16(u16& _rReturnValue, const u32 _Address) void Write16(const u16 _Value, const u32 _Address) { - INFO_LOG(COMMANDPROCESSOR, "(write16): 0x%04x @ 0x%08x",_Value,_Address); switch (_Address & 0xFFF) @@ -319,7 +325,7 @@ void Write16(const u16 _Value, const u32 _Address) case CLEAR_REGISTER: { UCPClearReg tmpCtrl(_Value); - m_CPClearReg.Hex = tmpCtrl.Hex; + m_CPClearReg.Hex = tmpCtrl.Hex; DEBUG_LOG(COMMANDPROCESSOR,"\t write to CLEAR_REGISTER : %04x", _Value); SetCpClearRegister(); } @@ -405,9 +411,10 @@ void Write16(const u16 _Value, const u32 _Address) { GPFifo::ResetGatherPipe(); ResetVideoBuffer(); - }else + } + else { - ResetVideoBuffer(); + ResetVideoBuffer(); } IncrementCheckContextId(); DEBUG_LOG(COMMANDPROCESSOR,"try to write to FIFO_RW_DISTANCE_HI : %04x", _Value); @@ -455,13 +462,12 @@ void STACKALIGN GatherPipeBursted() ProcessFifoAllDistance(); waitingForPEInterruptDisable = false; } - } return; } if (IsOnThread()) - SetOverflowStatusFromGatherPipe(); + SetCpStatus(true); // update the fifo-pointer if (fifo.CPWritePointer >= fifo.CPEnd) @@ -485,11 +491,11 @@ void STACKALIGN GatherPipeBursted() void UpdateInterrupts(u64 userdata) { - if (userdata) + if (userdata) { interruptSet = true; - INFO_LOG(COMMANDPROCESSOR,"Interrupt set"); - ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true); + INFO_LOG(COMMANDPROCESSOR,"Interrupt set"); + ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true); } else { @@ -497,7 +503,7 @@ void UpdateInterrupts(u64 userdata) INFO_LOG(COMMANDPROCESSOR,"Interrupt cleared"); ProcessorInterface::SetInterrupt(INT_CAUSE_CP, false); } - interruptWaiting = false; + interruptWaiting = false; } void UpdateInterruptsFromVideoBackend(u64 userdata) @@ -511,73 +517,75 @@ void AbortFrame() } -void SetOverflowStatusFromGatherPipe() +void SetCpStatus(bool isCPUThread) { + // overflow & underflow check fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark); - isHiWatermarkActive = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt && m_CPCtrlReg.GPReadEnable; + fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark); - if (isHiWatermarkActive) + // breakpoint + if (!isCPUThread) { - interruptSet = true; - INFO_LOG(COMMANDPROCESSOR,"Interrupt set"); - ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true); - } -} - -void SetCpStatus() -{ - // overflow & underflow check - fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark); - fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark); - - // breakpoint - if (fifo.bFF_BPEnable) - { - if (fifo.CPBreakpoint == fifo.CPReadPointer) - { - if (!fifo.bFF_Breakpoint) + if (fifo.bFF_BPEnable) + { + if (fifo.CPBreakpoint == fifo.CPReadPointer) + { + if (!fifo.bFF_Breakpoint) + { + INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %i", fifo.CPReadPointer); + fifo.bFF_Breakpoint = true; + IncrementCheckContextId(); + } + } + else { - INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %i", fifo.CPReadPointer); - fifo.bFF_Breakpoint = true; - IncrementCheckContextId(); + if (fifo.bFF_Breakpoint) + INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i", fifo.CPReadPointer); + fifo.bFF_Breakpoint = false; } - } + } else { if (fifo.bFF_Breakpoint) INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i", fifo.CPReadPointer); - fifo.bFF_Breakpoint = false; + fifo.bFF_Breakpoint = false; } - } - else - { - if (fifo.bFF_Breakpoint) - INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i", fifo.CPReadPointer); - fifo.bFF_Breakpoint = false; - } + } bool bpInt = fifo.bFF_Breakpoint && fifo.bFF_BPInt; bool ovfInt = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt; bool undfInt = fifo.bFF_LoWatermark && fifo.bFF_LoWatermarkInt; - + bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable; - isHiWatermarkActive = ovfInt && m_CPCtrlReg.GPReadEnable; + isHiWatermarkActive = ovfInt && m_CPCtrlReg.GPReadEnable; + isLoWatermarkActive = undfInt && m_CPCtrlReg.GPReadEnable; - if (interrupt != interruptSet && !interruptWaiting) - { - u64 userdata = interrupt?1:0; - if (IsOnThread()) - { - if(!interrupt || bpInt || undfInt) + if (interrupt != interruptSet && !interruptWaiting) + { + u64 userdata = interrupt?1:0; + if (IsOnThread()) + { + if (!interrupt || bpInt || undfInt || ovfInt) { - interruptWaiting = true; - CommandProcessor::UpdateInterruptsFromVideoBackend(userdata); + if (!isCPUThread) + { + // GPU thread: + interruptWaiting = true; + CommandProcessor::UpdateInterruptsFromVideoBackend(userdata); + } + else + { + // CPU thread: + interruptSet = interrupt; + INFO_LOG(COMMANDPROCESSOR,"Interrupt set"); + ProcessorInterface::SetInterrupt(INT_CAUSE_CP, interrupt); + } } - } - else - CommandProcessor::UpdateInterrupts(userdata); - } + } + else + CommandProcessor::UpdateInterrupts(userdata); + } } void ProcessFifoToLoWatermark() @@ -596,7 +604,7 @@ void ProcessFifoAllDistance() if (IsOnThread()) { while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && - fifo.CPReadWriteDistance && !AtBreakpoint() && !PixelEngine::WaitingForPEInterrupt()) + fifo.CPReadWriteDistance && !AtBreakpoint()) Common::YieldCPU(); } bProcessFifoAllDistance = false; @@ -617,15 +625,11 @@ void SetCpStatusRegister() { // Here always there is one fifo attached to the GPU m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint; - m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint) ; - m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance; + m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || AtBreakpoint() || (fifo.CPReadPointer == fifo.CPWritePointer); + m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance || AtBreakpoint() || !fifo.bFF_GPReadEnable; m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark; m_CPStatusReg.OverflowHiWatermark = fifo.bFF_HiWatermark; - // HACK to compensate for slow response to PE interrupts in Time Splitters: Future Perfect - if (IsOnThread()) - PixelEngine::ResumeWaitingForPEInterrupt(); - INFO_LOG(COMMANDPROCESSOR,"\t Read from STATUS_REGISTER : %04x", m_CPStatusReg.Hex); DEBUG_LOG(COMMANDPROCESSOR, "(r) status: iBP %s | fReadIdle %s | fCmdIdle %s | iOvF %s | iUndF %s" , m_CPStatusReg.Breakpoint ? "ON" : "OFF" @@ -638,14 +642,11 @@ void SetCpStatusRegister() void SetCpControlRegister() { - // If the new fifo is being attached We make sure there wont be SetFinish event pending. - // This protection fix eternal darkness booting, because the second SetFinish event when it is booting - // seems invalid or has a bug and hang the game. - + // If the new fifo is being attached, force an exception check + // This fixes the hang while booting Eternal Darkness if (!fifo.bFF_GPReadEnable && m_CPCtrlReg.GPReadEnable && !m_CPCtrlReg.BPEnable) { - ProcessFifoEvents(); - PixelEngine::ResetSetFinish(); + CoreTiming::ForceExceptionCheck(0); } fifo.bFF_BPInt = m_CPCtrlReg.BPInt; @@ -693,4 +694,12 @@ void SetCpClearRegister() // } } +void Update() +{ + while (VITicks > m_cpClockOrigin && fifo.isGpuReadingData && IsOnThread()) + Common::YieldCPU(); + + if (fifo.isGpuReadingData) + Common::AtomicAdd(VITicks, SystemTimers::GetTicksPerSecond() / 10000); +} } // end of namespace CommandProcessor diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.h b/Source/Core/VideoCommon/Src/CommandProcessor.h index 5d31453537..5aa49ac3e8 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.h +++ b/Source/Core/VideoCommon/Src/CommandProcessor.h @@ -31,6 +31,7 @@ namespace CommandProcessor extern SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread. extern volatile bool isPossibleWaitingSetDrawDone; //This one is used for sync gfx thread and emulator thread. extern volatile bool isHiWatermarkActive; +extern volatile bool isLoWatermarkActive; extern volatile bool interruptSet; extern volatile bool interruptWaiting; extern volatile bool interruptTokenWaiting; @@ -140,6 +141,9 @@ union UCPClearReg UCPClearReg(u16 _hex) {Hex = _hex; } }; +// Can be any number, low enough to not be below the number of clocks executed by the GPU per CP_PERIOD +const static u32 m_cpClockOrigin = 200000; + // Init void Init(); void Shutdown(); @@ -151,7 +155,7 @@ void Write16(const u16 _Data, const u32 _Address); void Read32(u32& _rReturnValue, const u32 _Address); void Write32(const u32 _Data, const u32 _Address); -void SetCpStatus(); +void SetCpStatus(bool isCPUThread = false); void GatherPipeBursted(); void UpdateInterrupts(u64 userdata); void UpdateInterruptsFromVideoBackend(u64 userdata); @@ -161,11 +165,14 @@ bool AllowIdleSkipping(); void SetCpClearRegister(); void SetCpControlRegister(); void SetCpStatusRegister(); -void SetOverflowStatusFromGatherPipe(); void ProcessFifoToLoWatermark(); void ProcessFifoAllDistance(); void ProcessFifoEvents(); void AbortFrame(); + +void Update(); +extern volatile u32 VITicks; + } // namespace CommandProcessor #endif // _COMMANDPROCESSOR_H diff --git a/Source/Core/VideoCommon/Src/DataReader.h b/Source/Core/VideoCommon/Src/DataReader.h index 06668f8bbc..03061229c0 100644 --- a/Source/Core/VideoCommon/Src/DataReader.h +++ b/Source/Core/VideoCommon/Src/DataReader.h @@ -20,6 +20,8 @@ #ifndef _DATAREADER_H #define _DATAREADER_H +#include "VertexManagerBase.h" + extern u8* g_pVideoData; #if _M_SSE >= 0x301 && !(defined __GNUC__ && !defined __SSSE3__) @@ -31,43 +33,63 @@ __forceinline void DataSkip(u32 skip) g_pVideoData += skip; } +// probably unnecessary +template <int count> +__forceinline void DataSkip() +{ + g_pVideoData += count; +} + +template <typename T> +__forceinline T DataPeek(int _uOffset) +{ + auto const result = Common::FromBigEndian(*reinterpret_cast<T*>(g_pVideoData + _uOffset)); + return result; +} + +// TODO: kill these __forceinline u8 DataPeek8(int _uOffset) { - return g_pVideoData[_uOffset]; + return DataPeek<u8>(_uOffset); } __forceinline u16 DataPeek16(int _uOffset) { - return Common::swap16(*(u16*)&g_pVideoData[_uOffset]); + return DataPeek<u16>(_uOffset); } __forceinline u32 DataPeek32(int _uOffset) { - return Common::swap32(*(u32*)&g_pVideoData[_uOffset]); + return DataPeek<u32>(_uOffset); +} + +template <typename T> +__forceinline T DataRead() +{ + auto const result = DataPeek<T>(0); + DataSkip<sizeof(T)>(); + return result; } +// TODO: kill these __forceinline u8 DataReadU8() { - return *g_pVideoData++; + return DataRead<u8>(); } __forceinline s8 DataReadS8() { - return (s8)(*g_pVideoData++); + return DataRead<s8>(); } __forceinline u16 DataReadU16() { - u16 tmp = Common::swap16(*(u16*)g_pVideoData); - g_pVideoData += 2; - return tmp; + return DataRead<u16>(); } __forceinline u32 DataReadU32() { - u32 tmp = Common::swap32(*(u32*)g_pVideoData); - g_pVideoData += 4; - return tmp; + return DataRead<u32>(); } typedef void (*DataReadU32xNfunc)(u32 *buf); @@ -120,58 +142,16 @@ __forceinline u32 DataReadU32Unswapped() return tmp; } -template<class T> -__forceinline T DataRead() -{ - T tmp = *(T*)g_pVideoData; - g_pVideoData += sizeof(T); - return tmp; -} - -template <> -__forceinline u16 DataRead() -{ - u16 tmp = Common::swap16(*(u16*)g_pVideoData); - g_pVideoData += 2; - return tmp; -} - -template <> -__forceinline s16 DataRead() -{ - s16 tmp = (s16)Common::swap16(*(u16*)g_pVideoData); - g_pVideoData += 2; - return tmp; -} - -template <> -__forceinline u32 DataRead() -{ - u32 tmp = (u32)Common::swap32(*(u32*)g_pVideoData); - g_pVideoData += 4; - return tmp; -} - -template <> -__forceinline s32 DataRead() -{ - s32 tmp = (s32)Common::swap32(*(u32*)g_pVideoData); - g_pVideoData += 4; - return tmp; -} - -__forceinline float DataReadF32() +__forceinline u8* DataGetPosition() { - union {u32 i; float f;} temp; - temp.i = Common::swap32(*(u32*)g_pVideoData); - g_pVideoData += 4; - float tmp = temp.f; - return tmp; + return g_pVideoData; } -__forceinline u8* DataGetPosition() +template <typename T> +__forceinline void DataWrite(T data) { - return g_pVideoData; + *(T*)VertexManager::s_pCurBufferPointer = data; + VertexManager::s_pCurBufferPointer += sizeof(T); } #endif diff --git a/Source/Core/VideoCommon/Src/EmuWindow.cpp b/Source/Core/VideoCommon/Src/EmuWindow.cpp index cbb0bc31ac..bf9da4190b 100644 --- a/Source/Core/VideoCommon/Src/EmuWindow.cpp +++ b/Source/Core/VideoCommon/Src/EmuWindow.cpp @@ -80,7 +80,7 @@ void FreeLookInput( UINT iMsg, WPARAM wParam ) static bool mouseLookEnabled = false; static bool mouseMoveEnabled = false; static float lastMouse[2]; - POINT point; + POINT point; switch(iMsg) { case WM_USER_KEYDOWN: @@ -133,7 +133,7 @@ void FreeLookInput( UINT iMsg, WPARAM wParam ) lastMouse[1] = (float)point.y; mouseLookEnabled= true; break; - case WM_MBUTTONDOWN: + case WM_MBUTTONDOWN: GetCursorPos(&point); lastMouse[0] = (float)point.x; lastMouse[1] = (float)point.y; @@ -205,10 +205,6 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) OnKeyDown(lParam); FreeLookInput((u32)wParam, lParam); } - else if (wParam == WIIMOTE_DISCONNECT) - { - PostMessage(m_hParent, WM_USER, wParam, lParam); - } break; // Called when a screensaver wants to show up while this window is active diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index 50aa21ebbf..c7d39844c8 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -26,6 +26,7 @@ #include "Fifo.h" #include "HW/Memmap.h" #include "Core.h" +#include "CoreTiming.h" volatile bool g_bSkipCurrentFrame = false; extern u8* g_pVideoData; @@ -42,10 +43,10 @@ static int size = 0; void Fifo_DoState(PointerWrap &p) { - p.DoArray(videoBuffer, FIFO_SIZE); - p.Do(size); - p.DoPointer(g_pVideoData, videoBuffer); - p.Do(g_bSkipCurrentFrame); + p.DoArray(videoBuffer, FIFO_SIZE); + p.Do(size); + p.DoPointer(g_pVideoData, videoBuffer); + p.Do(g_bSkipCurrentFrame); } void Fifo_PauseAndLock(bool doLock, bool unpauseOnUnlock) @@ -68,21 +69,22 @@ void Fifo_PauseAndLock(bool doLock, bool unpauseOnUnlock) void Fifo_Init() -{ - videoBuffer = (u8*)AllocateMemoryPages(FIFO_SIZE); +{ + videoBuffer = (u8*)AllocateMemoryPages(FIFO_SIZE); size = 0; GpuRunningState = false; + Common::AtomicStore(CommandProcessor::VITicks, CommandProcessor::m_cpClockOrigin); } void Fifo_Shutdown() { if (GpuRunningState) PanicAlert("Fifo shutting down while active"); - FreeMemoryPages(videoBuffer, FIFO_SIZE); + FreeMemoryPages(videoBuffer, FIFO_SIZE); } u8* GetVideoBufferStartPtr() { - return videoBuffer; + return videoBuffer; } u8* GetVideoBufferEndPtr() @@ -117,20 +119,20 @@ void EmulatorState(bool running) // Description: RunGpuLoop() sends data through this function. void ReadDataFromFifo(u8* _uData, u32 len) { - if (size + len >= FIFO_SIZE) - { + if (size + len >= FIFO_SIZE) + { int pos = (int)(g_pVideoData - videoBuffer); size -= pos; - if (size + len > FIFO_SIZE) - { - PanicAlert("FIFO out of bounds (sz = %i, at %08x)", size, pos); - } - memmove(&videoBuffer[0], &videoBuffer[pos], size); + if (size + len > FIFO_SIZE) + { + PanicAlert("FIFO out of bounds (sz = %i, len = %i at %08x)", size, len, pos); + } + memmove(&videoBuffer[0], &videoBuffer[pos], size); g_pVideoData = videoBuffer; - } + } // Copy new video instructions to videoBuffer for future use in rendering the new picture - memcpy(videoBuffer + size, _uData, len); - size += len; + memcpy(videoBuffer + size, _uData, len); + size += len; } void ResetVideoBuffer() @@ -147,39 +149,50 @@ void RunGpuLoop() std::lock_guard<std::mutex> lk(m_csHWVidOccupied); GpuRunningState = true; SCPFifoStruct &fifo = CommandProcessor::fifo; + u32 cyclesExecuted = 0; while (GpuRunningState) { g_video_backend->PeekMessages(); VideoFifo_CheckAsyncRequest(); - + CommandProcessor::SetCpStatus(); + + Common::AtomicStore(CommandProcessor::VITicks, CommandProcessor::m_cpClockOrigin); + // check if we are able to run this buffer - while (GpuRunningState && !CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint() && !PixelEngine::WaitingForPEInterrupt()) + while (GpuRunningState && !CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint()) { if (!GpuRunningState) break; fifo.isGpuReadingData = true; CommandProcessor::isPossibleWaitingSetDrawDone = fifo.bFF_GPLinkEnable ? true : false; - - u32 readPtr = fifo.CPReadPointer; - u8 *uData = Memory::GetPointer(readPtr); - if (readPtr == fifo.CPEnd) readPtr = fifo.CPBase; + if (Common::AtomicLoad(CommandProcessor::VITicks) > CommandProcessor::m_cpClockOrigin || !Core::g_CoreStartupParameter.bSyncGPU) + { + u32 readPtr = fifo.CPReadPointer; + u8 *uData = Memory::GetPointer(readPtr); + + if (readPtr == fifo.CPEnd) readPtr = fifo.CPBase; else readPtr += 32; - - _assert_msg_(COMMANDPROCESSOR, (s32)fifo.CPReadWriteDistance - 32 >= 0 , - "Negative fifo.CPReadWriteDistance = %i in FIFO Loop !\nThat can produce inestabilty in the game. Please report it.", fifo.CPReadWriteDistance - 32); - - ReadDataFromFifo(uData, 32); - - OpcodeDecoder_Run(g_bSkipCurrentFrame); - - Common::AtomicStore(fifo.CPReadPointer, readPtr); - Common::AtomicAdd(fifo.CPReadWriteDistance, -32); - if((GetVideoBufferEndPtr() - g_pVideoData) == 0) - Common::AtomicStore(fifo.SafeCPReadPointer, fifo.CPReadPointer); + + _assert_msg_(COMMANDPROCESSOR, (s32)fifo.CPReadWriteDistance - 32 >= 0 , + "Negative fifo.CPReadWriteDistance = %i in FIFO Loop !\nThat can produce instabilty in the game. Please report it.", fifo.CPReadWriteDistance - 32); + + ReadDataFromFifo(uData, 32); + + cyclesExecuted = OpcodeDecoder_Run(g_bSkipCurrentFrame); + + if (Common::AtomicLoad(CommandProcessor::VITicks) > cyclesExecuted && Core::g_CoreStartupParameter.bSyncGPU) + Common::AtomicAdd(CommandProcessor::VITicks, -(s32)cyclesExecuted); + + Common::AtomicStore(fifo.CPReadPointer, readPtr); + Common::AtomicAdd(fifo.CPReadWriteDistance, -32); + if((GetVideoBufferEndPtr() - g_pVideoData) == 0) + Common::AtomicStore(fifo.SafeCPReadPointer, fifo.CPReadPointer); + } + CommandProcessor::SetCpStatus(); // This call is pretty important in DualCore mode and must be called in the FIFO Loop. @@ -188,12 +201,18 @@ void RunGpuLoop() VideoFifo_CheckAsyncRequest(); CommandProcessor::isPossibleWaitingSetDrawDone = false; } - + fifo.isGpuReadingData = false; - if (EmuRunningState) + { + // NOTE(jsd): Calling SwitchToThread() on Windows 7 x64 is a hot spot, according to profiler. + // See https://docs.google.com/spreadsheet/ccc?key=0Ah4nh0yGtjrgdFpDeF9pS3V6RUotRVE3S3J4TGM1NlE#gid=0 + // for benchmark details. +#if 0 Common::YieldCPU(); +#endif + } else { // While the emu is paused, we still handle async requests then sleep. @@ -217,23 +236,23 @@ bool AtBreakpoint() void RunGpu() { - SCPFifoStruct &fifo = CommandProcessor::fifo; - while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint() ) - { - u8 *uData = Memory::GetPointer(fifo.CPReadPointer); - - SaveSSEState(); - LoadDefaultSSEState(); - ReadDataFromFifo(uData, 32); - OpcodeDecoder_Run(g_bSkipCurrentFrame); - LoadSSEState(); + SCPFifoStruct &fifo = CommandProcessor::fifo; + while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint() ) + { + u8 *uData = Memory::GetPointer(fifo.CPReadPointer); - //DEBUG_LOG(COMMANDPROCESSOR, "Fifo wraps to base"); + FPURoundMode::SaveSIMDState(); + FPURoundMode::LoadDefaultSIMDState(); + ReadDataFromFifo(uData, 32); + OpcodeDecoder_Run(g_bSkipCurrentFrame); + FPURoundMode::LoadSIMDState(); - if (fifo.CPReadPointer == fifo.CPEnd) fifo.CPReadPointer = fifo.CPBase; - else fifo.CPReadPointer += 32; + //DEBUG_LOG(COMMANDPROCESSOR, "Fifo wraps to base"); - fifo.CPReadWriteDistance -= 32; - } - CommandProcessor::SetCpStatus(); + if (fifo.CPReadPointer == fifo.CPEnd) fifo.CPReadPointer = fifo.CPBase; + else fifo.CPReadPointer += 32; + + fifo.CPReadWriteDistance -= 32; + } + CommandProcessor::SetCpStatus(); } diff --git a/Source/Core/VideoCommon/Src/Fifo.h b/Source/Core/VideoCommon/Src/Fifo.h index 75e7d782f5..f465db8f85 100644 --- a/Source/Core/VideoCommon/Src/Fifo.h +++ b/Source/Core/VideoCommon/Src/Fifo.h @@ -23,7 +23,7 @@ class PointerWrap; -#define FIFO_SIZE (1024*1024) +#define FIFO_SIZE (2*1024*1024) extern volatile bool g_bSkipCurrentFrame; diff --git a/Source/Core/VideoCommon/Src/FramebufferManagerBase.cpp b/Source/Core/VideoCommon/Src/FramebufferManagerBase.cpp index c883714daf..335344e229 100644 --- a/Source/Core/VideoCommon/Src/FramebufferManagerBase.cpp +++ b/Source/Core/VideoCommon/Src/FramebufferManagerBase.cpp @@ -60,12 +60,12 @@ const XFBSourceBase* const* FramebufferManagerBase::GetRealXFBSource(u32 xfbAddr m_realXFBSource->texHeight = fbHeight; // TODO: stuff only used by OGL... :/ - // OpenGL texture coordinates originate at the lower left, which is why - // sourceRc.top = fbHeight and sourceRc.bottom = 0. - m_realXFBSource->sourceRc.left = 0; - m_realXFBSource->sourceRc.top = fbHeight; - m_realXFBSource->sourceRc.right = fbWidth; - m_realXFBSource->sourceRc.bottom = 0; + // OpenGL texture coordinates originate at the lower left, which is why + // sourceRc.top = fbHeight and sourceRc.bottom = 0. + m_realXFBSource->sourceRc.left = 0; + m_realXFBSource->sourceRc.top = fbHeight; + m_realXFBSource->sourceRc.right = fbWidth; + m_realXFBSource->sourceRc.bottom = 0; // Decode YUYV data from GameCube RAM m_realXFBSource->DecodeToTexture(xfbAddr, fbWidth, fbHeight); @@ -163,13 +163,9 @@ void FramebufferManagerBase::CopyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHe // keep stale XFB data from being used ReplaceVirtualXFB(); - - g_renderer->ResetAPIState(); // reset any game specific settings // Copy EFB data to XFB and restore render target again vxfb->xfbSource->CopyEFB(Gamma); - - g_renderer->RestoreAPIState(); } FramebufferManagerBase::VirtualXFBListType::iterator FramebufferManagerBase::FindVirtualXFB(u32 xfbAddr, u32 width, u32 height) diff --git a/Source/Core/VideoCommon/Src/GenericDLCache.cpp b/Source/Core/VideoCommon/Src/GenericDLCache.cpp new file mode 100644 index 0000000000..d6826bbbde --- /dev/null +++ b/Source/Core/VideoCommon/Src/GenericDLCache.cpp @@ -0,0 +1,52 @@ +// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// TODO: Handle cache-is-full condition :p + + +#include "Common.h" +#include "DLCache.h" + +namespace DLCache +{ + +void Init() +{ +} + +void Shutdown() +{ +} + +void Clear() +{ +} + +void ProgressiveCleanup() +{ +} +} // namespace + +// NOTE - outside the namespace on purpose. +bool HandleDisplayList(u32 address, u32 size) +{ + return false; +} + +void IncrementCheckContextId() +{ +} diff --git a/Source/Core/VideoCommon/Src/GenericTextureDecoder.cpp b/Source/Core/VideoCommon/Src/GenericTextureDecoder.cpp new file mode 100644 index 0000000000..c5d14bfe9e --- /dev/null +++ b/Source/Core/VideoCommon/Src/GenericTextureDecoder.cpp @@ -0,0 +1,2210 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "Common.h" +//#include "VideoCommon.h" // to get debug logs + +#include "CPUDetect.h" +#include "TextureDecoder.h" +#include "OpenCL.h" +#include "OpenCL/OCLTextureDecoder.h" +#include "VideoConfig.h" + +#include "LookUpTables.h" + +#include <cmath> + + + +bool TexFmt_Overlay_Enable=false; +bool TexFmt_Overlay_Center=false; + +extern const char* texfmt[]; +extern const unsigned char sfont_map[]; +extern const unsigned char sfont_raw[][9*10]; + +// TRAM +// STATE_TO_SAVE + GC_ALIGNED16(u8 texMem[TMEM_SIZE]); + + +// Gamecube/Wii texture decoder + +// Decodes all known Gamecube/Wii texture formats. +// by ector + +int TexDecoder_GetTexelSizeInNibbles(int format) +{ + switch (format & 0x3f) { + case GX_TF_I4: return 1; + case GX_TF_I8: return 2; + case GX_TF_IA4: return 2; + case GX_TF_IA8: return 4; + case GX_TF_RGB565: return 4; + case GX_TF_RGB5A3: return 4; + case GX_TF_RGBA8: return 8; + case GX_TF_C4: return 1; + case GX_TF_C8: return 2; + case GX_TF_C14X2: return 4; + case GX_TF_CMPR: return 1; + case GX_CTF_R4: return 1; + case GX_CTF_RA4: return 2; + case GX_CTF_RA8: return 4; + case GX_CTF_YUVA8: return 8; + case GX_CTF_A8: return 2; + case GX_CTF_R8: return 2; + case GX_CTF_G8: return 2; + case GX_CTF_B8: return 2; + case GX_CTF_RG8: return 4; + case GX_CTF_GB8: return 4; + + case GX_TF_Z8: return 2; + case GX_TF_Z16: return 4; + case GX_TF_Z24X8: return 8; + + case GX_CTF_Z4: return 1; + case GX_CTF_Z8M: return 2; + case GX_CTF_Z8L: return 2; + case GX_CTF_Z16L: return 4; + default: return 1; + } +} + +int TexDecoder_GetTextureSizeInBytes(int width, int height, int format) +{ + return (width * height * TexDecoder_GetTexelSizeInNibbles(format)) / 2; +} + +int TexDecoder_GetBlockWidthInTexels(u32 format) +{ + switch (format) + { + case GX_TF_I4: return 8; + case GX_TF_I8: return 8; + case GX_TF_IA4: return 8; + case GX_TF_IA8: return 4; + case GX_TF_RGB565: return 4; + case GX_TF_RGB5A3: return 4; + case GX_TF_RGBA8: return 4; + case GX_TF_C4: return 8; + case GX_TF_C8: return 8; + case GX_TF_C14X2: return 4; + case GX_TF_CMPR: return 8; + case GX_CTF_R4: return 8; + case GX_CTF_RA4: return 8; + case GX_CTF_RA8: return 4; + case GX_CTF_A8: return 8; + case GX_CTF_R8: return 8; + case GX_CTF_G8: return 8; + case GX_CTF_B8: return 8; + case GX_CTF_RG8: return 4; + case GX_CTF_GB8: return 4; + case GX_TF_Z8: return 8; + case GX_TF_Z16: return 4; + case GX_TF_Z24X8: return 4; + case GX_CTF_Z4: return 8; + case GX_CTF_Z8M: return 8; + case GX_CTF_Z8L: return 8; + case GX_CTF_Z16L: return 4; + default: + ERROR_LOG(VIDEO, "Unsupported Texture Format (%08x)! (GetBlockWidthInTexels)", format); + return 8; + } +} + +int TexDecoder_GetBlockHeightInTexels(u32 format) +{ + switch (format) + { + case GX_TF_I4: return 8; + case GX_TF_I8: return 4; + case GX_TF_IA4: return 4; + case GX_TF_IA8: return 4; + case GX_TF_RGB565: return 4; + case GX_TF_RGB5A3: return 4; + case GX_TF_RGBA8: return 4; + case GX_TF_C4: return 8; + case GX_TF_C8: return 4; + case GX_TF_C14X2: return 4; + case GX_TF_CMPR: return 8; + case GX_CTF_R4: return 8; + case GX_CTF_RA4: return 4; + case GX_CTF_RA8: return 4; + case GX_CTF_A8: return 4; + case GX_CTF_R8: return 4; + case GX_CTF_G8: return 4; + case GX_CTF_B8: return 4; + case GX_CTF_RG8: return 4; + case GX_CTF_GB8: return 4; + case GX_TF_Z8: return 4; + case GX_TF_Z16: return 4; + case GX_TF_Z24X8: return 4; + case GX_CTF_Z4: return 8; + case GX_CTF_Z8M: return 4; + case GX_CTF_Z8L: return 4; + case GX_CTF_Z16L: return 4; + default: + ERROR_LOG(VIDEO, "Unsupported Texture Format (%08x)! (GetBlockHeightInTexels)", format); + return 4; + } +} + +//returns bytes +int TexDecoder_GetPaletteSize(int format) +{ + switch (format) + { + case GX_TF_C4: return 16 * 2; + case GX_TF_C8: return 256 * 2; + case GX_TF_C14X2: return 16384 * 2; + default: + return 0; + } +} + +static inline u32 decodeIA8(u16 val) +{ + int a = val >> 8; + int i = val & 0xFF; + return (a << 24) | (i << 16) | (i << 8) | i; +} + +static inline u32 decode5A3(u16 val) +{ + int r,g,b,a; + if ((val & 0x8000)) + { + a = 0xFF; + r = Convert5To8((val >> 10) & 0x1F); + g = Convert5To8((val >> 5) & 0x1F); + b = Convert5To8(val & 0x1F); + } + else + { + a = Convert3To8((val >> 12) & 0x7); + r = Convert4To8((val >> 8) & 0xF); + g = Convert4To8((val >> 4) & 0xF); + b = Convert4To8(val & 0xF); + } + return (a << 24) | (r << 16) | (g << 8) | b; +} + +static inline u32 decode5A3RGBA(u16 val) +{ + int r,g,b,a; + if ((val&0x8000)) + { + r=Convert5To8((val>>10) & 0x1f); + g=Convert5To8((val>>5 ) & 0x1f); + b=Convert5To8((val ) & 0x1f); + a=0xFF; + } + else + { + a=Convert3To8((val>>12) & 0x7); + r=Convert4To8((val>>8 ) & 0xf); + g=Convert4To8((val>>4 ) & 0xf); + b=Convert4To8((val ) & 0xf); + } + return r | (g<<8) | (b << 16) | (a << 24); +} + +static inline u32 decode565RGBA(u16 val) +{ + int r,g,b,a; + r=Convert5To8((val>>11) & 0x1f); + g=Convert6To8((val>>5 ) & 0x3f); + b=Convert5To8((val ) & 0x1f); + a=0xFF; + return r | (g<<8) | (b << 16) | (a << 24); +} + +static inline u32 decodeIA8Swapped(u16 val) +{ + int a = val & 0xFF; + int i = val >> 8; + return i | (i<<8) | (i<<16) | (a<<24); +} + + + +struct DXTBlock +{ + u16 color1; + u16 color2; + u8 lines[4]; +}; + +//inline void decodebytesC4(u32 *dst, const u8 *src, int numbytes, int tlutaddr, int tlutfmt) +inline void decodebytesC4_5A3_To_BGRA32(u32 *dst, const u8 *src, int tlutaddr) +{ + u16 *tlut = (u16*)(texMem + tlutaddr); + for (int x = 0; x < 4; x++) + { + u8 val = src[x]; + *dst++ = decode5A3(Common::swap16(tlut[val >> 4])); + *dst++ = decode5A3(Common::swap16(tlut[val & 0xF])); + } +} + +inline void decodebytesC4_5A3_To_rgba32(u32 *dst, const u8 *src, int tlutaddr) +{ + u16 *tlut = (u16*)(texMem + tlutaddr); + for (int x = 0; x < 4; x++) + { + u8 val = src[x]; + *dst++ = decode5A3RGBA(Common::swap16(tlut[val >> 4])); + *dst++ = decode5A3RGBA(Common::swap16(tlut[val & 0xF])); + } +} + +inline void decodebytesC4_To_Raw16(u16* dst, const u8* src, int tlutaddr) +{ + u16* tlut = (u16*)(texMem+tlutaddr); + for (int x = 0; x < 4; x++) + { + u8 val = src[x]; + *dst++ = Common::swap16(tlut[val >> 4]); + *dst++ = Common::swap16(tlut[val & 0xF]); + } +} + +inline void decodebytesC4IA8_To_RGBA(u32* dst, const u8* src, int tlutaddr) +{ + u16* tlut = (u16*)(texMem+tlutaddr); + for (int x = 0; x < 4; x++) + { + u8 val = src[x]; + *dst++ = decodeIA8Swapped(tlut[val >> 4]); + *dst++ = decodeIA8Swapped(tlut[val & 0xF]); + } +} + +inline void decodebytesC4RGB565_To_RGBA(u32* dst, const u8* src, int tlutaddr) +{ + u16* tlut = (u16*)(texMem+tlutaddr); + for (int x = 0; x < 4; x++) + { + u8 val = src[x]; + *dst++ = decode565RGBA(Common::swap16(tlut[val >> 4])); + *dst++ = decode565RGBA(Common::swap16(tlut[val & 0xF])); + } +} + +//inline void decodebytesC8(u32 *dst, const u8 *src, int numbytes, int tlutaddr, int tlutfmt) +inline void decodebytesC8_5A3_To_BGRA32(u32 *dst, const u8 *src, int tlutaddr) +{ + u16 *tlut = (u16*)(texMem + tlutaddr); + for (int x = 0; x < 8; x++) + { + u8 val = src[x]; + *dst++ = decode5A3(Common::swap16(tlut[val])); + } +} + +inline void decodebytesC8_5A3_To_RGBA32(u32 *dst, const u8 *src, int tlutaddr) +{ + u16 *tlut = (u16*)(texMem + tlutaddr); + for (int x = 0; x < 8; x++) + { + u8 val = src[x]; + *dst++ = decode5A3RGBA(Common::swap16(tlut[val])); + } +} + +inline void decodebytesC8_To_Raw16(u16* dst, const u8* src, int tlutaddr) +{ + u16* tlut = (u16*)(texMem + tlutaddr); + for (int x = 0; x < 8; x++) + { + u8 val = src[x]; + *dst++ = Common::swap16(tlut[val]); + } +} + +inline void decodebytesC8IA8_To_RGBA(u32* dst, const u8* src, int tlutaddr) +{ + u16* tlut = (u16*)(texMem + tlutaddr); + for (int x = 0; x < 8; x++) + { + *dst++ = decodeIA8Swapped(tlut[src[x]]); + } +} + +inline void decodebytesC8RGB565_To_RGBA(u32* dst, const u8* src, int tlutaddr) +{ + u16* tlut = (u16*)(texMem + tlutaddr); + for (int x = 0; x < 8; x++) + { + *dst++ = decode565RGBA(Common::swap16(tlut[src[x]])); + } +} + +inline void decodebytesC14X2_5A3_To_BGRA32(u32 *dst, const u16 *src, int tlutaddr) +{ + u16 *tlut = (u16*)(texMem + tlutaddr); + for (int x = 0; x < 4; x++) + { + u16 val = Common::swap16(src[x]); + *dst++ = decode5A3(Common::swap16(tlut[(val & 0x3FFF)])); + } +} + +inline void decodebytesC14X2_5A3_To_RGBA(u32 *dst, const u16 *src, int tlutaddr) +{ + u16 *tlut = (u16*)(texMem + tlutaddr); + for (int x = 0; x < 4; x++) + { + u16 val = Common::swap16(src[x]); + *dst++ = decode5A3RGBA(Common::swap16(tlut[(val & 0x3FFF)])); + } +} + +inline void decodebytesC14X2_To_Raw16(u16* dst, const u16* src, int tlutaddr) +{ + u16* tlut = (u16*)(texMem + tlutaddr); + for (int x = 0; x < 4; x++) + { + u16 val = Common::swap16(src[x]); + *dst++ = Common::swap16(tlut[(val & 0x3FFF)]); + } +} + +inline void decodebytesC14X2IA8_To_RGBA(u32* dst, const u16* src, int tlutaddr) +{ + u16* tlut = (u16*)(texMem + tlutaddr); + for (int x = 0; x < 4; x++) + { + u16 val = Common::swap16(src[x]); + *dst++ = decodeIA8Swapped(tlut[(val & 0x3FFF)]); + } +} + +inline void decodebytesC14X2rgb565_To_RGBA(u32* dst, const u16* src, int tlutaddr) +{ + u16* tlut = (u16*)(texMem + tlutaddr); + for (int x = 0; x < 4; x++) + { + u16 val = Common::swap16(src[x]); + *dst++ = decode565RGBA(Common::swap16(tlut[(val & 0x3FFF)])); + } +} + +// Needs more speed. +inline void decodebytesIA4(u16 *dst, const u8 *src) +{ + for (int x = 0; x < 8; x++) + { + const u8 val = src[x]; + u8 a = Convert4To8(val >> 4); + u8 l = Convert4To8(val & 0xF); + dst[x] = (a << 8) | l; + } +} + +inline void decodebytesIA4RGBA(u32 *dst, const u8 *src) +{ + for (int x = 0; x < 8; x++) + { + const u8 val = src[x]; + u8 a = Convert4To8(val >> 4); + u8 l = Convert4To8(val & 0xF); + dst[x] = (a << 24) | l << 16 | l << 8 | l; + } +} + +inline void decodebytesRGB5A3(u32 *dst, const u16 *src) +{ +#if 0 + for (int x = 0; x < 4; x++) + dst[x] = decode5A3(Common::swap16(src[x])); +#else + dst[0] = decode5A3(Common::swap16(src[0])); + dst[1] = decode5A3(Common::swap16(src[1])); + dst[2] = decode5A3(Common::swap16(src[2])); + dst[3] = decode5A3(Common::swap16(src[3])); +#endif +} + +inline void decodebytesRGB5A3rgba(u32 *dst, const u16 *src) +{ +#if 0 + for (int x = 0; x < 4; x++) + dst[x] = decode5A3RGBA(Common::swap16(src[x])); +#else + dst[0] = decode5A3RGBA(Common::swap16(src[0])); + dst[1] = decode5A3RGBA(Common::swap16(src[1])); + dst[2] = decode5A3RGBA(Common::swap16(src[2])); + dst[3] = decode5A3RGBA(Common::swap16(src[3])); +#endif +} + +// This one is used by many video formats. It'd therefore be good if it was fast. +// Needs more speed. +inline void decodebytesARGB8_4(u32 *dst, const u16 *src, const u16 *src2) +{ +#if 0 + for (int x = 0; x < 4; x++) + dst[x] = Common::swap32((src2[x] << 16) | src[x]); +#else + dst[0] = Common::swap32((src2[0] << 16) | src[0]); + dst[1] = Common::swap32((src2[1] << 16) | src[1]); + dst[2] = Common::swap32((src2[2] << 16) | src[2]); + dst[3] = Common::swap32((src2[3] << 16) | src[3]); +#endif + + // This can probably be done in a few SSE pack/unpack instructions + pshufb + // some unpack instruction x2: + // ABABABABABABABAB 1212121212121212 -> + // AB12AB12AB12AB12 AB12AB12AB12AB12 + // 2x pshufb-> + // 21BA21BA21BA21BA 21BA21BA21BA21BA + // and we are done. +} + +inline void decodebytesARGB8_4ToRgba(u32 *dst, const u16 *src, const u16 * src2) +{ +#if 0 + for (int x = 0; x < 4; x++) { + dst[x] = ((src[x] & 0xFF) << 24) | ((src[x] & 0xFF00)>>8) | (src2[x] << 8); + } +#else + dst[0] = ((src[0] & 0xFF) << 24) | ((src[0] & 0xFF00)>>8) | (src2[0] << 8); + dst[1] = ((src[1] & 0xFF) << 24) | ((src[1] & 0xFF00)>>8) | (src2[1] << 8); + dst[2] = ((src[2] & 0xFF) << 24) | ((src[2] & 0xFF00)>>8) | (src2[2] << 8); + dst[3] = ((src[3] & 0xFF) << 24) | ((src[3] & 0xFF00)>>8) | (src2[3] << 8); +#endif +} + +inline u32 makecol(int r, int g, int b, int a) +{ + return (a << 24)|(r << 16)|(g << 8)|b; +} + +inline u32 makeRGBA(int r, int g, int b, int a) +{ + return (a<<24)|(b<<16)|(g<<8)|r; +} + +void decodeDXTBlock(u32 *dst, const DXTBlock *src, int pitch) +{ + // S3TC Decoder (Note: GCN decodes differently from PC so we can't use native support) + // Needs more speed. + u16 c1 = Common::swap16(src->color1); + u16 c2 = Common::swap16(src->color2); + int blue1 = Convert5To8(c1 & 0x1F); + int blue2 = Convert5To8(c2 & 0x1F); + int green1 = Convert6To8((c1 >> 5) & 0x3F); + int green2 = Convert6To8((c2 >> 5) & 0x3F); + int red1 = Convert5To8((c1 >> 11) & 0x1F); + int red2 = Convert5To8((c2 >> 11) & 0x1F); + int colors[4]; + colors[0] = makecol(red1, green1, blue1, 255); + colors[1] = makecol(red2, green2, blue2, 255); + if (c1 > c2) + { + int blue3 = ((blue2 - blue1) >> 1) - ((blue2 - blue1) >> 3); + int green3 = ((green2 - green1) >> 1) - ((green2 - green1) >> 3); + int red3 = ((red2 - red1) >> 1) - ((red2 - red1) >> 3); + colors[2] = makecol(red1 + red3, green1 + green3, blue1 + blue3, 255); + colors[3] = makecol(red2 - red3, green2 - green3, blue2 - blue3, 255); + } + else + { + colors[2] = makecol((red1 + red2 + 1) / 2, // Average + (green1 + green2 + 1) / 2, + (blue1 + blue2 + 1) / 2, 255); + colors[3] = makecol(red2, green2, blue2, 0); // Color2 but transparent + } + + for (int y = 0; y < 4; y++) + { + int val = src->lines[y]; + for (int x = 0; x < 4; x++) + { + dst[x] = colors[(val >> 6) & 3]; + val <<= 2; + } + dst += pitch; + } +} + +void decodeDXTBlockRGBA(u32 *dst, const DXTBlock *src, int pitch) +{ + // S3TC Decoder (Note: GCN decodes differently from PC so we can't use native support) + // Needs more speed. + u16 c1 = Common::swap16(src->color1); + u16 c2 = Common::swap16(src->color2); + int blue1 = Convert5To8(c1 & 0x1F); + int blue2 = Convert5To8(c2 & 0x1F); + int green1 = Convert6To8((c1 >> 5) & 0x3F); + int green2 = Convert6To8((c2 >> 5) & 0x3F); + int red1 = Convert5To8((c1 >> 11) & 0x1F); + int red2 = Convert5To8((c2 >> 11) & 0x1F); + int colors[4]; + colors[0] = makeRGBA(red1, green1, blue1, 255); + colors[1] = makeRGBA(red2, green2, blue2, 255); + if (c1 > c2) + { + int blue3 = ((blue2 - blue1) >> 1) - ((blue2 - blue1) >> 3); + int green3 = ((green2 - green1) >> 1) - ((green2 - green1) >> 3); + int red3 = ((red2 - red1) >> 1) - ((red2 - red1) >> 3); + colors[2] = makeRGBA(red1 + red3, green1 + green3, blue1 + blue3, 255); + colors[3] = makeRGBA(red2 - red3, green2 - green3, blue2 - blue3, 255); + } + else + { + colors[2] = makeRGBA((red1 + red2 + 1) / 2, // Average + (green1 + green2 + 1) / 2, + (blue1 + blue2 + 1) / 2, 255); + colors[3] = makeRGBA(red2, green2, blue2, 0); // Color2 but transparent + } + + for (int y = 0; y < 4; y++) + { + int val = src->lines[y]; + for (int x = 0; x < 4; x++) + { + dst[x] = colors[(val >> 6) & 3]; + val <<= 2; + } + dst += pitch; + } +} + +#if 0 // TODO - currently does not handle transparency correctly and causes problems when texture dimensions are not multiples of 8 +static void copyDXTBlock(u8* dst, const u8* src) +{ + ((u16*)dst)[0] = Common::swap16(((u16*)src)[0]); + ((u16*)dst)[1] = Common::swap16(((u16*)src)[1]); + u32 pixels = ((u32*)src)[1]; + // A bit of trickiness here: the row are in the same order + // between the two formats, but the ordering within the rows + // is reversed. + pixels = ((pixels >> 4) & 0x0F0F0F0F) | ((pixels << 4) & 0xF0F0F0F0); + pixels = ((pixels >> 2) & 0x33333333) | ((pixels << 2) & 0xCCCCCCCC); + ((u32*)dst)[1] = pixels; +} +#endif + +static PC_TexFormat GetPCFormatFromTLUTFormat(int tlutfmt) +{ + switch (tlutfmt) + { + case 0: return PC_TEX_FMT_IA8; // IA8 + case 1: return PC_TEX_FMT_RGB565; // RGB565 + case 2: return PC_TEX_FMT_BGRA32; // RGB5A3: This TLUT format requires + // extra work to decode. + } + return PC_TEX_FMT_NONE; // Error +} + +PC_TexFormat GetPC_TexFormat(int texformat, int tlutfmt) +{ + switch (texformat) + { + case GX_TF_C4: + return GetPCFormatFromTLUTFormat(tlutfmt); + case GX_TF_I4: + return PC_TEX_FMT_IA8; + case GX_TF_I8: // speed critical + return PC_TEX_FMT_IA8; + case GX_TF_C8: + return GetPCFormatFromTLUTFormat(tlutfmt); + case GX_TF_IA4: + return PC_TEX_FMT_IA4_AS_IA8; + case GX_TF_IA8: + return PC_TEX_FMT_IA8; + case GX_TF_C14X2: + return GetPCFormatFromTLUTFormat(tlutfmt); + case GX_TF_RGB565: + return PC_TEX_FMT_RGB565; + case GX_TF_RGB5A3: + return PC_TEX_FMT_BGRA32; + case GX_TF_RGBA8: // speed critical + return PC_TEX_FMT_BGRA32; + case GX_TF_CMPR: // speed critical + // The metroid games use this format almost exclusively. + { + return PC_TEX_FMT_BGRA32; + } + } + + // The "copy" texture formats, too? + return PC_TEX_FMT_NONE; +} + + +//switch endianness, unswizzle +//TODO: to save memory, don't blindly convert everything to argb8888 +//also ARGB order needs to be swapped later, to accommodate modern hardware better +//need to add DXT support too +PC_TexFormat TexDecoder_Decode_real(u8 *dst, const u8 *src, int width, int height, int texformat, int tlutaddr, int tlutfmt) +{ + const int Wsteps4 = (width + 3) / 4; + const int Wsteps8 = (width + 7) / 8; + + switch (texformat) + { + case GX_TF_C4: + if (tlutfmt == 2) + { + // Special decoding is required for TLUT format 5A3 + for (int y = 0; y < height; y += 8) + for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = yStep * 8; iy < 8; iy++, xStep++) + decodebytesC4_5A3_To_BGRA32((u32*)dst + (y + iy) * width + x, src + 4 * xStep, tlutaddr); + } + else + { + for (int y = 0; y < height; y += 8) + for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = yStep * 8; iy < 8; iy++, xStep++) + decodebytesC4_To_Raw16((u16*)dst + (y + iy) * width + x, src + 4 * xStep, tlutaddr); + } + return GetPCFormatFromTLUTFormat(tlutfmt); + case GX_TF_I4: + { + for (int y = 0; y < height; y += 8) + for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = yStep * 8 ; iy < 8; iy++,xStep++) + for (int ix = 0; ix < 4; ix++) + { + int val = src[4 * xStep + ix]; + dst[(y + iy) * width + x + ix * 2] = Convert4To8(val >> 4); + dst[(y + iy) * width + x + ix * 2 + 1] = Convert4To8(val & 0xF); + } + } + return PC_TEX_FMT_I4_AS_I8; + case GX_TF_I8: // speed critical + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + ((u64*)(dst + (y + iy) * width + x))[0] = ((u64*)(src + 8 * xStep))[0]; + } + return PC_TEX_FMT_I8; + case GX_TF_C8: + if (tlutfmt == 2) + { + // Special decoding is required for TLUT format 5A3 + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + decodebytesC8_5A3_To_BGRA32((u32*)dst + (y + iy) * width + x, src + 8 * xStep, tlutaddr); + } + else + { + + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + decodebytesC8_To_Raw16((u16*)dst + (y + iy) * width + x, src + 8 * xStep, tlutaddr); + } + } + return GetPCFormatFromTLUTFormat(tlutfmt); + case GX_TF_IA4: + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + decodebytesIA4((u16*)dst + (y + iy) * width + x, src + 8 * xStep); + } + return PC_TEX_FMT_IA4_AS_IA8; + case GX_TF_IA8: + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = yStep * 4; iy < 4; iy++, xStep++) + { + u16 *ptr = (u16 *)dst + (y + iy) * width + x; + u16 *s = (u16 *)(src + 8 * xStep); + for(int j = 0; j < 4; j++) + *ptr++ = Common::swap16(*s++); + } + } + return PC_TEX_FMT_IA8; + case GX_TF_C14X2: + if (tlutfmt == 2) + { + // Special decoding is required for TLUT format 5A3 + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + decodebytesC14X2_5A3_To_BGRA32((u32*)dst + (y + iy) * width + x, (u16*)(src + 8 * xStep), tlutaddr); + } + else + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + decodebytesC14X2_To_Raw16((u16*)dst + (y + iy) * width + x,(u16*)(src + 8 * xStep), tlutaddr); + } + return GetPCFormatFromTLUTFormat(tlutfmt); + case GX_TF_RGB565: + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + { + u16 *ptr = (u16 *)dst + (y + iy) * width + x; + u16 *s = (u16 *)(src + 8 * xStep); + for(int j = 0; j < 4; j++) + *ptr++ = Common::swap16(*s++); + } + } + return PC_TEX_FMT_RGB565; + case GX_TF_RGB5A3: + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + //decodebytesRGB5A3((u32*)dst+(y+iy)*width+x, (u16*)src, 4); + decodebytesRGB5A3((u32*)dst+(y+iy)*width+x, (u16*)(src + 8 * xStep)); + } + return PC_TEX_FMT_BGRA32; + case GX_TF_RGBA8: // speed critical + { + for (int y = 0; y < height; y += 4) + { + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + { + const u8* src2 = src + 64 * yStep; + for (int iy = 0; iy < 4; iy++) + decodebytesARGB8_4((u32*)dst + (y+iy)*width + x, (u16*)src2 + 4 * iy, (u16*)src2 + 4 * iy + 16); + } + } + } + return PC_TEX_FMT_BGRA32; + case GX_TF_CMPR: // speed critical + // The metroid games use this format almost exclusively. + { +#if 0 // TODO - currently does not handle transparency correctly and causes problems when texture dimensions are not multiples of 8 + // 11111111 22222222 55555555 66666666 + // 33333333 44444444 77777777 88888888 + for (int y = 0; y < height; y += 8) + { + for (int x = 0; x < width; x += 8) + { + copyDXTBlock(dst+(y/2)*width+x*2, src); + src += 8; + copyDXTBlock(dst+(y/2)*width+x*2+8, src); + src += 8; + copyDXTBlock(dst+(y/2+2)*width+x*2, src); + src += 8; + copyDXTBlock(dst+(y/2+2)*width+x*2+8, src); + src += 8; + } + } + return PC_TEX_FMT_DXT1; +#else + for (int y = 0; y < height; y += 8) + { + for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8, yStep++) + { + const u8* src2 = src + 4 * sizeof(DXTBlock) * yStep; + decodeDXTBlock((u32*)dst + y * width + x, (DXTBlock*)src2, width); + src2 += sizeof(DXTBlock); + decodeDXTBlock((u32*)dst + y * width + x + 4, (DXTBlock*)src2, width); + src2 += sizeof(DXTBlock); + decodeDXTBlock((u32*)dst + (y + 4) * width + x, (DXTBlock*)src2, width); + src2 += sizeof(DXTBlock); + decodeDXTBlock((u32*)dst + (y + 4) * width + x + 4, (DXTBlock*)src2, width); + } + } +#endif + return PC_TEX_FMT_BGRA32; + } + } + + // The "copy" texture formats, too? + return PC_TEX_FMT_NONE; +} + + + +// JSD 01/06/11: +// TODO: we really should ensure BOTH the source and destination addresses are aligned to 16-byte boundaries to +// squeeze out a little more performance. _mm_loadu_si128/_mm_storeu_si128 is slower than _mm_load_si128/_mm_store_si128 +// because they work on unaligned addresses. The processor is free to make the assumption that addresses are multiples +// of 16 in the aligned case. +// TODO: complete SSE2 optimization of less often used texture formats. +// TODO: refactor algorithms using _mm_loadl_epi64 unaligned loads to prefer 128-bit aligned loads. + +PC_TexFormat TexDecoder_Decode_RGBA(u32 * dst, const u8 * src, int width, int height, int texformat, int tlutaddr, int tlutfmt) +{ + + const int Wsteps4 = (width + 3) / 4; + const int Wsteps8 = (width + 7) / 8; + + switch (texformat) + { + case GX_TF_C4: + if (tlutfmt == 2) + { + // Special decoding is required for TLUT format 5A3 + for (int y = 0; y < height; y += 8) + for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8,yStep++) + for (int iy = 0, xStep = 8 * yStep; iy < 8; iy++,xStep++) + decodebytesC4_5A3_To_rgba32(dst + (y + iy) * width + x, src + 4 * xStep, tlutaddr); + } + else if(tlutfmt == 0) + { + for (int y = 0; y < height; y += 8) + for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8,yStep++) + for (int iy = 0, xStep = 8 * yStep; iy < 8; iy++,xStep++) + decodebytesC4IA8_To_RGBA(dst + (y + iy) * width + x, src + 4 * xStep, tlutaddr); + } + else + { + for (int y = 0; y < height; y += 8) + for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8,yStep++) + for (int iy = 0, xStep = 8 * yStep; iy < 8; iy++,xStep++) + decodebytesC4RGB565_To_RGBA(dst + (y + iy) * width + x, src + 4 * xStep, tlutaddr); + } + break; + case GX_TF_I4: + { + // Reference C implementation: + for (int y = 0; y < height; y += 8) + for (int x = 0; x < width; x += 8) + for (int iy = 0; iy < 8; iy++, src += 4) + for (int ix = 0; ix < 4; ix++) + { + int val = src[ix]; + u8 i1 = Convert4To8(val >> 4); + u8 i2 = Convert4To8(val & 0xF); + memset(dst+(y + iy) * width + x + ix * 2 , i1,4); + memset(dst+(y + iy) * width + x + ix * 2 + 1 , i2,4); + } + } + break; + case GX_TF_I8: // speed critical + { + // Reference C implementation + for (int y = 0; y < height; y += 4) + for (int x = 0; x < width; x += 8) + for (int iy = 0; iy < 4; ++iy, src += 8) + { + u32 * newdst = dst + (y + iy)*width+x; + const u8 * newsrc = src; + u8 srcval; + + srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); + srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); + srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); + srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); + srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); + srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); + srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); + srcval = newsrc[0]; newdst[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); + } + } + break; + case GX_TF_C8: + if (tlutfmt == 2) + { + // Special decoding is required for TLUT format 5A3 + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + decodebytesC8_5A3_To_RGBA32((u32*)dst + (y + iy) * width + x, src + 8 * xStep, tlutaddr); + } + else if(tlutfmt == 0) + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + decodebytesC8IA8_To_RGBA(dst + (y + iy) * width + x, src + 8 * xStep, tlutaddr); + } + else + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + decodebytesC8RGB565_To_RGBA(dst + (y + iy) * width + x, src + 8 * xStep, tlutaddr); + + } + break; + case GX_TF_IA4: + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + decodebytesIA4RGBA(dst + (y + iy) * width + x, src + 8 * xStep); + } + break; + case GX_TF_IA8: + { + // Reference C implementation: + for (int y = 0; y < height; y += 4) + for (int x = 0; x < width; x += 4) + for (int iy = 0; iy < 4; iy++, src += 8) + { + u32 *ptr = dst + (y + iy) * width + x; + u16 *s = (u16 *)src; + ptr[0] = decodeIA8Swapped(s[0]); + ptr[1] = decodeIA8Swapped(s[1]); + ptr[2] = decodeIA8Swapped(s[2]); + ptr[3] = decodeIA8Swapped(s[3]); + } + } + break; + case GX_TF_C14X2: + if (tlutfmt == 2) + { + // Special decoding is required for TLUT format 5A3 + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + decodebytesC14X2_5A3_To_BGRA32(dst + (y + iy) * width + x, (u16*)(src + 8 * xStep), tlutaddr); + } + else if (tlutfmt == 0) + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + decodebytesC14X2IA8_To_RGBA(dst + (y + iy) * width + x, (u16*)(src + 8 * xStep), tlutaddr); + } + else + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + decodebytesC14X2rgb565_To_RGBA(dst + (y + iy) * width + x, (u16*)(src + 8 * xStep), tlutaddr); + } + break; + case GX_TF_RGB565: + { + // Reference C implementation. + for (int y = 0; y < height; y += 4) + for (int x = 0; x < width; x += 4) + for (int iy = 0; iy < 4; iy++, src += 8) + { + u32 *ptr = dst + (y + iy) * width + x; + u16 *s = (u16 *)src; + for(int j = 0; j < 4; j++) + *ptr++ = decode565RGBA(Common::swap16(*s++)); + } + } + break; + case GX_TF_RGB5A3: + { + // Reference C implementation: + for (int y = 0; y < height; y += 4) + for (int x = 0; x < width; x += 4) + for (int iy = 0; iy < 4; iy++, src += 8) + decodebytesRGB5A3rgba(dst+(y+iy)*width+x, (u16*)src); + } + break; + case GX_TF_RGBA8: // speed critical + { + // Reference C implementation. + for (int y = 0; y < height; y += 4) + for (int x = 0; x < width; x += 4) + { + for (int iy = 0; iy < 4; iy++) + decodebytesARGB8_4ToRgba(dst + (y+iy)*width + x, (u16*)src + 4 * iy, (u16*)src + 4 * iy + 16); + src += 64; + } + } + break; + case GX_TF_CMPR: // speed critical + // The metroid games use this format almost exclusively. + { + for (int y = 0; y < height; y += 8) + { + for (int x = 0; x < width; x += 8) + { + decodeDXTBlockRGBA((u32*)dst + y * width + x, (DXTBlock*)src, width); + src += sizeof(DXTBlock); + decodeDXTBlockRGBA((u32*)dst + y * width + x + 4, (DXTBlock*)src, width); + src += sizeof(DXTBlock); + decodeDXTBlockRGBA((u32*)dst + (y + 4) * width + x, (DXTBlock*)src, width); + src += sizeof(DXTBlock); + decodeDXTBlockRGBA((u32*)dst + (y + 4) * width + x + 4, (DXTBlock*)src, width); + src += sizeof(DXTBlock); + } + } + break; + } + } + + // The "copy" texture formats, too? + return PC_TEX_FMT_RGBA32; +} + + + + +void TexDecoder_SetTexFmtOverlayOptions(bool enable, bool center) +{ + TexFmt_Overlay_Enable = enable; + TexFmt_Overlay_Center = center; +} + +PC_TexFormat TexDecoder_Decode(u8 *dst, const u8 *src, int width, int height, int texformat, int tlutaddr, int tlutfmt,bool rgbaOnly) +{ + PC_TexFormat retval = TexDecoder_Decode_OpenCL(dst, src, + width, height, texformat, tlutaddr, tlutfmt, rgbaOnly); + if (retval == PC_TEX_FMT_NONE) + retval = rgbaOnly ? TexDecoder_Decode_RGBA((u32*)dst, src, + width, height, texformat, tlutaddr, tlutfmt) + : TexDecoder_Decode_real(dst, src, + width, height, texformat, tlutaddr, tlutfmt); + + if ((!TexFmt_Overlay_Enable)|| (retval == PC_TEX_FMT_NONE)) + return retval; + + int w = min(width, 40); + int h = min(height, 10); + + int xoff = (width - w) >> 1; + int yoff = (height - h) >> 1; + + if (!TexFmt_Overlay_Center) + { + xoff=0; + yoff=0; + } + + const char* fmt = texfmt[texformat&15]; + while (*fmt) + { + int xcnt = 0; + int nchar = sfont_map[(int)*fmt]; + + const unsigned char *ptr = sfont_raw[nchar]; // each char is up to 9x10 + + for (int x = 0; x < 9;x++) + { + if (ptr[x] == 0x78) + break; + xcnt++; + } + + for (int y=0; y < 10; y++) + { + for (int x=0; x < xcnt; x++) + { + switch(retval) + { + case PC_TEX_FMT_I8: + { + // TODO: Is this an acceptable way to draw in I8? + u8 *dtp = (u8*)dst; + dtp[(y + yoff) * width + x + xoff] = ptr[x] ? 0xFF : 0x88; + break; + } + case PC_TEX_FMT_IA8: + case PC_TEX_FMT_IA4_AS_IA8: + { + u16 *dtp = (u16*)dst; + dtp[(y + yoff) * width + x + xoff] = ptr[x] ? 0xFFFF : 0xFF00; + break; + } + case PC_TEX_FMT_RGB565: + { + u16 *dtp = (u16*)dst; + dtp[(y + yoff)*width + x + xoff] = ptr[x] ? 0xFFFF : 0x0000; + break; + } + default: + case PC_TEX_FMT_BGRA32: + { + int *dtp = (int*)dst; + dtp[(y + yoff) * width + x + xoff] = ptr[x] ? 0xFFFFFFFF : 0xFF000000; + break; + } + } + } + ptr += 9; + } + xoff += xcnt; + fmt++; + } + + return retval; +} + + + +void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth, int texformat, int tlutaddr, int tlutfmt) +{ + /* General formula for computing texture offset + // + u16 sBlk = s / blockWidth; + u16 tBlk = t / blockHeight; + u16 widthBlks = (width / blockWidth) + 1; + u32 base = (tBlk * widthBlks + sBlk) * blockWidth * blockHeight; + u16 blkS = s & (blockWidth - 1); + u16 blkT = t & (blockHeight - 1); + u32 blkOff = blkT * blockWidth + blkS; + */ + + switch (texformat) + { + case GX_TF_C4: + { + u16 sBlk = s >> 3; + u16 tBlk = t >> 3; + u16 widthBlks = (imageWidth >> 3) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 5; + u16 blkS = s & 7; + u16 blkT = t & 7; + u32 blkOff = (blkT << 3) + blkS; + + int rs = (blkOff & 1)?0:4; + u32 offset = base + (blkOff >> 1); + + u8 val = (*(src + offset) >> rs) & 0xF; + u16 *tlut = (u16*)(texMem + tlutaddr); + + switch (tlutfmt) + { + case 0: + *((u32*)dst) = decodeIA8Swapped(tlut[val]); + break; + case 1: + *((u32*)dst) = decode565RGBA(Common::swap16(tlut[val])); + break; + case 2: + *((u32*)dst) = decode5A3RGBA(Common::swap16(tlut[val])); + break; + } + } + break; + case GX_TF_I4: + { + u16 sBlk = s >> 3; + u16 tBlk = t >> 3; + u16 widthBlks = (imageWidth >> 3) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 5; + u16 blkS = s & 7; + u16 blkT = t & 7; + u32 blkOff = (blkT << 3) + blkS; + + int rs = (blkOff & 1)?0:4; + u32 offset = base + (blkOff >> 1); + + u8 val = (*(src + offset) >> rs) & 0xF; + val = Convert4To8(val); + dst[0] = val; + dst[1] = val; + dst[2] = val; + dst[3] = val; + } + break; + case GX_TF_I8: + { + u16 sBlk = s >> 3; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 3) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 5; + u16 blkS = s & 7; + u16 blkT = t & 3; + u32 blkOff = (blkT << 3) + blkS; + + u8 val = *(src + base + blkOff); + dst[0] = val; + dst[1] = val; + dst[2] = val; + dst[3] = val; + } + break; + case GX_TF_C8: + { + u16 sBlk = s >> 3; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 3) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 5; + u16 blkS = s & 7; + u16 blkT = t & 3; + u32 blkOff = (blkT << 3) + blkS; + + u8 val = *(src + base + blkOff); + u16 *tlut = (u16*)(texMem + tlutaddr); + + switch (tlutfmt) + { + case 0: + *((u32*)dst) = decodeIA8Swapped(tlut[val]); + break; + case 1: + *((u32*)dst) = decode565RGBA(Common::swap16(tlut[val])); + break; + case 2: + *((u32*)dst) = decode5A3RGBA(Common::swap16(tlut[val])); + break; + } + } + break; + case GX_TF_IA4: + { + u16 sBlk = s >> 3; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 3) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 5; + u16 blkS = s & 7; + u16 blkT = t & 3; + u32 blkOff = (blkT << 3) + blkS; + + u8 val = *(src + base + blkOff); + const u8 a = Convert4To8(val>>4); + const u8 l = Convert4To8(val&0xF); + dst[0] = l; + dst[1] = l; + dst[2] = l; + dst[3] = a; + } + break; + case GX_TF_IA8: + { + u16 sBlk = s >> 2; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 2) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 4; + u16 blkS = s & 3; + u16 blkT = t & 3; + u32 blkOff = (blkT << 2) + blkS; + + u32 offset = (base + blkOff) << 1; + const u16* valAddr = (u16*)(src + offset); + + *((u32*)dst) = decodeIA8Swapped(*valAddr); + } + break; + case GX_TF_C14X2: + { + u16 sBlk = s >> 2; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 2) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 4; + u16 blkS = s & 3; + u16 blkT = t & 3; + u32 blkOff = (blkT << 2) + blkS; + + u32 offset = (base + blkOff) << 1; + const u16* valAddr = (u16*)(src + offset); + + u16 val = Common::swap16(*valAddr) & 0x3FFF; + u16 *tlut = (u16*)(texMem + tlutaddr); + + switch (tlutfmt) + { + case 0: + *((u32*)dst) = decodeIA8Swapped(tlut[val]); + break; + case 1: + *((u32*)dst) = decode565RGBA(Common::swap16(tlut[val])); + break; + case 2: + *((u32*)dst) = decode5A3RGBA(Common::swap16(tlut[val])); + break; + } + } + break; + case GX_TF_RGB565: + { + u16 sBlk = s >> 2; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 2) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 4; + u16 blkS = s & 3; + u16 blkT = t & 3; + u32 blkOff = (blkT << 2) + blkS; + + u32 offset = (base + blkOff) << 1; + const u16* valAddr = (u16*)(src + offset); + + *((u32*)dst) = decode565RGBA(Common::swap16(*valAddr)); + } + break; + case GX_TF_RGB5A3: + { + u16 sBlk = s >> 2; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 2) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 4; + u16 blkS = s & 3; + u16 blkT = t & 3; + u32 blkOff = (blkT << 2) + blkS; + + u32 offset = (base + blkOff) << 1; + const u16* valAddr = (u16*)(src + offset); + + *((u32*)dst) = decode5A3RGBA(Common::swap16(*valAddr)); + } + break; + case GX_TF_RGBA8: + { + u16 sBlk = s >> 2; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 2) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 5; // shift by 5 is correct + u16 blkS = s & 3; + u16 blkT = t & 3; + u32 blkOff = (blkT << 2) + blkS; + + u32 offset = (base + blkOff) << 1 ; + const u8* valAddr = src + offset; + + dst[3] = valAddr[0]; + dst[0] = valAddr[1]; + dst[1] = valAddr[32]; + dst[2] = valAddr[33]; + } + break; + case GX_TF_CMPR: + { + u16 sDxt = s >> 2; + u16 tDxt = t >> 2; + + u16 sBlk = sDxt >> 1; + u16 tBlk = tDxt >> 1; + u16 widthBlks = (imageWidth >> 3) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 2; + u16 blkS = sDxt & 1; + u16 blkT = tDxt & 1; + u32 blkOff = (blkT << 1) + blkS; + + u32 offset = (base + blkOff) << 3; + + const DXTBlock* dxtBlock = (const DXTBlock*)(src + offset); + + u16 c1 = Common::swap16(dxtBlock->color1); + u16 c2 = Common::swap16(dxtBlock->color2); + int blue1 = Convert5To8(c1 & 0x1F); + int blue2 = Convert5To8(c2 & 0x1F); + int green1 = Convert6To8((c1 >> 5) & 0x3F); + int green2 = Convert6To8((c2 >> 5) & 0x3F); + int red1 = Convert5To8((c1 >> 11) & 0x1F); + int red2 = Convert5To8((c2 >> 11) & 0x1F); + + u16 ss = s & 3; + u16 tt = t & 3; + + int colorSel = dxtBlock->lines[tt]; + int rs = 6 - (ss << 1); + colorSel = (colorSel >> rs) & 3; + colorSel |= c1 > c2?0:4; + + u32 color = 0; + + switch (colorSel) + { + case 0: + case 4: + color = makeRGBA(red1, green1, blue1, 255); + break; + case 1: + case 5: + color = makeRGBA(red2, green2, blue2, 255); + break; + case 2: + color = makeRGBA(red1+(red2-red1)/3, green1+(green2-green1)/3, blue1+(blue2-blue1)/3, 255); + break; + case 3: + color = makeRGBA(red2+(red1-red2)/3, green2+(green1-green2)/3, blue2+(blue1-blue2)/3, 255); + break; + case 6: + color = makeRGBA((int)ceil((float)(red1+red2)/2), (int)ceil((float)(green1+green2)/2), (int)ceil((float)(blue1+blue2)/2), 255); + break; + case 7: + color = makeRGBA(red2, green2, blue2, 0); + break; + } + + *((u32*)dst) = color; + } + break; + } +} + +void TexDecoder_DecodeTexelRGBA8FromTmem(u8 *dst, const u8 *src_ar, const u8* src_gb, int s, int t, int imageWidth) +{ + u16 sBlk = s >> 2; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 2) + 1; // TODO: Looks wrong. Shouldn't this be ((imageWidth-1)>>2)+1 ? + u32 base_ar = (tBlk * widthBlks + sBlk) << 4; + u32 base_gb = (tBlk * widthBlks + sBlk) << 4; + u16 blkS = s & 3; + u16 blkT = t & 3; + u32 blk_off = (blkT << 2) + blkS; + + u32 offset_ar = (base_ar + blk_off) << 1; + u32 offset_gb = (base_gb + blk_off) << 1; + const u8* val_addr_ar = src_ar + offset_ar; + const u8* val_addr_gb = src_gb + offset_gb; + + dst[3] = val_addr_ar[0]; // A + dst[0] = val_addr_ar[1]; // R + dst[1] = val_addr_gb[0]; // G + dst[2] = val_addr_gb[1]; // B +} + +PC_TexFormat TexDecoder_DecodeRGBA8FromTmem(u8* dst, const u8 *src_ar, const u8 *src_gb, int width, int height) +{ + // TODO for someone who cares: Make this less slow! + for (int y = 0; y < height; ++y) + for (int x = 0; x < width; ++x) + { + TexDecoder_DecodeTexelRGBA8FromTmem(dst, src_ar, src_gb, x, y, width-1); + dst += 4; + } + + return PC_TEX_FMT_RGBA32; +} + +const char* texfmt[] = { + // pixel + "I4", "I8", "IA4", "IA8", + "RGB565", "RGB5A3", "RGBA8", "0x07", + "C4", "C8", "C14X2", "0x0B", + "0x0C", "0x0D", "CMPR", "0x0F", + // Z-buffer + "0x10", "Z8", "0x12", "Z16", + "0x14", "0x15", "Z24X8", "0x17", + "0x18", "0x19", "0x1A", "0x1B", + "0x1C", "0x1D", "0x1E", "0x1F", + // pixel + copy + "CR4", "0x21", "CRA4", "CRA8", + "0x24", "0x25", "CYUVA8", "CA8", + "CR8", "CG8", "CB8", "CRG8", + "CGB8", "0x2D", "0x2E", "0x2F", + // Z + copy + "CZ4", "0x31", "0x32", "0x33", + "0x34", "0x35", "0x36", "0x37", + "0x38", "CZ8M", "CZ8L", "0x3B", + "CZ16L", "0x3D", "0x3E", "0x3F", +}; + +const unsigned char sfont_map[] = { + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,10,10,10,10, + 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25, + 26,27,28,29,30,31,32,33,34,35,36,10,10,10,10,10, + 10,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51, + 52,53,54,55,56,57,58,59,60,61,62,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, +}; + +const unsigned char sfont_raw[][9*10] = { + { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0x00, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + },{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x78, 0x78, 0x78, + }, +}; diff --git a/Source/Core/VideoCommon/Src/ImageWrite.cpp b/Source/Core/VideoCommon/Src/ImageWrite.cpp index 23b0e73427..52d48fc547 100644 --- a/Source/Core/VideoCommon/Src/ImageWrite.cpp +++ b/Source/Core/VideoCommon/Src/ImageWrite.cpp @@ -25,22 +25,22 @@ struct TGA_HEADER { - u8 identsize; // size of ID field that follows 18 u8 header (0 usually) - u8 colourmaptype; // type of colour map 0=none, 1=has palette - u8 imagetype; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed - - s16 colourmapstart; // first colour map entry in palette - s16 colourmaplength; // number of colours in palette - u8 colourmapbits; // number of bits per palette entry 15,16,24,32 - - s16 xstart; // image x origin - s16 ystart; // image y origin - s16 width; // image width in pixels - s16 height; // image height in pixels - u8 bits; // image bits per pixel 8,16,24,32 - u8 descriptor; // image descriptor bits (vh flip bits) - - // pixel data follows header + u8 identsize; // size of ID field that follows 18 u8 header (0 usually) + u8 colourmaptype; // type of colour map 0=none, 1=has palette + u8 imagetype; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed + + s16 colourmapstart; // first colour map entry in palette + s16 colourmaplength; // number of colours in palette + u8 colourmapbits; // number of bits per palette entry 15,16,24,32 + + s16 xstart; // image x origin + s16 ystart; // image y origin + s16 width; // image width in pixels + s16 height; // image height in pixels + u8 bits; // image bits per pixel 8,16,24,32 + u8 descriptor; // image descriptor bits (vh flip bits) + + // pixel data follows header }; #pragma pack(pop) @@ -53,7 +53,7 @@ bool SaveTGA(const char* filename, int width, int height, void* pdata) return false; _assert_(sizeof(TGA_HEADER) == 18 && sizeof(hdr) == 18); - + memset(&hdr, 0, sizeof(hdr)); hdr.imagetype = 2; hdr.bits = 32; @@ -69,7 +69,8 @@ bool SaveTGA(const char* filename, int width, int height, void* pdata) bool SaveData(const char* filename, const char* data) { - std::ofstream f(filename, std::ios::binary); + std::ofstream f; + OpenFStream(f, filename, std::ios::binary); f << data; return true; diff --git a/Source/Core/VideoCommon/Src/IndexGenerator.cpp b/Source/Core/VideoCommon/Src/IndexGenerator.cpp index 8053114fae..aa1a971687 100644 --- a/Source/Core/VideoCommon/Src/IndexGenerator.cpp +++ b/Source/Core/VideoCommon/Src/IndexGenerator.cpp @@ -15,6 +15,9 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ +#include <cstddef> + +#include "Common.h" #include "IndexGenerator.h" /* @@ -27,24 +30,18 @@ QUAD simulator */ //Init -u16 *IndexGenerator::Tptr = 0; -u16 *IndexGenerator::BASETptr = 0; -u16 *IndexGenerator::Lptr = 0; -u16 *IndexGenerator::BASELptr = 0; -u16 *IndexGenerator::Pptr = 0; -u16 *IndexGenerator::BASEPptr = 0; -int IndexGenerator::numT = 0; -int IndexGenerator::numL = 0; -int IndexGenerator::numP = 0; -int IndexGenerator::index = 0; -int IndexGenerator::Tadds = 0; -int IndexGenerator::Ladds = 0; -int IndexGenerator::Padds = 0; -IndexGenerator::IndexPrimitiveType IndexGenerator::LastTPrimitive = Prim_None; -IndexGenerator::IndexPrimitiveType IndexGenerator::LastLPrimitive = Prim_None; -bool IndexGenerator::used = false; - -void IndexGenerator::Start(u16 *Triangleptr,u16 *Lineptr,u16 *Pointptr) +u16 *IndexGenerator::Tptr; +u16 *IndexGenerator::BASETptr; +u16 *IndexGenerator::Lptr; +u16 *IndexGenerator::BASELptr; +u16 *IndexGenerator::Pptr; +u16 *IndexGenerator::BASEPptr; +u32 IndexGenerator::numT; +u32 IndexGenerator::numL; +u32 IndexGenerator::numP; +u32 IndexGenerator::index; + +void IndexGenerator::Start(u16* Triangleptr, u16* Lineptr, u16* Pointptr) { Tptr = Triangleptr; Lptr = Lineptr; @@ -56,288 +53,123 @@ void IndexGenerator::Start(u16 *Triangleptr,u16 *Lineptr,u16 *Pointptr) numT = 0; numL = 0; numP = 0; - Tadds = 0; - Ladds = 0; - Padds = 0; - LastTPrimitive = Prim_None; - LastLPrimitive = Prim_None; } -// Triangles -void IndexGenerator::AddList(int numVerts) + +void IndexGenerator::AddIndices(int primitive, u32 numVerts) { - //if we have no vertices return - if(numVerts <= 0) return; - int numTris = numVerts / 3; - if (!numTris) + //switch (primitive) + //{ + //case GX_DRAW_QUADS: IndexGenerator::AddQuads(numVerts); break; + //case GX_DRAW_TRIANGLES: IndexGenerator::AddList(numVerts); break; + //case GX_DRAW_TRIANGLE_STRIP: IndexGenerator::AddStrip(numVerts); break; + //case GX_DRAW_TRIANGLE_FAN: IndexGenerator::AddFan(numVerts); break; + //case GX_DRAW_LINES: IndexGenerator::AddLineList(numVerts); break; + //case GX_DRAW_LINE_STRIP: IndexGenerator::AddLineStrip(numVerts); break; + //case GX_DRAW_POINTS: IndexGenerator::AddPoints(numVerts); break; + //} + + static void (*const primitive_table[])(u32) = { - //if we have less than 3 verts - if(numVerts == 1) - { - // discard - index++; - return; - } - else - { - //we have two verts render a degenerated triangle - numTris = 1; - *Tptr++ = index; - *Tptr++ = index+1; - *Tptr++ = index; - } - } - else - { - for (int i = 0; i < numTris; i++) - { - *Tptr++ = index+i*3; - *Tptr++ = index+i*3+1; - *Tptr++ = index+i*3+2; - } - int baseRemainingverts = numVerts - numVerts % 3; - switch (numVerts % 3) - { - case 2: - //whe have 2 remaining verts use strip method - *Tptr++ = index + baseRemainingverts - 1; - *Tptr++ = index + baseRemainingverts; - *Tptr++ = index + baseRemainingverts + 1; - numTris++; - break; - case 1: - //whe have 1 remaining verts use strip method this is only a conjeture - *Tptr++ = index + baseRemainingverts - 2; - *Tptr++ = index + baseRemainingverts - 1; - *Tptr++ = index + baseRemainingverts; - numTris++; - break; - default: - break; - }; - } + IndexGenerator::AddQuads, + NULL, + IndexGenerator::AddList, + IndexGenerator::AddStrip, + IndexGenerator::AddFan, + IndexGenerator::AddLineList, + IndexGenerator::AddLineStrip, + IndexGenerator::AddPoints, + }; + + primitive_table[primitive](numVerts); index += numVerts; - numT += numTris; - Tadds++; - LastTPrimitive = Prim_List; } -void IndexGenerator::AddStrip(int numVerts) +// Triangles +__forceinline void IndexGenerator::WriteTriangle(u32 index1, u32 index2, u32 index3) { - if(numVerts <= 0) return; - int numTris = numVerts - 2; - if (numTris < 1) - { - //if we have less than 3 verts - if(numVerts == 1) - { - // discard - index++; - return; - } - else - { - //we have two verts render a degenerated triangle - numTris = 1; - *Tptr++ = index; - *Tptr++ = index+1; - *Tptr++ = index; - } - } - else - { - bool wind = false; - for (int i = 0; i < numTris; i++) - { - *Tptr++ = index+i; - *Tptr++ = index+i+(wind?2:1); - *Tptr++ = index+i+(wind?1:2); - wind = !wind; - } - } - index += numVerts; - numT += numTris; - Tadds++; - LastTPrimitive = Prim_Strip; + *Tptr++ = index1; + *Tptr++ = index2; + *Tptr++ = index3; + + ++numT; } -void IndexGenerator::AddFan(int numVerts) + +void IndexGenerator::AddList(u32 const numVerts) { - if(numVerts <= 0) return; - int numTris = numVerts - 2; - if (numTris < 1) + auto const numTris = numVerts / 3; + for (u32 i = 0; i != numTris; ++i) { - //if we have less than 3 verts - if(numVerts == 1) - { - //Discard - index++; - return; - } - else - { - //we have two verts render a degenerated triangle - numTris = 1; - *Tptr++ = index; - *Tptr++ = index+1; - *Tptr++ = index; - } + WriteTriangle(index + i * 3, index + i * 3 + 1, index + i * 3 + 2); } - else - { - for (int i = 0; i < numTris; i++) - { - *Tptr++ = index; - *Tptr++ = index+i+1; - *Tptr++ = index+i+2; - } - } - index += numVerts; - numT += numTris; - Tadds++; - LastTPrimitive = Prim_Fan; } -void IndexGenerator::AddQuads(int numVerts) +void IndexGenerator::AddStrip(u32 const numVerts) { - if(numVerts <= 0) return; - int numTris = (numVerts/4)*2; - if (numTris == 0) + bool wind = false; + for (u32 i = 2; i < numVerts; ++i) { - //if we have less than 3 verts - if(numVerts == 1) - { - //discard - index++; - return; - } - else - { - if(numVerts == 2) - { - //we have two verts render a degenerated triangle - numTris = 1; - *Tptr++ = index; - *Tptr++ = index + 1; - *Tptr++ = index; - } - else - { - //we have 3 verts render a full triangle - numTris = 1; - *Tptr++ = index; - *Tptr++ = index + 1; - *Tptr++ = index + 2; - } - } + WriteTriangle( + index + i - 2, + index + i - !wind, + index + i - wind); + + wind ^= true; } - else +} + +void IndexGenerator::AddFan(u32 numVerts) +{ + for (u32 i = 2; i < numVerts; ++i) { - for (int i = 0; i < numTris / 2; i++) - { - *Tptr++ = index+i*4; - *Tptr++ = index+i*4+1; - *Tptr++ = index+i*4+2; - *Tptr++ = index+i*4; - *Tptr++ = index+i*4+2; - *Tptr++ = index+i*4+3; - } - int baseRemainingverts = numVerts - numVerts % 4; - switch (numVerts % 4) - { - case 3: - //whe have 3 remaining verts use strip method - *Tptr++ = index + baseRemainingverts; - *Tptr++ = index + baseRemainingverts + 1; - *Tptr++ = index + baseRemainingverts + 2; - numTris++; - break; - case 2: - //whe have 2 remaining verts use strip method - *Tptr++ = index + baseRemainingverts - 1; - *Tptr++ = index + baseRemainingverts; - *Tptr++ = index + baseRemainingverts + 1; - numTris++; - break; - case 1: - //whe have 1 remaining verts use strip method this is only a conjeture - *Tptr++ = index + baseRemainingverts - 2; - *Tptr++ = index + baseRemainingverts - 1; - *Tptr++ = index + baseRemainingverts; - numTris++; - break; - default: - break; - }; + WriteTriangle(index, index + i - 1, index + i); } - index += numVerts; - numT += numTris; - Tadds++; - LastTPrimitive = Prim_List; } - -//Lines -void IndexGenerator::AddLineList(int numVerts) +void IndexGenerator::AddQuads(u32 numVerts) { - if(numVerts <= 0) return; - int numLines = numVerts / 2; - if (!numLines) + auto const numQuads = numVerts / 4; + for (u32 i = 0; i != numQuads; ++i) { - //Discard - index++; - return; + WriteTriangle(index + i * 4, index + i * 4 + 1, index + i * 4 + 2); + WriteTriangle(index + i * 4, index + i * 4 + 2, index + i * 4 + 3); } - else +} + +// Lines +void IndexGenerator::AddLineList(u32 numVerts) +{ + auto const numLines = numVerts / 2; + for (u32 i = 0; i != numLines; ++i) { - for (int i = 0; i < numLines; i++) - { - *Lptr++ = index+i*2; - *Lptr++ = index+i*2+1; - } - if((numVerts & 1) != 0) - { - //use line strip for remaining vert - *Lptr++ = index + numLines * 2 - 1; - *Lptr++ = index + numLines * 2; - } + *Lptr++ = index + i * 2; + *Lptr++ = index + i * 2 + 1; + ++numL; } - index += numVerts; - numL += numLines; - Ladds++; - LastLPrimitive = Prim_List; } -void IndexGenerator::AddLineStrip(int numVerts) +void IndexGenerator::AddLineStrip(u32 numVerts) { - int numLines = numVerts - 1; - if (numLines <= 0) + for (u32 i = 1; i < numVerts; ++i) { - if(numVerts == 1) - { - index++; - } - return; + *Lptr++ = index + i - 1; + *Lptr++ = index + i; + ++numL; } - for (int i = 0; i < numLines; i++) +} + +// Points +void IndexGenerator::AddPoints(u32 numVerts) +{ + for (u32 i = 0; i != numVerts; ++i) { - *Lptr++ = index+i; - *Lptr++ = index+i+1; + *Pptr++ = index + i; + ++numP; } - index += numVerts; - numL += numLines; - Ladds++; - LastLPrimitive = Prim_Strip; } - -//Points -void IndexGenerator::AddPoints(int numVerts) +u32 IndexGenerator::GetRemainingIndices() { - for (int i = 0; i < numVerts; i++) - { - *Pptr++ = index+i; - } - index += numVerts; - numP += numVerts; - Padds++; + u32 max_index = 65535; + return max_index - index; } diff --git a/Source/Core/VideoCommon/Src/IndexGenerator.h b/Source/Core/VideoCommon/Src/IndexGenerator.h index d1ed143d98..f14d3ae026 100644 --- a/Source/Core/VideoCommon/Src/IndexGenerator.h +++ b/Source/Core/VideoCommon/Src/IndexGenerator.h @@ -25,53 +25,60 @@ class IndexGenerator { public: - //Init + // Init static void Start(u16 *Triangleptr,u16 *Lineptr,u16 *Pointptr); - //Triangles - static void AddList(int numVerts); - static void AddStrip(int numVerts); - static void AddFan(int numVerts); - static void AddQuads(int numVerts); - //Lines - static void AddLineList(int numVerts); - static void AddLineStrip(int numVerts); - //Points - static void AddPoints(int numVerts); - //Interface - static int GetNumTriangles() {used = true; return numT;} - static int GetNumLines() {used = true;return numL;} - static int GetNumPoints() {used = true;return numP;} - static int GetNumVerts() {return index;} //returns numprimitives - static int GetNumAdds() {return Tadds + Ladds + Padds;} - static int GetTriangleindexLen() {return (int)(Tptr - BASETptr);} - static int GetLineindexLen() {return (int)(Lptr - BASELptr);} - static int GetPointindexLen() {return (int)(Pptr - BASEPptr);} + static void AddIndices(int primitive, u32 numVertices); + + // Interface + static u32 GetNumTriangles() {return numT;} + static u32 GetNumLines() {return numL;} + static u32 GetNumPoints() {return numP;} + + // returns numprimitives + static u32 GetNumVerts() {return index;} + + static u32 GetTriangleindexLen() {return (u32)(Tptr - BASETptr);} + static u32 GetLineindexLen() {return (u32)(Lptr - BASELptr);} + static u32 GetPointindexLen() {return (u32)(Pptr - BASEPptr);} + + static u32 GetRemainingIndices(); +/* enum IndexPrimitiveType { Prim_None = 0, Prim_List, Prim_Strip, Prim_Fan - } ; + }; +*/ private: + // Triangles + static void AddList(u32 numVerts); + static void AddStrip(u32 numVerts); + static void AddFan(u32 numVerts); + static void AddQuads(u32 numVerts); + + // Lines + static void AddLineList(u32 numVerts); + static void AddLineStrip(u32 numVerts); + + // Points + static void AddPoints(u32 numVerts); + + static void WriteTriangle(u32 index1, u32 index2, u32 index3); + static u16 *Tptr; static u16 *BASETptr; static u16 *Lptr; static u16 *BASELptr; static u16 *Pptr; static u16 *BASEPptr; - static int numT; - static int numL; - static int numP; - static int index; - static int Tadds; - static int Ladds; - static int Padds; - static IndexPrimitiveType LastTPrimitive; - static IndexPrimitiveType LastLPrimitive; - static bool used; - + // TODO: redundant variables + static u32 numT; + static u32 numL; + static u32 numP; + static u32 index; }; #endif // _INDEXGENERATOR_H diff --git a/Source/Core/VideoCommon/Src/LightingShaderGen.cpp b/Source/Core/VideoCommon/Src/LightingShaderGen.cpp index f32e5dfeee..2b717bdba6 100644 --- a/Source/Core/VideoCommon/Src/LightingShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/LightingShaderGen.cpp @@ -47,13 +47,13 @@ char *GenerateLightShader(char *p, int index, const LitChannel& chan, const char // atten disabled switch (chan.diffusefunc) { case LIGHTDIF_NONE: - WRITE(p, "lacc.%s += %s.lights[%d].col.%s;\n", swizzle, lightsName, index, swizzle); + WRITE(p, "lacc.%s += %s[%d].%s;\n", swizzle, lightsName, index * 5, swizzle); break; case LIGHTDIF_SIGN: case LIGHTDIF_CLAMP: - WRITE(p, "ldir = normalize(%s.lights[%d].pos.xyz - pos.xyz);\n", lightsName, index); - WRITE(p, "lacc.%s += %sdot(ldir, _norm0)) * %s.lights[%d].col.%s;\n", - swizzle, chan.diffusefunc != LIGHTDIF_SIGN ? "max(0.0f," :"(", lightsName, index, swizzle); + WRITE(p, "ldir = normalize(%s[%d + 3].xyz - pos.xyz);\n", lightsName, index * 5); + WRITE(p, "lacc.%s += %sdot(ldir, _norm0)) * %s[%d].%s;\n", + swizzle, chan.diffusefunc != LIGHTDIF_SIGN ? "max(0.0f," :"(", lightsName, index * 5, swizzle); break; default: _assert_(0); } @@ -62,32 +62,32 @@ char *GenerateLightShader(char *p, int index, const LitChannel& chan, const char if (chan.attnfunc == 3) { // spot - WRITE(p, "ldir = %s.lights[%d].pos.xyz - pos.xyz;\n", lightsName, index); + WRITE(p, "ldir = %s[%d + 3].xyz - pos.xyz;\n", lightsName, index * 5); WRITE(p, "dist2 = dot(ldir, ldir);\n" "dist = sqrt(dist2);\n" "ldir = ldir / dist;\n" - "attn = max(0.0f, dot(ldir, %s.lights[%d].dir.xyz));\n", lightsName, index); - WRITE(p, "attn = max(0.0f, dot(%s.lights[%d].cosatt.xyz, float3(1.0f, attn, attn*attn))) / dot(%s.lights[%d].distatt.xyz, float3(1.0f,dist,dist2));\n", lightsName, index, lightsName, index); + "attn = max(0.0f, dot(ldir, %s[%d + 4].xyz));\n", lightsName, index * 5); + WRITE(p, "attn = max(0.0f, dot(%s[%d + 1].xyz, float3(1.0f, attn, attn*attn))) / dot(%s[%d + 2].xyz, float3(1.0f,dist,dist2));\n", lightsName, index * 5, lightsName, index * 5); } else if (chan.attnfunc == 1) { // specular - WRITE(p, "ldir = normalize(%s.lights[%d].pos.xyz);\n", lightsName, index); - WRITE(p, "attn = (dot(_norm0,ldir) >= 0.0f) ? max(0.0f, dot(_norm0, %s.lights[%d].dir.xyz)) : 0.0f;\n", lightsName, index); - WRITE(p, "attn = max(0.0f, dot(%s.lights[%d].cosatt.xyz, float3(1,attn,attn*attn))) / dot(%s.lights[%d].distatt.xyz, float3(1,attn,attn*attn));\n", lightsName, index, lightsName, index); + WRITE(p, "ldir = normalize(%s[%d + 3].xyz);\n", lightsName, index * 5); + WRITE(p, "attn = (dot(_norm0,ldir) >= 0.0f) ? max(0.0f, dot(_norm0, %s[%d + 4].xyz)) : 0.0f;\n", lightsName, index * 5); + WRITE(p, "attn = max(0.0f, dot(%s[%d + 1].xyz, float3(1,attn,attn*attn))) / dot(%s[%d + 2].xyz, float3(1,attn,attn*attn));\n", lightsName, index * 5, lightsName, index * 5); } switch (chan.diffusefunc) { case LIGHTDIF_NONE: - WRITE(p, "lacc.%s += attn * %s.lights[%d].col.%s;\n", swizzle, lightsName, index, swizzle); + WRITE(p, "lacc.%s += attn * %s[%d].%s;\n", swizzle, lightsName, index * 5, swizzle); break; case LIGHTDIF_SIGN: case LIGHTDIF_CLAMP: - WRITE(p, "lacc.%s += attn * %sdot(ldir, _norm0)) * %s.lights[%d].col.%s;\n", + WRITE(p, "lacc.%s += attn * %sdot(ldir, _norm0)) * %s[%d].%s;\n", swizzle, chan.diffusefunc != LIGHTDIF_SIGN ? "max(0.0f," :"(", lightsName, - index, + index * 5, swizzle); break; default: _assert_(0); @@ -120,7 +120,7 @@ char *GenerateLightingShader(char *p, int components, const char* materialsName, WRITE(p, "mat = float4(1.0f, 1.0f, 1.0f, 1.0f);\n"); } else // from color - WRITE(p, "mat = %s.C%d;\n", materialsName, j+2); + WRITE(p, "mat = %s[%d];\n", materialsName, j+2); if (color.enablelighting) { if (color.ambsource) { // from vertex @@ -132,7 +132,7 @@ char *GenerateLightingShader(char *p, int components, const char* materialsName, WRITE(p, "lacc = float4(0.0f, 0.0f, 0.0f, 0.0f);\n"); } else // from color - WRITE(p, "lacc = %s.C%d;\n", materialsName, j); + WRITE(p, "lacc = %s[%d];\n", materialsName, j); } else { @@ -149,7 +149,7 @@ char *GenerateLightingShader(char *p, int components, const char* materialsName, else WRITE(p, "mat.w = 1.0f;\n"); } else // from color - WRITE(p, "mat.w = %s.C%d.w;\n", materialsName, j+2); + WRITE(p, "mat.w = %s[%d].w;\n", materialsName, j+2); } if (alpha.enablelighting) @@ -163,7 +163,7 @@ char *GenerateLightingShader(char *p, int components, const char* materialsName, WRITE(p, "lacc.w = 0.0f;\n"); } else // from color - WRITE(p, "lacc.w = %s.C%d.w;\n", materialsName, j); + WRITE(p, "lacc.w = %s[%d].w;\n", materialsName, j); } else { diff --git a/Source/Core/VideoCommon/Src/MainBase.cpp b/Source/Core/VideoCommon/Src/MainBase.cpp index 726ef71b38..1472367f21 100644 --- a/Source/Core/VideoCommon/Src/MainBase.cpp +++ b/Source/Core/VideoCommon/Src/MainBase.cpp @@ -21,6 +21,10 @@ volatile u32 s_swapRequested = false; u32 s_efbAccessRequested = false; volatile u32 s_FifoShuttingDown = false; +std::condition_variable s_perf_query_cond; +std::mutex s_perf_query_lock; +static volatile bool s_perf_query_requested; + static volatile struct { u32 xfbAddr; @@ -169,6 +173,43 @@ u32 VideoBackendHardware::Video_AccessEFB(EFBAccessType type, u32 x, u32 y, u32 return 0; } +static bool QueryResultIsReady() +{ + return !s_perf_query_requested || s_FifoShuttingDown; +} + +void VideoFifo_CheckPerfQueryRequest() +{ + if (s_perf_query_requested) + { + g_perf_query->FlushResults(); + + { + std::lock_guard<std::mutex> lk(s_perf_query_lock); + s_perf_query_requested = false; + } + + s_perf_query_cond.notify_one(); + } +} + +u32 VideoBackendHardware::Video_GetQueryResult(PerfQueryType type) +{ + // TODO: Is this check sane? + if (!g_perf_query->IsFlushed()) + { + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread) + { + s_perf_query_requested = true; + std::unique_lock<std::mutex> lk(s_perf_query_lock); + s_perf_query_cond.wait(lk, QueryResultIsReady); + } + else + g_perf_query->FlushResults(); + } + + return g_perf_query->GetQueryResult(type); +} void VideoBackendHardware::InitializeShared() { @@ -176,6 +217,7 @@ void VideoBackendHardware::InitializeShared() s_swapRequested = 0; s_efbAccessRequested = 0; + s_perf_query_requested = false; s_FifoShuttingDown = 0; memset((void*)&s_beginFieldArgs, 0, sizeof(s_beginFieldArgs)); memset(&s_accessEFBArgs, 0, sizeof(s_accessEFBArgs)); @@ -186,6 +228,11 @@ void VideoBackendHardware::InitializeShared() // Run from the CPU thread void VideoBackendHardware::DoState(PointerWrap& p) { + bool software = false; + p.Do(software); + if (p.GetMode() == PointerWrap::MODE_READ && software == true) + // change mode to abort load of incompatible save state. + p.SetMode(PointerWrap::MODE_VERIFY); VideoCommon_DoState(p); p.DoMarker("VideoCommon"); @@ -233,6 +280,7 @@ void VideoFifo_CheckAsyncRequest() { VideoFifo_CheckSwapRequest(); VideoFifo_CheckEFBAccess(); + VideoFifo_CheckPerfQueryRequest(); } void VideoBackendHardware::Video_GatherPipeBursted() diff --git a/Source/Core/VideoCommon/Src/NativeVertexFormat.h b/Source/Core/VideoCommon/Src/NativeVertexFormat.h index 02184fde1c..1340991b21 100644 --- a/Source/Core/VideoCommon/Src/NativeVertexFormat.h +++ b/Source/Core/VideoCommon/Src/NativeVertexFormat.h @@ -102,7 +102,7 @@ public: virtual void SetupVertexPointers() = 0; virtual void EnableComponents(u32 components) {} - int GetVertexStride() const { return vertex_stride; } + u32 GetVertexStride() const { return vertex_stride; } // TODO: move this under private: u32 m_components; // VB_HAS_X. Bitmask telling what vertex components are present. diff --git a/Source/Core/VideoCommon/Src/OnScreenDisplay.h b/Source/Core/VideoCommon/Src/OnScreenDisplay.h index 3777e2b5d3..80187b8ac3 100644 --- a/Source/Core/VideoCommon/Src/OnScreenDisplay.h +++ b/Source/Core/VideoCommon/Src/OnScreenDisplay.h @@ -22,7 +22,7 @@ namespace OSD { // On-screen message display -void AddMessage(const char* str, u32 ms); +void AddMessage(const char* str, u32 ms = 2000); void DrawMessages(); // draw the current messages on the screen. Only call once per frame. void ClearMessages(); diff --git a/Source/Core/VideoCommon/Src/OpcodeDecoding.cpp b/Source/Core/VideoCommon/Src/OpcodeDecoding.cpp index 4f7f86d655..92d596b774 100644 --- a/Source/Core/VideoCommon/Src/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/Src/OpcodeDecoding.cpp @@ -123,7 +123,7 @@ void InterpretDisplayList(u32 address, u32 size) Statistics::SwapDL(); } - // reset to the old pointer + // reset to the old pointer g_pVideoData = old_pVideoData; } @@ -136,74 +136,114 @@ void ExecuteDisplayList(u32 address, u32 size) InterpretDisplayList(address, size); } -bool FifoCommandRunnable() +u32 FifoCommandRunnable(u32 &command_size) { + u32 cycleTime = 0; u32 buffer_size = (u32)(GetVideoBufferEndPtr() - g_pVideoData); - if (buffer_size == 0) - return false; // can't peek + if (buffer_size == 0) + return 0; // can't peek u8 cmd_byte = DataPeek8(0); - u32 command_size = 0; - switch (cmd_byte) - { - case GX_NOP: // Hm, this means that we scan over nop streams pretty slowly... + switch (cmd_byte) + { + case GX_NOP: // Hm, this means that we scan over nop streams pretty slowly... + command_size = 1; + cycleTime = 6; + break; case GX_CMD_INVL_VC: // Invalidate Vertex Cache - no parameters - case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that - command_size = 1; - break; - - case GX_LOAD_BP_REG: - command_size = 5; - break; - - case GX_LOAD_CP_REG: - command_size = 6; - break; - - case GX_LOAD_INDX_A: - case GX_LOAD_INDX_B: - case GX_LOAD_INDX_C: - case GX_LOAD_INDX_D: - command_size = 5; - break; - - case GX_CMD_CALL_DL: - command_size = 9; - break; - - case GX_LOAD_XF_REG: - { - // check if we can read the header - if (buffer_size >= 5) - { - command_size = 1 + 4; - u32 Cmd2 = DataPeek32(1); - int transfer_size = ((Cmd2 >> 16) & 15) + 1; - command_size += transfer_size * 4; - } - else + command_size = 1; + cycleTime = 6; + break; + case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that + command_size = 1; + cycleTime = 6; + break; + + case GX_LOAD_BP_REG: + command_size = 5; + cycleTime = 12; + break; + + case GX_LOAD_CP_REG: + command_size = 6; + cycleTime = 12; + break; + + case GX_LOAD_INDX_A: + case GX_LOAD_INDX_B: + case GX_LOAD_INDX_C: + case GX_LOAD_INDX_D: + command_size = 5; + cycleTime = 6; // TODO + break; + + case GX_CMD_CALL_DL: + { + // FIXME: Calculate the cycle time of the display list. + //u32 address = DataPeek32(1); + //u32 size = DataPeek32(5); + //u8* old_pVideoData = g_pVideoData; + //u8* startAddress = Memory::GetPointer(address); + + //// Avoid the crash if Memory::GetPointer failed .. + //if (startAddress != 0) + //{ + // g_pVideoData = startAddress; + // u8 *end = g_pVideoData + size; + // u32 step = 0; + // while (g_pVideoData < end) + // { + // cycleTime += FifoCommandRunnable(step); + // g_pVideoData += step; + // } + //} + //else + //{ + // cycleTime = 45; + //} + + //// reset to the old pointer + //g_pVideoData = old_pVideoData; + command_size = 9; + cycleTime = 45; // This is unverified + } + break; + + case GX_LOAD_XF_REG: + { + // check if we can read the header + if (buffer_size >= 5) { - return false; - } - } - break; - - default: - if (cmd_byte & 0x80) - { - // check if we can read the header - if (buffer_size >= 3) + command_size = 1 + 4; + u32 Cmd2 = DataPeek32(1); + int transfer_size = ((Cmd2 >> 16) & 15) + 1; + command_size += transfer_size * 4; + cycleTime = 18 + 6 * transfer_size; + } + else { - command_size = 1 + 2; - u16 numVertices = DataPeek16(1); + return 0; + } + } + break; + + default: + if (cmd_byte & 0x80) + { + // check if we can read the header + if (buffer_size >= 3) + { + command_size = 1 + 2; + u16 numVertices = DataPeek16(1); command_size += numVertices * VertexLoaderManager::GetVertexSize(cmd_byte & GX_VAT_MASK); - } + cycleTime = 1600; // This depends on the number of pixels rendered + } else - { - return false; - } - } + { + return 0; + } + } else { // TODO(Omega): Maybe dump FIFO to file on this error @@ -218,7 +258,7 @@ bool FifoCommandRunnable() Host_SysMessage(szTemp); INFO_LOG(VIDEO, "%s", szTemp); { - SCPFifoStruct &fifo = CommandProcessor::fifo; + SCPFifoStruct &fifo = CommandProcessor::fifo; char szTmp[512]; // sprintf(szTmp, "Illegal command %02x (at %08x)",cmd_byte,g_pDataReader->GetPtr()); @@ -243,197 +283,205 @@ bool FifoCommandRunnable() Host_SysMessage(szTmp); INFO_LOG(VIDEO, "%s", szTmp); } - } - break; - } - - if (command_size > buffer_size) - return false; + } + break; + } + + if (command_size > buffer_size) + return 0; - // INFO_LOG("OP detected: cmd_byte 0x%x size %i buffer %i",cmd_byte, command_size, buffer_size); + // INFO_LOG("OP detected: cmd_byte 0x%x size %i buffer %i",cmd_byte, command_size, buffer_size); + if (cycleTime == 0) + cycleTime = 6; - return true; + return cycleTime; +} + +u32 FifoCommandRunnable() +{ + u32 command_size = 0; + return FifoCommandRunnable(command_size); } static void Decode() { - u8 *opcodeStart = g_pVideoData; - - int cmd_byte = DataReadU8(); - switch (cmd_byte) - { - case GX_NOP: - break; - - case GX_LOAD_CP_REG: //0x08 - { - u8 sub_cmd = DataReadU8(); - u32 value = DataReadU32(); - LoadCPReg(sub_cmd, value); + u8 *opcodeStart = g_pVideoData; + + int cmd_byte = DataReadU8(); + switch (cmd_byte) + { + case GX_NOP: + break; + + case GX_LOAD_CP_REG: //0x08 + { + u8 sub_cmd = DataReadU8(); + u32 value = DataReadU32(); + LoadCPReg(sub_cmd, value); INCSTAT(stats.thisFrame.numCPLoads); - } - break; + } + break; - case GX_LOAD_XF_REG: - { - u32 Cmd2 = DataReadU32(); - int transfer_size = ((Cmd2 >> 16) & 15) + 1; + case GX_LOAD_XF_REG: + { + u32 Cmd2 = DataReadU32(); + int transfer_size = ((Cmd2 >> 16) & 15) + 1; u32 xf_address = Cmd2 & 0xFFFF; GC_ALIGNED128(u32 data_buffer[16]); DataReadU32xFuncs[transfer_size-1](data_buffer); - LoadXFReg(transfer_size, xf_address, data_buffer); + LoadXFReg(transfer_size, xf_address, data_buffer); INCSTAT(stats.thisFrame.numXFLoads); - } - break; - - case GX_LOAD_INDX_A: //used for position matrices - LoadIndexedXF(DataReadU32(), 0xC); - break; - case GX_LOAD_INDX_B: //used for normal matrices - LoadIndexedXF(DataReadU32(), 0xD); - break; - case GX_LOAD_INDX_C: //used for postmatrices - LoadIndexedXF(DataReadU32(), 0xE); - break; - case GX_LOAD_INDX_D: //used for lights - LoadIndexedXF(DataReadU32(), 0xF); - break; - - case GX_CMD_CALL_DL: - { - u32 address = DataReadU32(); - u32 count = DataReadU32(); - ExecuteDisplayList(address, count); - } - break; - - case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that + } + break; + + case GX_LOAD_INDX_A: //used for position matrices + LoadIndexedXF(DataReadU32(), 0xC); + break; + case GX_LOAD_INDX_B: //used for normal matrices + LoadIndexedXF(DataReadU32(), 0xD); + break; + case GX_LOAD_INDX_C: //used for postmatrices + LoadIndexedXF(DataReadU32(), 0xE); + break; + case GX_LOAD_INDX_D: //used for lights + LoadIndexedXF(DataReadU32(), 0xF); + break; + + case GX_CMD_CALL_DL: + { + u32 address = DataReadU32(); + u32 count = DataReadU32(); + ExecuteDisplayList(address, count); + } + break; + + case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that DEBUG_LOG(VIDEO, "GX 0x44: %08x", cmd_byte); - break; + break; - case GX_CMD_INVL_VC: // Invalidate Vertex Cache - DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)"); - break; + case GX_CMD_INVL_VC: // Invalidate Vertex Cache + DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)"); + break; - case GX_LOAD_BP_REG: //0x61 - { + case GX_LOAD_BP_REG: //0x61 + { u32 bp_cmd = DataReadU32(); - LoadBPReg(bp_cmd); + LoadBPReg(bp_cmd); INCSTAT(stats.thisFrame.numBPLoads); - } - break; - - // draw primitives - default: - if (cmd_byte & 0x80) - { - // load vertices (use computed vertex size from FifoCommandRunnable above) + } + break; + + // draw primitives + default: + if (cmd_byte & 0x80) + { + // load vertices (use computed vertex size from FifoCommandRunnable above) u16 numVertices = DataReadU16(); VertexLoaderManager::RunVertices( cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7) (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, numVertices); - } - else - { + } + else + { ERROR_LOG(VIDEO, "OpcodeDecoding::Decode: Illegal command %02x", cmd_byte); - break; - } - break; - } + break; + } + break; + } // Display lists get added directly into the FIFO stream if (g_bRecordFifoData && cmd_byte != GX_CMD_CALL_DL) - FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, g_pVideoData - opcodeStart); + FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, u32(g_pVideoData - opcodeStart)); } static void DecodeSemiNop() { - u8 *opcodeStart = g_pVideoData; - - int cmd_byte = DataReadU8(); - switch (cmd_byte) - { - case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that - case GX_CMD_INVL_VC: // Invalidate Vertex Cache - case GX_NOP: + u8 *opcodeStart = g_pVideoData; + + int cmd_byte = DataReadU8(); + switch (cmd_byte) + { + case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that + case GX_CMD_INVL_VC: // Invalidate Vertex Cache + case GX_NOP: break; case GX_LOAD_CP_REG: //0x08 // We have to let CP writes through because they determine the size of vertices. - { - u8 sub_cmd = DataReadU8(); - u32 value = DataReadU32(); - LoadCPReg(sub_cmd, value); - INCSTAT(stats.thisFrame.numCPLoads); - } - break; - - case GX_LOAD_XF_REG: - { - u32 Cmd2 = DataReadU32(); - int transfer_size = ((Cmd2 >> 16) & 15) + 1; - u32 address = Cmd2 & 0xFFFF; - GC_ALIGNED128(u32 data_buffer[16]); - DataReadU32xFuncs[transfer_size-1](data_buffer); - LoadXFReg(transfer_size, address, data_buffer); - INCSTAT(stats.thisFrame.numXFLoads); - } - break; - - case GX_LOAD_INDX_A: //used for position matrices - LoadIndexedXF(DataReadU32(), 0xC); - break; - case GX_LOAD_INDX_B: //used for normal matrices - LoadIndexedXF(DataReadU32(), 0xD); - break; - case GX_LOAD_INDX_C: //used for postmatrices - LoadIndexedXF(DataReadU32(), 0xE); - break; - case GX_LOAD_INDX_D: //used for lights - LoadIndexedXF(DataReadU32(), 0xF); - break; - - case GX_CMD_CALL_DL: + { + u8 sub_cmd = DataReadU8(); + u32 value = DataReadU32(); + LoadCPReg(sub_cmd, value); + INCSTAT(stats.thisFrame.numCPLoads); + } + break; + + case GX_LOAD_XF_REG: + { + u32 Cmd2 = DataReadU32(); + int transfer_size = ((Cmd2 >> 16) & 15) + 1; + u32 address = Cmd2 & 0xFFFF; + GC_ALIGNED128(u32 data_buffer[16]); + DataReadU32xFuncs[transfer_size-1](data_buffer); + LoadXFReg(transfer_size, address, data_buffer); + INCSTAT(stats.thisFrame.numXFLoads); + } + break; + + case GX_LOAD_INDX_A: //used for position matrices + LoadIndexedXF(DataReadU32(), 0xC); + break; + case GX_LOAD_INDX_B: //used for normal matrices + LoadIndexedXF(DataReadU32(), 0xD); + break; + case GX_LOAD_INDX_C: //used for postmatrices + LoadIndexedXF(DataReadU32(), 0xE); + break; + case GX_LOAD_INDX_D: //used for lights + LoadIndexedXF(DataReadU32(), 0xF); + break; + + case GX_CMD_CALL_DL: // Hm, wonder if any games put tokens in display lists - in that case, // we'll have to parse them too. - DataSkip(8); - break; + DataSkip(8); + break; - case GX_LOAD_BP_REG: //0x61 + case GX_LOAD_BP_REG: //0x61 // We have to let BP writes through because they set tokens and stuff. // TODO: Call a much simplified LoadBPReg instead. - { + { u32 bp_cmd = DataReadU32(); - LoadBPReg(bp_cmd); + LoadBPReg(bp_cmd); INCSTAT(stats.thisFrame.numBPLoads); - } - break; - - // draw primitives - default: - if (cmd_byte & 0x80) - { - // load vertices (use computed vertex size from FifoCommandRunnable above) + } + break; + + // draw primitives + default: + if (cmd_byte & 0x80) + { + // load vertices (use computed vertex size from FifoCommandRunnable above) u16 numVertices = DataReadU16(); DataSkip(numVertices * VertexLoaderManager::GetVertexSize(cmd_byte & GX_VAT_MASK)); - } - else - { + } + else + { ERROR_LOG(VIDEO, "OpcodeDecoding::Decode: Illegal command %02x", cmd_byte); - break; - } - break; - } + break; + } + break; + } if (g_bRecordFifoData && cmd_byte != GX_CMD_CALL_DL) - FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, g_pVideoData - opcodeStart); + FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, u32(g_pVideoData - opcodeStart)); } void OpcodeDecoder_Init() -{ +{ g_pVideoData = GetVideoBufferStartPtr(); #if _M_SSE >= 0x301 @@ -446,8 +494,8 @@ void OpcodeDecoder_Init() if (g_Config.bEnableOpenCL) { - OpenCL::Initialize(); - TexDecoder_OpenCL_Initialize(); + OpenCL::Initialize(); + TexDecoder_OpenCL_Initialize(); } } @@ -456,21 +504,20 @@ void OpcodeDecoder_Shutdown() { if (g_Config.bEnableOpenCL) { - TexDecoder_OpenCL_Shutdown(); - OpenCL::Destroy(); + TexDecoder_OpenCL_Shutdown(); + OpenCL::Destroy(); } } -void OpcodeDecoder_Run(bool skipped_frame) +u32 OpcodeDecoder_Run(bool skipped_frame) { - if (!skipped_frame) - { - while (FifoCommandRunnable()) - Decode(); - } - else + u32 totalCycles = 0; + u32 cycles = FifoCommandRunnable(); + while (cycles > 0) { - while (FifoCommandRunnable()) - DecodeSemiNop(); + skipped_frame ? DecodeSemiNop() : Decode(); + totalCycles += cycles; + cycles = FifoCommandRunnable(); } + return totalCycles; } diff --git a/Source/Core/VideoCommon/Src/OpcodeDecoding.h b/Source/Core/VideoCommon/Src/OpcodeDecoding.h index f2e9cd1321..b825809705 100644 --- a/Source/Core/VideoCommon/Src/OpcodeDecoding.h +++ b/Source/Core/VideoCommon/Src/OpcodeDecoding.h @@ -44,12 +44,12 @@ #define GX_DRAW_LINES 0x5 // 0xA8 #define GX_DRAW_LINE_STRIP 0x6 // 0xB0 #define GX_DRAW_POINTS 0x7 // 0xB8 -#define GX_DRAW_NONE 0x1; //Tis is a fake value to used in the backends +#define GX_DRAW_NONE 0x1; //Tis is a fake value to used in the backends extern bool g_bRecordFifoData; void OpcodeDecoder_Init(); void OpcodeDecoder_Shutdown(); -void OpcodeDecoder_Run(bool skipped_frame); +u32 OpcodeDecoder_Run(bool skipped_frame); void ExecuteDisplayList(u32 address, u32 size); #endif // _OPCODE_DECODING_H diff --git a/Source/Core/VideoCommon/Src/OpenCL.cpp b/Source/Core/VideoCommon/Src/OpenCL.cpp index 0fc18017af..202c0c4b41 100644 --- a/Source/Core/VideoCommon/Src/OpenCL.cpp +++ b/Source/Core/VideoCommon/Src/OpenCL.cpp @@ -148,25 +148,25 @@ cl_program CompileProgram(const char *Kernel) // Build the program executable err = clBuildProgram(program , 0, NULL, NULL, NULL, NULL); if(err != CL_SUCCESS) { - HandleCLError(err, "Error: failed to build program"); + HandleCLError(err, "Error: failed to build program"); char *buildlog = NULL; - size_t buildlog_size = 0; + size_t buildlog_size = 0; clGetProgramBuildInfo(program, OpenCL::device_id, CL_PROGRAM_BUILD_LOG, 0, NULL, &buildlog_size); - buildlog = new char[buildlog_size + 1]; - err = clGetProgramBuildInfo(program, OpenCL::device_id, CL_PROGRAM_BUILD_LOG, buildlog_size, buildlog, NULL); - buildlog[buildlog_size] = 0; - - if(err != CL_SUCCESS) - { - HandleCLError(err, "Error: can't get build log"); - } else - { - ERROR_LOG(COMMON, "Error log:\n%s\n", buildlog); - } - - delete[] buildlog; + buildlog = new char[buildlog_size + 1]; + err = clGetProgramBuildInfo(program, OpenCL::device_id, CL_PROGRAM_BUILD_LOG, buildlog_size, buildlog, NULL); + buildlog[buildlog_size] = 0; + + if(err != CL_SUCCESS) + { + HandleCLError(err, "Error: can't get build log"); + } else + { + ERROR_LOG(COMMON, "Error log:\n%s\n", buildlog); + } + + delete[] buildlog; return NULL; } diff --git a/Source/Core/VideoCommon/Src/OpenCL/OCLTextureDecoder.cpp b/Source/Core/VideoCommon/Src/OpenCL/OCLTextureDecoder.cpp index 440e69efd6..db70640fbb 100644 --- a/Source/Core/VideoCommon/Src/OpenCL/OCLTextureDecoder.cpp +++ b/Source/Core/VideoCommon/Src/OpenCL/OCLTextureDecoder.cpp @@ -98,7 +98,7 @@ void TexDecoder_OpenCL_Initialize() size_t nDevices = 0; cl_device_id *devices = NULL; size_t *binary_sizes = NULL; - char **binaries = NULL; + char **binaries = NULL; std::string filename; char dolphin_rev[HEADER_SIZE]; @@ -132,7 +132,7 @@ void TexDecoder_OpenCL_Initialize() { OpenCL::HandleCLError(err, "clCreateProgramWithBinary"); } - + if (!err) { err = clBuildProgram(g_program, 1, &OpenCL::device_id, NULL, NULL, NULL); diff --git a/Source/Core/VideoCommon/Src/PerfQueryBase.cpp b/Source/Core/VideoCommon/Src/PerfQueryBase.cpp new file mode 100644 index 0000000000..c537d176f6 --- /dev/null +++ b/Source/Core/VideoCommon/Src/PerfQueryBase.cpp @@ -0,0 +1,3 @@ +#include "PerfQueryBase.h" + +PerfQueryBase* g_perf_query = 0; diff --git a/Source/Core/VideoCommon/Src/PerfQueryBase.h b/Source/Core/VideoCommon/Src/PerfQueryBase.h new file mode 100644 index 0000000000..b979449edb --- /dev/null +++ b/Source/Core/VideoCommon/Src/PerfQueryBase.h @@ -0,0 +1,54 @@ +#ifndef _PERFQUERY_BASE_H_ +#define _PERFQUERY_BASE_H_ + +#include "CommonTypes.h" + +enum PerfQueryType +{ + PQ_ZCOMP_INPUT_ZCOMPLOC = 0, + PQ_ZCOMP_OUTPUT_ZCOMPLOC, + PQ_ZCOMP_INPUT, + PQ_ZCOMP_OUTPUT, + PQ_BLEND_INPUT, + PQ_EFB_COPY_CLOCKS, + PQ_NUM_MEMBERS +}; + +enum PerfQueryGroup +{ + PQG_ZCOMP_ZCOMPLOC, + PQG_ZCOMP, + PQG_EFB_COPY_CLOCKS, + PQG_NUM_MEMBERS, +}; + +class PerfQueryBase +{ +public: + PerfQueryBase() {}; + virtual ~PerfQueryBase() {} + + // Begin querying the specified value for the following host GPU commands + virtual void EnableQuery(PerfQueryGroup type) {} + + // Stop querying the specified value for the following host GPU commands + virtual void DisableQuery(PerfQueryGroup type) {} + + // Reset query counters to zero and drop any pending queries + virtual void ResetQuery() {} + + // Return the measured value for the specified query type + // NOTE: Called from CPU thread + virtual u32 GetQueryResult(PerfQueryType type) { return 0; } + + // Request the value of any pending queries - causes a pipeline flush and thus should be used carefully! + virtual void FlushResults() {} + + // True if there are no further pending query results + // NOTE: Called from CPU thread + virtual bool IsFlushed() const { return true; } +}; + +extern PerfQueryBase* g_perf_query; + +#endif // _PERFQUERY_H_ diff --git a/Source/Core/VideoCommon/Src/PixelEngine.cpp b/Source/Core/VideoCommon/Src/PixelEngine.cpp index a488e52b42..b014148d8d 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.cpp +++ b/Source/Core/VideoCommon/Src/PixelEngine.cpp @@ -28,10 +28,12 @@ #include "ConfigManager.h" #include "PixelEngine.h" +#include "RenderBase.h" #include "CommandProcessor.h" #include "HW/ProcessorInterface.h" #include "DLCache.h" #include "State.h" + namespace PixelEngine { @@ -110,22 +112,22 @@ static UPEAlphaReadReg m_AlphaRead; static UPECtrlReg m_Control; //static u16 m_Token; // token value most recently encountered -static bool g_bSignalTokenInterrupt; -static bool g_bSignalFinishInterrupt; +volatile u32 g_bSignalTokenInterrupt; +volatile u32 g_bSignalFinishInterrupt; static int et_SetTokenOnMainThread; static int et_SetFinishOnMainThread; -volatile bool interruptSetToken = false; -volatile bool interruptSetFinish = false; +volatile u32 interruptSetToken = 0; +volatile u32 interruptSetFinish = 0; u16 bbox[4]; bool bbox_active; enum { - INT_CAUSE_PE_TOKEN = 0x200, // GP Token - INT_CAUSE_PE_FINISH = 0x400, // GP Finished + INT_CAUSE_PE_TOKEN = 0x200, // GP Token + INT_CAUSE_PE_FINISH = 0x400, // GP Finished }; void DoState(PointerWrap &p) @@ -161,10 +163,10 @@ void Init() m_AlphaModeConf.Hex = 0; m_AlphaRead.Hex = 0; - g_bSignalTokenInterrupt = false; - g_bSignalFinishInterrupt = false; - interruptSetToken = false; - interruptSetFinish = false; + g_bSignalTokenInterrupt = 0; + g_bSignalFinishInterrupt = 0; + interruptSetToken = 0; + interruptSetFinish = 0; et_SetTokenOnMainThread = CoreTiming::RegisterEvent("SetToken", SetToken_OnMainThread); et_SetFinishOnMainThread = CoreTiming::RegisterEvent("SetFinish", SetFinish_OnMainThread); @@ -211,7 +213,7 @@ void Read16(u16& _uReturnValue, const u32 _iAddress) break; case PE_TOKEN_REG: - _uReturnValue = CommandProcessor::fifo.PEToken; + _uReturnValue = Common::AtomicLoad(*(volatile u32*)&CommandProcessor::fifo.PEToken); INFO_LOG(PIXELENGINE, "(r16) TOKEN_REG : %04x", _uReturnValue); break; @@ -255,23 +257,59 @@ void Read16(u16& _uReturnValue, const u32 _iAddress) break; } - case PE_PERF_0L: - case PE_PERF_0H: - case PE_PERF_1L: - case PE_PERF_1H: - case PE_PERF_2L: - case PE_PERF_2H: - case PE_PERF_3L: - case PE_PERF_3H: - case PE_PERF_4L: - case PE_PERF_4H: - case PE_PERF_5L: - case PE_PERF_5H: - INFO_LOG(PIXELENGINE, "(r16) perf counter @ %08x", _iAddress); - // git r90a2096a24f4 (svn r3663) added the PE_PERF cases, without setting - // _uReturnValue to anything, this reverts to the previous behaviour which allows - // The timer in SMS:Scrubbing Serena Beach to countdown correctly - _uReturnValue = 1; + // NOTE(neobrain): only PE_PERF_ZCOMP_OUTPUT is implemented in D3D11, but the other values shouldn't be contradictionary to the value of that register (i.e. INPUT registers should always be greater or equal to their corresponding OUTPUT registers). + case PE_PERF_ZCOMP_INPUT_ZCOMPLOC_L: + _uReturnValue = g_video_backend->Video_GetQueryResult(PQ_ZCOMP_INPUT_ZCOMPLOC) & 0xFFFF; + break; + + case PE_PERF_ZCOMP_INPUT_ZCOMPLOC_H: + _uReturnValue = g_video_backend->Video_GetQueryResult(PQ_ZCOMP_INPUT_ZCOMPLOC) >> 16; + break; + + case PE_PERF_ZCOMP_OUTPUT_ZCOMPLOC_L: + _uReturnValue = g_video_backend->Video_GetQueryResult(PQ_ZCOMP_OUTPUT_ZCOMPLOC) & 0xFFFF; + break; + + case PE_PERF_ZCOMP_OUTPUT_ZCOMPLOC_H: + _uReturnValue = g_video_backend->Video_GetQueryResult(PQ_ZCOMP_OUTPUT_ZCOMPLOC) >> 16; + break; + + case PE_PERF_ZCOMP_INPUT_L: + _uReturnValue = g_video_backend->Video_GetQueryResult(PQ_ZCOMP_INPUT) & 0xFFFF; + break; + + case PE_PERF_ZCOMP_INPUT_H: + _uReturnValue = g_video_backend->Video_GetQueryResult(PQ_ZCOMP_INPUT) >> 16; + break; + + case PE_PERF_ZCOMP_OUTPUT_L: + _uReturnValue = g_video_backend->Video_GetQueryResult(PQ_ZCOMP_OUTPUT) & 0xFFFF; + break; + + case PE_PERF_ZCOMP_OUTPUT_H: + _uReturnValue = g_video_backend->Video_GetQueryResult(PQ_ZCOMP_OUTPUT) >> 16; + break; + + case PE_PERF_BLEND_INPUT_L: + // Super Mario Sunshine uses this register in episode 6 of Sirena Beach: + // The amount of remaining goop is determined by checking how many pixels reach the blending stage. + // Once this register falls below a particular value (around 0x90), the game regards the challenge finished. + // In very old builds, Dolphin only returned 0. That caused the challenge to be immediately finished without any goop being cleaned (the timer just didn't even start counting from 3:00:00). + // Later builds returned 1 for the high register. That caused the timer to actually count down, but made the challenge unbeatable because the game always thought you didn't clear any goop at all. + // Note that currently this functionality is only implemented in the D3D11 backend. + _uReturnValue = g_video_backend->Video_GetQueryResult(PQ_BLEND_INPUT) & 0xFFFF; + break; + + case PE_PERF_BLEND_INPUT_H: + _uReturnValue = g_video_backend->Video_GetQueryResult(PQ_BLEND_INPUT) >> 16; + break; + + case PE_PERF_EFB_COPY_CLOCKS_L: + _uReturnValue = g_video_backend->Video_GetQueryResult(PQ_EFB_COPY_CLOCKS) & 0xFFFF; + break; + + case PE_PERF_EFB_COPY_CLOCKS_H: + _uReturnValue = g_video_backend->Video_GetQueryResult(PQ_EFB_COPY_CLOCKS) >> 16; break; default: @@ -312,8 +350,8 @@ void Write16(const u16 _iValue, const u32 _iAddress) { UPECtrlReg tmpCtrl(_iValue); - if (tmpCtrl.PEToken) g_bSignalTokenInterrupt = false; - if (tmpCtrl.PEFinish) g_bSignalFinishInterrupt = false; + if (tmpCtrl.PEToken) g_bSignalTokenInterrupt = 0; + if (tmpCtrl.PEFinish) g_bSignalFinishInterrupt = 0; m_Control.PETokenEnable = tmpCtrl.PETokenEnable; m_Control.PEFinishEnable = tmpCtrl.PEFinishEnable; @@ -359,14 +397,14 @@ void UpdateInterrupts() void UpdateTokenInterrupt(bool active) { - ProcessorInterface::SetInterrupt(INT_CAUSE_PE_TOKEN, active); - interruptSetToken = active; + ProcessorInterface::SetInterrupt(INT_CAUSE_PE_TOKEN, active); + Common::AtomicStore(interruptSetToken, active ? 1 : 0); } void UpdateFinishInterrupt(bool active) { - ProcessorInterface::SetInterrupt(INT_CAUSE_PE_FINISH, active); - interruptSetFinish = active; + ProcessorInterface::SetInterrupt(INT_CAUSE_PE_FINISH, active); + Common::AtomicStore(interruptSetFinish, active ? 1 : 0); } // TODO(mb2): Refactor SetTokenINT_OnMainThread(u64 userdata, int cyclesLate). @@ -376,20 +414,23 @@ void UpdateFinishInterrupt(bool active) // Called only if BPMEM_PE_TOKEN_INT_ID is ack by GP void SetToken_OnMainThread(u64 userdata, int cyclesLate) { - //if (userdata >> 16) - //{ - g_bSignalTokenInterrupt = true; - //_dbg_assert_msg_(PIXELENGINE, (CommandProcessor::fifo.PEToken == (userdata&0xFFFF)), "WTF? BPMEM_PE_TOKEN_INT_ID's token != BPMEM_PE_TOKEN_ID's token" ); - INFO_LOG(PIXELENGINE, "VIDEO Backend raises INT_CAUSE_PE_TOKEN (btw, token: %04x)", CommandProcessor::fifo.PEToken); + // XXX: No 16-bit atomic store available, so cheat and use 32-bit. + // That's what we've always done. We're counting on fifo.PEToken to be + // 4-byte padded. + Common::AtomicStore(*(volatile u32*)&CommandProcessor::fifo.PEToken, userdata & 0xffff); + INFO_LOG(PIXELENGINE, "VIDEO Backend raises INT_CAUSE_PE_TOKEN (btw, token: %04x)", CommandProcessor::fifo.PEToken); + if (userdata >> 16) + { + Common::AtomicStore(*(volatile u32*)&g_bSignalTokenInterrupt, 1); UpdateInterrupts(); - CommandProcessor::interruptTokenWaiting = false; - IncrementCheckContextId(); - //} + } + CommandProcessor::interruptTokenWaiting = false; + IncrementCheckContextId(); } void SetFinish_OnMainThread(u64 userdata, int cyclesLate) { - g_bSignalFinishInterrupt = 1; + Common::AtomicStore(*(volatile u32*)&g_bSignalFinishInterrupt, 1); UpdateInterrupts(); CommandProcessor::interruptFinishWaiting = false; CommandProcessor::isPossibleWaitingSetDrawDone = false; @@ -399,23 +440,13 @@ void SetFinish_OnMainThread(u64 userdata, int cyclesLate) // THIS IS EXECUTED FROM VIDEO THREAD void SetToken(const u16 _token, const int _bSetTokenAcknowledge) { - // TODO?: set-token-value and set-token-INT could be merged since set-token-INT own the token value. if (_bSetTokenAcknowledge) // set token INT { - - Common::AtomicStore(*(volatile u32*)&CommandProcessor::fifo.PEToken, _token); - CommandProcessor::interruptTokenWaiting = true; - CoreTiming::ScheduleEvent_Threadsafe(0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16)); - } - else // set token value - { - // we do it directly from videoThread because of - // Super Monkey Ball - // XXX: No 16-bit atomic store available, so cheat and use 32-bit. - // That's what we've always done. We're counting on fifo.PEToken to be - // 4-byte padded. - Common::AtomicStore(*(volatile u32*)&CommandProcessor::fifo.PEToken, _token); + Common::AtomicStore(*(volatile u32*)&g_bSignalTokenInterrupt, 1); } + + CommandProcessor::interruptTokenWaiting = true; + CoreTiming::ScheduleEvent_Threadsafe(0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16)); IncrementCheckContextId(); } @@ -438,7 +469,6 @@ void ResetSetFinish() { UpdateFinishInterrupt(false); g_bSignalFinishInterrupt = false; - } else { @@ -452,8 +482,7 @@ void ResetSetToken() if (g_bSignalTokenInterrupt) { UpdateTokenInterrupt(false); - g_bSignalTokenInterrupt = false; - + g_bSignalTokenInterrupt = 0; } else { @@ -461,17 +490,4 @@ void ResetSetToken() } CommandProcessor::interruptTokenWaiting = false; } - -bool WaitingForPEInterrupt() -{ - return !CommandProcessor::waitingForPEInterruptDisable && (CommandProcessor::interruptFinishWaiting || CommandProcessor::interruptTokenWaiting || interruptSetFinish || interruptSetToken); -} - -void ResumeWaitingForPEInterrupt() -{ - interruptSetFinish = false; - interruptSetToken = false; - CommandProcessor::interruptFinishWaiting = false; - CommandProcessor::interruptTokenWaiting = false; -} } // end of namespace PixelEngine diff --git a/Source/Core/VideoCommon/Src/PixelEngine.h b/Source/Core/VideoCommon/Src/PixelEngine.h index 64f959009f..f34621774c 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.h +++ b/Source/Core/VideoCommon/Src/PixelEngine.h @@ -24,31 +24,32 @@ class PointerWrap; // internal hardware addresses enum { - PE_ZCONF = 0x00, // Z Config - PE_ALPHACONF = 0x02, // Alpha Config - PE_DSTALPHACONF = 0x04, // Destination Alpha Config - PE_ALPHAMODE = 0x06, // Alpha Mode Config - PE_ALPHAREAD = 0x08, // Alpha Read + PE_ZCONF = 0x00, // Z Config + PE_ALPHACONF = 0x02, // Alpha Config + PE_DSTALPHACONF = 0x04, // Destination Alpha Config + PE_ALPHAMODE = 0x06, // Alpha Mode Config + PE_ALPHAREAD = 0x08, // Alpha Read PE_CTRL_REGISTER = 0x0a, // Control - PE_TOKEN_REG = 0x0e, // Token + PE_TOKEN_REG = 0x0e, // Token PE_BBOX_LEFT = 0x10, // Flip Left PE_BBOX_RIGHT = 0x12, // Flip Right PE_BBOX_TOP = 0x14, // Flip Top PE_BBOX_BOTTOM = 0x16, // Flip Bottom - // These have not yet been RE:d. They are the perf counters. - PE_PERF_0L = 0x18, - PE_PERF_0H = 0x1a, - PE_PERF_1L = 0x1c, - PE_PERF_1H = 0x1e, - PE_PERF_2L = 0x20, - PE_PERF_2H = 0x22, - PE_PERF_3L = 0x24, - PE_PERF_3H = 0x26, - PE_PERF_4L = 0x28, - PE_PERF_4H = 0x2a, - PE_PERF_5L = 0x2c, - PE_PERF_5H = 0x2e, + // NOTE: Order not verified + // These indicate the number of quads that are being used as input/output for each particular stage + PE_PERF_ZCOMP_INPUT_ZCOMPLOC_L = 0x18, + PE_PERF_ZCOMP_INPUT_ZCOMPLOC_H = 0x1a, + PE_PERF_ZCOMP_OUTPUT_ZCOMPLOC_L = 0x1c, + PE_PERF_ZCOMP_OUTPUT_ZCOMPLOC_H = 0x1e, + PE_PERF_ZCOMP_INPUT_L = 0x20, + PE_PERF_ZCOMP_INPUT_H = 0x22, + PE_PERF_ZCOMP_OUTPUT_L = 0x24, + PE_PERF_ZCOMP_OUTPUT_H = 0x26, + PE_PERF_BLEND_INPUT_L = 0x28, + PE_PERF_BLEND_INPUT_H = 0x2a, + PE_PERF_EFB_COPY_CLOCKS_L = 0x2c, + PE_PERF_EFB_COPY_CLOCKS_H = 0x2e, }; namespace PixelEngine @@ -80,8 +81,6 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge); void SetFinish(void); void ResetSetFinish(void); void ResetSetToken(void); -bool WaitingForPEInterrupt(); -void ResumeWaitingForPEInterrupt(); // Bounding box functionality. Paper Mario (both) are a couple of the few games that use it. extern u16 bbox[4]; diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index 448501aad0..d863a6e0a9 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -173,7 +173,7 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 compo *ptr++ = components; } - uid->num_values = ptr - uid->values; + uid->num_values = int(ptr - uid->values); } void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode, u32 components) @@ -205,7 +205,7 @@ void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode, u *ptr++ = bpmem.tevindref.hex; // 31 - for (unsigned int i = 0; i < bpmem.genMode.numtevstages+1u; ++i) // up to 16 times + for (u32 i = 0; i < bpmem.genMode.numtevstages+1u; ++i) // up to 16 times { *ptr++ = bpmem.combiners[i].colorC.hex; // 32+5*i *ptr++ = bpmem.combiners[i].alphaC.hex; // 33+5*i @@ -252,7 +252,8 @@ void ValidatePixelShaderIDs(API_TYPE api, PIXELSHADERUIDSAFE old_id, const std:: static int num_failures = 0; char szTemp[MAX_PATH]; sprintf(szTemp, "%spsuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); - std::ofstream file(szTemp); + std::ofstream file; + OpenFStream(file, szTemp, std::ios_base::out); file << msg; file << "\n\nOld shader code:\n" << old_code; file << "\n\nNew shader code:\n" << new_code; @@ -275,7 +276,7 @@ void ValidatePixelShaderIDs(API_TYPE api, PIXELSHADERUIDSAFE old_id, const std:: static void WriteStage(char *&p, int n, API_TYPE ApiType); static void SampleTexture(char *&p, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType); // static void WriteAlphaCompare(char *&p, int num, int comp); -static void WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode); +static void WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth); static void WriteFog(char *&p); static const char *tevKSelTableC[] = // KCSEL @@ -373,38 +374,38 @@ static const char *tevOpTable[] = { // TEV static const char *tevCInputTable[] = // CC { - "(prev.rgb)", // CPREV, + "(prev.rgb)", // CPREV, "(prev.aaa)", // APREV, - "(c0.rgb)", // C0, + "(c0.rgb)", // C0, "(c0.aaa)", // A0, - "(c1.rgb)", // C1, + "(c1.rgb)", // C1, "(c1.aaa)", // A1, - "(c2.rgb)", // C2, + "(c2.rgb)", // C2, "(c2.aaa)", // A2, - "(textemp.rgb)", // TEXC, + "(textemp.rgb)", // TEXC, "(textemp.aaa)", // TEXA, - "(rastemp.rgb)", // RASC, + "(rastemp.rgb)", // RASC, "(rastemp.aaa)", // RASA, "float3(1.0f, 1.0f, 1.0f)", // ONE - "float3(0.5f, 0.5f, 0.5f)", // HALF - "(konsttemp.rgb)", //"konsttemp.rgb", // KONST + "float3(0.5f, 0.5f, 0.5f)", // HALF + "(konsttemp.rgb)", //"konsttemp.rgb", // KONST "float3(0.0f, 0.0f, 0.0f)", // ZERO ///aded extra values to map clamped values - "(cprev.rgb)", // CPREV, - "(cprev.aaa)", // APREV, - "(cc0.rgb)", // C0, - "(cc0.aaa)", // A0, - "(cc1.rgb)", // C1, - "(cc1.aaa)", // A1, - "(cc2.rgb)", // C2, - "(cc2.aaa)", // A2, - "(textemp.rgb)", // TEXC, + "(cprev.rgb)", // CPREV, + "(cprev.aaa)", // APREV, + "(cc0.rgb)", // C0, + "(cc0.aaa)", // A0, + "(cc1.rgb)", // C1, + "(cc1.aaa)", // A1, + "(cc2.rgb)", // C2, + "(cc2.aaa)", // A2, + "(textemp.rgb)", // TEXC, "(textemp.aaa)", // TEXA, - "(crastemp.rgb)", // RASC, - "(crastemp.aaa)", // RASA, + "(crastemp.rgb)", // RASC, + "(crastemp.aaa)", // RASA, "float3(1.0f, 1.0f, 1.0f)", // ONE - "float3(0.5f, 0.5f, 0.5f)", // HALF - "(ckonsttemp.rgb)", //"konsttemp.rgb", // KONST + "float3(0.5f, 0.5f, 0.5f)", // HALF + "(ckonsttemp.rgb)", //"konsttemp.rgb", // KONST "float3(0.0f, 0.0f, 0.0f)", // ZERO "PADERROR1", "PADERROR2", "PADERROR3", "PADERROR4" }; @@ -424,7 +425,7 @@ static const char *tevAInputTable[] = // CA "cc0", // A0, "cc1", // A1, "cc2", // A2, - "textemp", // TEXA, + "textemp", // TEXA, "crastemp", // RASA, "ckonsttemp", // KONST, (hw1 had quarter) "float4(0.0f, 0.0f, 0.0f, 0.0f)", // ZERO @@ -439,8 +440,8 @@ static const char *tevRasTable[] = "ERROR13", //2 "ERROR14", //3 "ERROR15", //4 - "alphabump", // use bump alpha - "(alphabump*(255.0f/248.0f))", //normalized + "float4(alphabump,alphabump,alphabump,alphabump)", // use bump alpha + "(float4(alphabump,alphabump,alphabump,alphabump)*(255.0f/248.0f))", //normalized "float4(0.0f, 0.0f, 0.0f, 0.0f)", // zero }; @@ -484,6 +485,24 @@ static void BuildSwapModeTable() } } +const char* WriteRegister(API_TYPE ApiType, const char *prefix, const u32 num) +{ + if (ApiType == API_OPENGL) + return ""; // Nothing to do here + static char result[64]; + sprintf(result, " : register(%s%d)", prefix, num); + return result; +} + +const char *WriteLocation(API_TYPE ApiType) +{ + if (g_ActiveConfig.backend_info.bSupportsGLSLUBO) + return ""; + static char result[64]; + sprintf(result, "uniform "); + return result; +} + const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components) { setlocale(LC_NUMERIC, "C"); // Reset locale for compilation @@ -493,6 +512,8 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType int numStages = bpmem.genMode.numtevstages + 1; int numTexgen = bpmem.genMode.numtexgens; + bool per_pixel_depth = bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.early_ztest && bpmem.zmode.testenable; + char *p = text; WRITE(p, "//Pixel Shader for TEV stages\n"); WRITE(p, "//%i TEV stages, %i texgens, XXX IND stages\n", @@ -507,138 +528,216 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType nIndirectStagesUsed |= 1 << bpmem.tevind[i].bt; } } - // Declare samplers - if(ApiType != API_D3D11) + if (ApiType == API_OPENGL) { - WRITE(p, "uniform sampler2D "); + + // A function here + // Fmod implementation gleaned from Nvidia + // At http://http.developer.nvidia.com/Cg/fmod.html + WRITE(p, "float fmod( float x, float y )\n"); + WRITE(p, "{\n"); + WRITE(p, "\tfloat z = fract( abs( x / y) ) * abs( y );\n"); + WRITE(p, "\treturn (x < 0) ? -z : z;\n"); + WRITE(p, "}\n"); + + for (int i = 0; i < 8; ++i) + WRITE(p, "uniform sampler2D samp%d;\n", i); } else { - WRITE(p, "sampler "); - } + // Declare samplers + if (ApiType != API_D3D11) + { + WRITE(p, "uniform sampler2D "); + } + else + { + WRITE(p, "sampler "); + } - bool bfirst = true; - for (int i = 0; i < 8; ++i) - { - WRITE(p, "%s samp%d : register(s%d)", bfirst?"":",", i, i); - bfirst = false; - } - WRITE(p, ";\n"); - if(ApiType == API_D3D11) - { - WRITE(p, "Texture2D "); - bfirst = true; + bool bfirst = true; for (int i = 0; i < 8; ++i) { - WRITE(p, "%s Tex%d : register(t%d)", bfirst?"":",", i, i); + WRITE(p, "%s samp%d %s", bfirst?"":",", i, WriteRegister(ApiType, "s", i)); bfirst = false; } WRITE(p, ";\n"); + if (ApiType == API_D3D11) + { + WRITE(p, "Texture2D "); + bfirst = true; + for (int i = 0; i < 8; ++i) + { + WRITE(p, "%s Tex%d : register(t%d)", bfirst?"":",", i, i); + bfirst = false; + } + WRITE(p, ";\n"); + } } WRITE(p, "\n"); - - WRITE(p, "uniform float4 " I_COLORS"[4] : register(c%d);\n", C_COLORS); - WRITE(p, "uniform float4 " I_KCOLORS"[4] : register(c%d);\n", C_KCOLORS); - WRITE(p, "uniform float4 " I_ALPHA"[1] : register(c%d);\n", C_ALPHA); - WRITE(p, "uniform float4 " I_TEXDIMS"[8] : register(c%d);\n", C_TEXDIMS); - WRITE(p, "uniform float4 " I_ZBIAS"[2] : register(c%d);\n", C_ZBIAS); - WRITE(p, "uniform float4 " I_INDTEXSCALE"[2] : register(c%d);\n", C_INDTEXSCALE); - WRITE(p, "uniform float4 " I_INDTEXMTX"[6] : register(c%d);\n", C_INDTEXMTX); - WRITE(p, "uniform float4 " I_FOG"[3] : register(c%d);\n", C_FOG); - - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - { - WRITE(p,"typedef struct { float4 col; float4 cosatt; float4 distatt; float4 pos; float4 dir; } Light;\n"); - WRITE(p,"typedef struct { Light lights[8]; } s_" I_PLIGHTS";\n"); - WRITE(p, "uniform s_" I_PLIGHTS" " I_PLIGHTS" : register(c%d);\n", C_PLIGHTS); - WRITE(p, "typedef struct { float4 C0, C1, C2, C3; } s_" I_PMATERIALS";\n"); - WRITE(p, "uniform s_" I_PMATERIALS" " I_PMATERIALS" : register(c%d);\n", C_PMATERIALS); - } - - WRITE(p, "void main(\n"); - if(ApiType != API_D3D11) + if (g_ActiveConfig.backend_info.bSupportsGLSLUBO) + WRITE(p, "layout(std140) uniform PSBlock {\n"); + + WRITE(p, "\t%sfloat4 " I_COLORS"[4] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_COLORS)); + WRITE(p, "\t%sfloat4 " I_KCOLORS"[4] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_KCOLORS)); + WRITE(p, "\t%sfloat4 " I_ALPHA"[1] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_ALPHA)); + WRITE(p, "\t%sfloat4 " I_TEXDIMS"[8] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_TEXDIMS)); + WRITE(p, "\t%sfloat4 " I_ZBIAS"[2] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_ZBIAS)); + WRITE(p, "\t%sfloat4 " I_INDTEXSCALE"[2] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_INDTEXSCALE)); + WRITE(p, "\t%sfloat4 " I_INDTEXMTX"[6] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_INDTEXMTX)); + WRITE(p, "\t%sfloat4 " I_FOG"[3] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_FOG)); + + // For pixel lighting + WRITE(p, "\t%sfloat4 " I_PLIGHTS"[40] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_PLIGHTS)); + WRITE(p, "\t%sfloat4 " I_PMATERIALS"[4] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_PMATERIALS)); + + if (g_ActiveConfig.backend_info.bSupportsGLSLUBO) + WRITE(p, "};\n"); + + if (ApiType == API_OPENGL) { - WRITE(p, " out float4 ocol0 : COLOR0,%s%s\n in float4 rawpos : %s,\n", - dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : COLOR1," : "", - "\n out float depth : DEPTH,", - ApiType & API_OPENGL ? "WPOS" : ApiType & API_D3D9_SM20 ? "POSITION" : "VPOS"); + WRITE(p, "out float4 ocol0;\n"); + if (dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) + WRITE(p, "out float4 ocol1;\n"); + + if (per_pixel_depth) + WRITE(p, "#define depth gl_FragDepth\n"); + WRITE(p, "float4 rawpos = gl_FragCoord;\n"); + + WRITE(p, "VARYIN float4 colors_02;\n"); + WRITE(p, "VARYIN float4 colors_12;\n"); + WRITE(p, "float4 colors_0 = colors_02;\n"); + WRITE(p, "float4 colors_1 = colors_12;\n"); + + // compute window position if needed because binding semantic WPOS is not widely supported + // Let's set up attributes + if (xfregs.numTexGen.numTexGens < 7) + { + for (int i = 0; i < 8; ++i) + { + WRITE(p, "VARYIN float3 uv%d_2;\n", i); + WRITE(p, "float3 uv%d = uv%d_2;\n", i, i); + } + WRITE(p, "VARYIN float4 clipPos_2;\n"); + WRITE(p, "float4 clipPos = clipPos_2;\n"); + if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + { + WRITE(p, "VARYIN float4 Normal_2;\n"); + WRITE(p, "float4 Normal = Normal_2;\n"); + } + } + else + { + // wpos is in w of first 4 texcoords + if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + { + for (int i = 0; i < 8; ++i) + { + WRITE(p, "VARYIN float4 uv%d_2;\n", i); + WRITE(p, "float4 uv%d = uv%d_2;\n", i, i); + } + } + else + { + for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) + { + WRITE(p, "VARYIN float%d uv%d_2;\n", i < 4 ? 4 : 3 , i); + WRITE(p, "float%d uv%d = uv%d_2;\n", i < 4 ? 4 : 3 , i, i); + } + } + WRITE(p, "float4 clipPos;\n"); + } + WRITE(p, "void main()\n{\n"); } else { - WRITE(p, " out float4 ocol0 : SV_Target0,%s%s\n in float4 rawpos : SV_Position,\n", - dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : SV_Target1," : "", - "\n out float depth : SV_Depth,"); - } + WRITE(p, "void main(\n"); + if (ApiType != API_D3D11) + { + WRITE(p, " out float4 ocol0 : COLOR0,%s%s\n in float4 rawpos : %s,\n", + dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : COLOR1," : "", + per_pixel_depth ? "\n out float depth : DEPTH," : "", + ApiType & API_D3D9_SM20 ? "POSITION" : "VPOS"); + } + else + { + WRITE(p, " out float4 ocol0 : SV_Target0,%s%s\n in float4 rawpos : SV_Position,\n", + dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : SV_Target1," : "", + per_pixel_depth ? "\n out float depth : SV_Depth," : ""); + } - WRITE(p, " in float4 colors_0 : COLOR0,\n"); - WRITE(p, " in float4 colors_1 : COLOR1"); + WRITE(p, " in float4 colors_0 : COLOR0,\n"); + WRITE(p, " in float4 colors_1 : COLOR1"); - // compute window position if needed because binding semantic WPOS is not widely supported - if (numTexgen < 7) - { - for (int i = 0; i < numTexgen; ++i) - WRITE(p, ",\n in float3 uv%d : TEXCOORD%d", i, i); - WRITE(p, ",\n in float4 clipPos : TEXCOORD%d", numTexgen); - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - WRITE(p, ",\n in float4 Normal : TEXCOORD%d", numTexgen + 1); - } - else - { - // wpos is in w of first 4 texcoords - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + // compute window position if needed because binding semantic WPOS is not widely supported + if (numTexgen < 7) { - for (int i = 0; i < 8; ++i) - WRITE(p, ",\n in float4 uv%d : TEXCOORD%d", i, i); + for (int i = 0; i < numTexgen; ++i) + WRITE(p, ",\n in float3 uv%d : TEXCOORD%d", i, i); + WRITE(p, ",\n in float4 clipPos : TEXCOORD%d", numTexgen); + if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + WRITE(p, ",\n in float4 Normal : TEXCOORD%d", numTexgen + 1); + WRITE(p, " ) {\n"); } else { - for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) - WRITE(p, ",\n in float%d uv%d : TEXCOORD%d", i < 4 ? 4 : 3 , i, i); + // wpos is in w of first 4 texcoords + if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + { + for (int i = 0; i < 8; ++i) + WRITE(p, ",\n in float4 uv%d : TEXCOORD%d", i, i); + } + else + { + for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) + WRITE(p, ",\n in float%d uv%d : TEXCOORD%d", i < 4 ? 4 : 3 , i, i); + } + WRITE(p, " ) {\n"); + WRITE(p, "\tfloat4 clipPos = float4(0.0f, 0.0f, 0.0f, 0.0f);"); } } - WRITE(p, " ) {\n"); WRITE(p, " float4 c0 = " I_COLORS"[1], c1 = " I_COLORS"[2], c2 = " I_COLORS"[3], prev = float4(0.0f, 0.0f, 0.0f, 0.0f), textemp = float4(0.0f, 0.0f, 0.0f, 0.0f), rastemp = float4(0.0f, 0.0f, 0.0f, 0.0f), konsttemp = float4(0.0f, 0.0f, 0.0f, 0.0f);\n" " float3 comp16 = float3(1.0f, 255.0f, 0.0f), comp24 = float3(1.0f, 255.0f, 255.0f*255.0f);\n" - " float4 alphabump=float4(0.0f,0.0f,0.0f,0.0f);\n" + " float alphabump=0.0f;\n" " float3 tevcoord=float3(0.0f, 0.0f, 0.0f);\n" " float2 wrappedcoord=float2(0.0f,0.0f), tempcoord=float2(0.0f,0.0f);\n" " float4 cc0=float4(0.0f,0.0f,0.0f,0.0f), cc1=float4(0.0f,0.0f,0.0f,0.0f);\n" " float4 cc2=float4(0.0f,0.0f,0.0f,0.0f), cprev=float4(0.0f,0.0f,0.0f,0.0f);\n" " float4 crastemp=float4(0.0f,0.0f,0.0f,0.0f),ckonsttemp=float4(0.0f,0.0f,0.0f,0.0f);\n\n"); - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) { if (xfregs.numTexGen.numTexGens < 7) { - WRITE(p,"float3 _norm0 = normalize(Normal.xyz);\n\n"); - WRITE(p,"float3 pos = float3(clipPos.x,clipPos.y,Normal.w);\n"); + WRITE(p,"\tfloat3 _norm0 = normalize(Normal.xyz);\n\n"); + WRITE(p,"\tfloat3 pos = float3(clipPos.x,clipPos.y,Normal.w);\n"); } else { - WRITE(p," float3 _norm0 = normalize(float3(uv4.w,uv5.w,uv6.w));\n\n"); - WRITE(p,"float3 pos = float3(uv0.w,uv1.w,uv7.w);\n"); + WRITE(p,"\tfloat3 _norm0 = normalize(float3(uv4.w,uv5.w,uv6.w));\n\n"); + WRITE(p,"\tfloat3 pos = float3(uv0.w,uv1.w,uv7.w);\n"); } - WRITE(p, "float4 mat, lacc;\n" - "float3 ldir, h;\n" - "float dist, dist2, attn;\n"); + WRITE(p, "\tfloat4 mat, lacc;\n" + "\tfloat3 ldir, h;\n" + "\tfloat dist, dist2, attn;\n"); p = GenerateLightingShader(p, components, I_PMATERIALS, I_PLIGHTS, "colors_", "colors_"); } if (numTexgen < 7) - WRITE(p, "clipPos = float4(rawpos.x, rawpos.y, clipPos.z, clipPos.w);\n"); + WRITE(p, "\tclipPos = float4(rawpos.x, rawpos.y, clipPos.z, clipPos.w);\n"); else - WRITE(p, "float4 clipPos = float4(rawpos.x, rawpos.y, uv2.w, uv3.w);\n"); + WRITE(p, "\tclipPos = float4(rawpos.x, rawpos.y, uv2.w, uv3.w);\n"); // HACK to handle cases where the tex gen is not enabled if (numTexgen == 0) { - WRITE(p, "float3 uv0 = float3(0.0f, 0.0f, 0.0f);\n"); + WRITE(p, "\tfloat3 uv0 = float3(0.0f, 0.0f, 0.0f);\n"); } else { @@ -647,8 +746,8 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType // optional perspective divides if (xfregs.texMtxInfo[i].projection == XF_TEXPROJ_STQ) { - WRITE(p, "if (uv%d.z)", i); - WRITE(p, " uv%d.xy = uv%d.xy / uv%d.z;\n", i, i, i); + WRITE(p, "\tif (uv%d.z != 0.0f)", i); + WRITE(p, "\t\tuv%d.xy = uv%d.xy / uv%d.z;\n", i, i, i); } WRITE(p, "uv%d.xy = uv%d.xy * " I_TEXDIMS"[%d].zw;\n", i, i, i); @@ -656,16 +755,16 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType } // indirect texture map lookup - for(u32 i = 0; i < bpmem.genMode.numindstages; ++i) + for (u32 i = 0; i < bpmem.genMode.numindstages; ++i) { if (nIndirectStagesUsed & (1<<i)) { int texcoord = bpmem.tevindref.getTexCoord(i); if (texcoord < numTexgen) - WRITE(p, "tempcoord = uv%d.xy * " I_INDTEXSCALE"[%d].%s;\n", texcoord, i/2, (i&1)?"zw":"xy"); + WRITE(p, "\ttempcoord = uv%d.xy * " I_INDTEXSCALE"[%d].%s;\n", texcoord, i/2, (i&1)?"zw":"xy"); else - WRITE(p, "tempcoord = float2(0.0f, 0.0f);\n"); + WRITE(p, "\ttempcoord = float2(0.0f, 0.0f);\n"); char buffer[32]; sprintf(buffer, "float3 indtex%d", i); @@ -686,36 +785,42 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType for (int i = 0; i < numStages; i++) WriteStage(p, i, ApiType); //build the equation for this stage - if(numStages) + if (numStages) { // The results of the last texenv stage are put onto the screen, // regardless of the used destination register if(bpmem.combiners[numStages - 1].colorC.dest != 0) { bool retrieveFromAuxRegister = !RegisterStates[bpmem.combiners[numStages - 1].colorC.dest].ColorNeedOverflowControl && RegisterStates[bpmem.combiners[numStages - 1].colorC.dest].AuxStored; - WRITE(p, "prev.rgb = %s%s;\n", retrieveFromAuxRegister ? "c" : "" , tevCOutputTable[bpmem.combiners[numStages - 1].colorC.dest]); + WRITE(p, "\tprev.rgb = %s%s;\n", retrieveFromAuxRegister ? "c" : "" , tevCOutputTable[bpmem.combiners[numStages - 1].colorC.dest]); RegisterStates[0].ColorNeedOverflowControl = RegisterStates[bpmem.combiners[numStages - 1].colorC.dest].ColorNeedOverflowControl; } if(bpmem.combiners[numStages - 1].alphaC.dest != 0) { bool retrieveFromAuxRegister = !RegisterStates[bpmem.combiners[numStages - 1].alphaC.dest].AlphaNeedOverflowControl && RegisterStates[bpmem.combiners[numStages - 1].alphaC.dest].AuxStored; - WRITE(p, "prev.a = %s%s;\n", retrieveFromAuxRegister ? "c" : "" , tevAOutputTable[bpmem.combiners[numStages - 1].alphaC.dest]); + WRITE(p, "\tprev.a = %s%s;\n", retrieveFromAuxRegister ? "c" : "" , tevAOutputTable[bpmem.combiners[numStages - 1].alphaC.dest]); RegisterStates[0].AlphaNeedOverflowControl = RegisterStates[bpmem.combiners[numStages - 1].alphaC.dest].AlphaNeedOverflowControl; } } // emulation of unsigned 8 overflow when casting if needed if(RegisterStates[0].AlphaNeedOverflowControl || RegisterStates[0].ColorNeedOverflowControl) - WRITE(p, "prev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + WRITE(p, "\tprev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f);\n"); AlphaTest::TEST_RESULT Pretest = bpmem.alpha_test.TestResult(); if (Pretest == AlphaTest::UNDETERMINED) - WriteAlphaTest(p, ApiType, dstAlphaMode); + WriteAlphaTest(p, ApiType, dstAlphaMode, per_pixel_depth); + // the screen space depth value = far z + (clip z / clip w) * z range - WRITE(p, "float zCoord = " I_ZBIAS"[1].x + (clipPos.z / clipPos.w) * " I_ZBIAS"[1].y;\n"); + if(ApiType == API_OPENGL || ApiType == API_D3D11) + WRITE(p, "float zCoord = rawpos.z;\n"); + else + // dx9 doesn't support 4 component position, so we have to calculate it again + WRITE(p, "float zCoord = " I_ZBIAS"[1].x + (clipPos.z / clipPos.w) * " I_ZBIAS"[1].y;\n"); - // Note: depth textures are disabled if early depth test is enabled - if (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.early_ztest && bpmem.zmode.testenable) + // depth texture can safely be ignored if the result won't be written to the depth buffer (early_ztest) and isn't used for fog either + bool skip_ztexture = !per_pixel_depth && !bpmem.fog.c_proj_fsel.fsel; + if (bpmem.ztex2.op != ZTEXTURE_DISABLE && !skip_ztexture) { // use the texture input of the last texture stage (textemp), hopefully this has been read and is in correct format... WRITE(p, "zCoord = dot(" I_ZBIAS"[0].xyzw, textemp.xyzw) + " I_ZBIAS"[1].w %s;\n", @@ -725,15 +830,18 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType WRITE(p, "zCoord = zCoord * (16777215.0f/16777216.0f);\n"); WRITE(p, "zCoord = frac(zCoord);\n"); WRITE(p, "zCoord = zCoord * (16777216.0f/16777215.0f);\n"); + + // Note: depth texture out put is only written to depth buffer if late depth test is used + if (per_pixel_depth) + WRITE(p, "depth = zCoord;\n"); } - WRITE(p, "depth = zCoord;\n"); if (dstAlphaMode == DSTALPHA_ALPHA_PASS) - WRITE(p, " ocol0 = float4(prev.rgb, " I_ALPHA"[0].a);\n"); + WRITE(p, "\tocol0 = float4(prev.rgb, " I_ALPHA"[0].a);\n"); else { WriteFog(p); - WRITE(p, " ocol0 = prev;\n"); + WRITE(p, "\tocol0 = prev;\n"); } // On D3D11, use dual-source color blending to perform dst alpha in a @@ -741,9 +849,9 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType if (dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) { // Colors will be blended against the alpha from ocol1... - WRITE(p, " ocol1 = ocol0;\n"); + WRITE(p, "\tocol1 = prev;\n"); // ...and the alpha from ocol0 will be written to the framebuffer. - WRITE(p, " ocol0.a = " I_ALPHA"[0].a;\n"); + WRITE(p, "\tocol0.a = " I_ALPHA"[0].a;\n"); } WRITE(p, "}\n"); @@ -852,10 +960,10 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) WRITE(p, "float2 indtevtrans%d = " I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.yy;\n", n, mtxidx, texcoord, n); } else - WRITE(p, "float2 indtevtrans%d = 0;\n", n); + WRITE(p, "float2 indtevtrans%d = float2(0.0f, 0.0f);\n", n); } else - WRITE(p, "float2 indtevtrans%d = 0;\n", n); + WRITE(p, "float2 indtevtrans%d = float2(0.0f, 0.0f);\n", n); // --------- // Wrapping @@ -901,10 +1009,10 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) if (bpmem.tevorders[n/2].getEnable(n&1)) { - if(!bHasIndStage) + if (!bHasIndStage) { // calc tevcord - if(bHasTexCoord) + if (bHasTexCoord) WRITE(p, "tevcoord.xy = uv%d.xy;\n", texcoord); else WRITE(p, "tevcoord.xy = float2(0.0f, 0.0f);\n"); @@ -924,7 +1032,7 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) int kc = bpmem.tevksel[n / 2].getKC(n & 1); int ka = bpmem.tevksel[n / 2].getKA(n & 1); WRITE(p, "konsttemp = float4(%s, %s);\n", tevKSelTableC[kc], tevKSelTableA[ka]); - if(kc > 7 || ka > 7) + if (kc > 7 || ka > 7) { WRITE(p, "ckonsttemp = frac(konsttemp * (255.0f/256.0f)) * (256.0f/255.0f);\n"); } @@ -1023,7 +1131,7 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) if (cc.shift > TEVSCALE_1) WRITE(p, "%s*(", tevScaleTable[cc.shift]); - if(!(cc.d == TEVCOLORARG_ZERO && cc.op == TEVOP_ADD)) + if (!(cc.d == TEVCOLORARG_ZERO && cc.op == TEVOP_ADD)) WRITE(p, "%s%s", tevCInputTable[cc.d], tevOpTable[cc.op]); if (cc.a == cc.b) @@ -1073,7 +1181,7 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) if (ac.shift > TEVSCALE_1) WRITE(p, "%s*(", tevScaleTable[ac.shift]); - if(!(ac.d == TEVALPHAARG_ZERO && ac.op == TEVOP_ADD)) + if (!(ac.d == TEVALPHAARG_ZERO && ac.op == TEVOP_ADD)) WRITE(p, "%s.a%s", tevAInputTable[ac.d], tevOpTable[ac.op]); if (ac.a == ac.b) @@ -1089,7 +1197,7 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) WRITE(p, "%s",tevBiasTable[ac.bias]); - if (ac.shift>0) + if (ac.shift > 0) WRITE(p, ")"); } @@ -1114,7 +1222,7 @@ void SampleTexture(char *&p, const char *destination, const char *texcoords, con if (ApiType == API_D3D11) WRITE(p, "%s=Tex%d.Sample(samp%d,%s.xy * " I_TEXDIMS"[%d].xy).%s;\n", destination, texmap,texmap, texcoords, texmap, texswap); else - WRITE(p, "%s=tex2D(samp%d,%s.xy * " I_TEXDIMS"[%d].xy).%s;\n", destination, texmap, texcoords, texmap, texswap); + WRITE(p, "%s=%s(samp%d,%s.xy * " I_TEXDIMS"[%d].xy).%s;\n", destination, ApiType == API_OPENGL ? "texture" : "tex2D", texmap, texcoords, texmap, texswap); } static const char *tevAlphaFuncsTable[] = @@ -1137,7 +1245,7 @@ static const char *tevAlphaFunclogicTable[] = " == " // xnor }; -static void WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode) +static void WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth) { static const char *alphaRef[2] = { @@ -1145,8 +1253,9 @@ static void WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode I_ALPHA"[0].g" }; + // using discard then return works the same in cg and dx9 but not in dx11 - WRITE(p, "if(!( "); + WRITE(p, "\tif(!( "); int compindex = bpmem.alpha_test.comp0; WRITE(p, tevAlphaFuncsTable[compindex],alphaRef[0]);//lookup the first component from the alpha function table @@ -1157,10 +1266,11 @@ static void WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode WRITE(p, tevAlphaFuncsTable[compindex],alphaRef[1]);//lookup the second component from the alpha function table WRITE(p, ")) {\n"); - WRITE(p, "ocol0 = 0;\n"); + WRITE(p, "\t\tocol0 = float4(0.0f, 0.0f, 0.0f, 0.0f);\n"); if (dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) - WRITE(p, "ocol1 = 0;\n"); - WRITE(p, "depth = 1.f;\n"); + WRITE(p, "\t\tocol1 = float4(0.0f, 0.0f, 0.0f, 0.0f);\n"); + if(per_pixel_depth) + WRITE(p, "depth = 1.f;\n"); // HAXX: zcomploc (aka early_ztest) is a way to control whether depth test is done before // or after texturing and alpha test. PC GPUs have no way to support this @@ -1174,9 +1284,9 @@ static void WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode // we don't have a choice. if (!(bpmem.zcontrol.early_ztest && bpmem.zmode.updateenable)) { - WRITE(p, "discard;\n"); + WRITE(p, "\t\tdiscard;\n"); if (ApiType != API_D3D11) - WRITE(p, "return;\n"); + WRITE(p, "\t\treturn;\n"); } WRITE(p, "}\n"); @@ -1188,52 +1298,51 @@ static const char *tevFogFuncsTable[] = "", //? "", //Linear "", //? - " fog = 1.0f - pow(2.0f, -8.0f * fog);\n", //exp - " fog = 1.0f - pow(2.0f, -8.0f * fog * fog);\n", //exp2 - " fog = pow(2.0f, -8.0f * (1.0f - fog));\n", //backward exp - " fog = 1.0f - fog;\n fog = pow(2.0f, -8.0f * fog * fog);\n" //backward exp2 + "\tfog = 1.0f - pow(2.0f, -8.0f * fog);\n", //exp + "\tfog = 1.0f - pow(2.0f, -8.0f * fog * fog);\n", //exp2 + "\tfog = pow(2.0f, -8.0f * (1.0f - fog));\n", //backward exp + "\tfog = 1.0f - fog;\n fog = pow(2.0f, -8.0f * fog * fog);\n" //backward exp2 }; static void WriteFog(char *&p) { - if(bpmem.fog.c_proj_fsel.fsel == 0)return;//no Fog + if (bpmem.fog.c_proj_fsel.fsel == 0) + return; // no Fog if (bpmem.fog.c_proj_fsel.proj == 0) { // perspective // ze = A/(B - (Zs >> B_SHF) - WRITE (p, " float ze = " I_FOG"[1].x / (" I_FOG"[1].y - (zCoord / " I_FOG"[1].w));\n"); + WRITE (p, "\tfloat ze = " I_FOG"[1].x / (" I_FOG"[1].y - (zCoord / " I_FOG"[1].w));\n"); } else { // orthographic // ze = a*Zs (here, no B_SHF) - WRITE (p, " float ze = " I_FOG"[1].x * zCoord;\n"); + WRITE (p, "\tfloat ze = " I_FOG"[1].x * zCoord;\n"); } // x_adjust = sqrt((x-center)^2 + k^2)/k // ze *= x_adjust //this is complitly teorical as the real hard seems to use a table intead of calculate the values. - if(bpmem.fogRange.Base.Enabled) + if (bpmem.fogRange.Base.Enabled) { - WRITE (p, " float x_adjust = (2.0f * (clipPos.x / " I_FOG"[2].y)) - 1.0f - " I_FOG"[2].x;\n"); - WRITE (p, " x_adjust = sqrt(x_adjust * x_adjust + " I_FOG"[2].z * " I_FOG"[2].z) / " I_FOG"[2].z;\n"); - WRITE (p, " ze *= x_adjust;\n"); + WRITE (p, "\tfloat x_adjust = (2.0f * (clipPos.x / " I_FOG"[2].y)) - 1.0f - " I_FOG"[2].x;\n"); + WRITE (p, "\tx_adjust = sqrt(x_adjust * x_adjust + " I_FOG"[2].z * " I_FOG"[2].z) / " I_FOG"[2].z;\n"); + WRITE (p, "\tze *= x_adjust;\n"); } - WRITE (p, " float fog = saturate(ze - " I_FOG"[1].z);\n"); + WRITE (p, "\tfloat fog = saturate(ze - " I_FOG"[1].z);\n"); - if(bpmem.fog.c_proj_fsel.fsel > 3) + if (bpmem.fog.c_proj_fsel.fsel > 3) { WRITE(p, "%s", tevFogFuncsTable[bpmem.fog.c_proj_fsel.fsel]); } else { - if(bpmem.fog.c_proj_fsel.fsel != 2) + if (bpmem.fog.c_proj_fsel.fsel != 2) WARN_LOG(VIDEO, "Unknown Fog Type! %08x", bpmem.fog.c_proj_fsel.fsel); } - WRITE(p, " prev.rgb = lerp(prev.rgb," I_FOG"[0].rgb,fog);\n"); - - + WRITE(p, "\tprev.rgb = lerp(prev.rgb, " I_FOG"[0].rgb, fog);\n"); } diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.h b/Source/Core/VideoCommon/Src/PixelShaderGen.h index 9c8bfce256..7896bc93e0 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.h +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.h @@ -28,8 +28,8 @@ #define I_INDTEXSCALE "cindscale" #define I_INDTEXMTX "cindmtx" #define I_FOG "cfog" -#define I_PLIGHTS "cLights" -#define I_PMATERIALS "cmtrl" +#define I_PLIGHTS "cPLights" +#define I_PMATERIALS "cPmtrl" #define C_COLORMATRIX 0 // 0 #define C_COLORS 0 // 0 @@ -47,6 +47,19 @@ #define PIXELSHADERUID_MAX_VALUES 70 #define PIXELSHADERUID_MAX_VALUES_SAFE 115 +// Annoying sure, can be removed once we get up to GLSL ~1.3 +const s_svar PSVar_Loc[] = { {I_COLORS, C_COLORS, 4 }, + {I_KCOLORS, C_KCOLORS, 4 }, + {I_ALPHA, C_ALPHA, 1 }, + {I_TEXDIMS, C_TEXDIMS, 8 }, + {I_ZBIAS , C_ZBIAS, 2 }, + {I_INDTEXSCALE , C_INDTEXSCALE, 2 }, + {I_INDTEXMTX, C_INDTEXMTX, 6 }, + {I_FOG, C_FOG, 3 }, + {I_PLIGHTS, C_PLIGHTS, 40 }, + {I_PMATERIALS, C_PMATERIALS, 4 }, + }; + // DO NOT make anything in this class virtual. template<bool safe> class _PIXELSHADERUID diff --git a/Source/Core/VideoCommon/Src/PixelShaderManager.cpp b/Source/Core/VideoCommon/Src/PixelShaderManager.cpp index eaaf99fbc8..ad84f6876e 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderManager.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderManager.cpp @@ -85,61 +85,63 @@ void PixelShaderManager::Shutdown() void PixelShaderManager::SetConstants() { - for (int i = 0; i < 2; ++i) + if (g_ActiveConfig.backend_info.APIType == API_OPENGL && !g_ActiveConfig.backend_info.bSupportsGLSLUBO) + Dirty(); + for (int i = 0; i < 2; ++i) { - if (s_nColorsChanged[i]) + if (s_nColorsChanged[i]) { - int baseind = i ? C_KCOLORS : C_COLORS; - for (int j = 0; j < 4; ++j) + int baseind = i ? C_KCOLORS : C_COLORS; + for (int j = 0; j < 4; ++j) { - if (s_nColorsChanged[i] & (1 << j)) - SetPSConstant4fv(baseind+j, &lastRGBAfull[i][j][0]); - } - s_nColorsChanged[i] = 0; - } - } - - if (s_nTexDimsChanged) + if (s_nColorsChanged[i] & (1 << j)) + SetPSConstant4fv(baseind+j, &lastRGBAfull[i][j][0]); + } + s_nColorsChanged[i] = 0; + } + } + + if (s_nTexDimsChanged) { - for (int i = 0; i < 8; ++i) + for (int i = 0; i < 8; ++i) { - if (s_nTexDimsChanged & (1<<i)) + if (s_nTexDimsChanged & (1<<i)) SetPSTextureDims(i); - } - s_nTexDimsChanged = 0; - } + } + s_nTexDimsChanged = 0; + } - if (s_bAlphaChanged) + if (s_bAlphaChanged) { SetPSConstant4f(C_ALPHA, (lastAlpha&0xff)/255.0f, ((lastAlpha>>8)&0xff)/255.0f, 0, ((lastAlpha>>16)&0xff)/255.0f); s_bAlphaChanged = false; - } + } if (s_bZTextureTypeChanged) { - float ftemp[4]; - switch (bpmem.ztex2.type) + float ftemp[4]; + switch (bpmem.ztex2.type) { - case 0: - // 8 bits - ftemp[0] = 0; ftemp[1] = 0; ftemp[2] = 0; ftemp[3] = 255.0f/16777215.0f; - break; - case 1: - // 16 bits - ftemp[0] = 255.0f/16777215.0f; ftemp[1] = 0; ftemp[2] = 0; ftemp[3] = 65280.0f/16777215.0f; - break; - case 2: - // 24 bits + case 0: + // 8 bits + ftemp[0] = 0; ftemp[1] = 0; ftemp[2] = 0; ftemp[3] = 255.0f/16777215.0f; + break; + case 1: + // 16 bits + ftemp[0] = 255.0f/16777215.0f; ftemp[1] = 0; ftemp[2] = 0; ftemp[3] = 65280.0f/16777215.0f; + break; + case 2: + // 24 bits ftemp[0] = 16711680.0f/16777215.0f; ftemp[1] = 65280.0f/16777215.0f; ftemp[2] = 255.0f/16777215.0f; ftemp[3] = 0; - break; - } + break; + } SetPSConstant4fv(C_ZBIAS, ftemp); s_bZTextureTypeChanged = false; } if (s_bZBiasChanged || s_bDepthRangeChanged) { - // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) + // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) // [0] = width/2 // [1] = height/2 // [2] = 16777215 * (farz - nearz) @@ -150,78 +152,78 @@ void PixelShaderManager::SetConstants() //ERROR_LOG("pixel=%x,%x, bias=%x\n", bpmem.zcontrol.pixel_format, bpmem.ztex2.type, lastZBias); SetPSConstant4f(C_ZBIAS+1, xfregs.viewport.farZ / 16777216.0f, xfregs.viewport.zRange / 16777216.0f, 0, (float)(lastZBias)/16777215.0f); s_bZBiasChanged = s_bDepthRangeChanged = false; - } + } - // indirect incoming texture scales - if (s_nIndTexScaleChanged) + // indirect incoming texture scales + if (s_nIndTexScaleChanged) { // set as two sets of vec4s, each containing S and T of two ind stages. - float f[8]; + float f[8]; - if (s_nIndTexScaleChanged & 0x03) + if (s_nIndTexScaleChanged & 0x03) { - for (u32 i = 0; i < 2; ++i) + for (u32 i = 0; i < 2; ++i) { - f[2 * i] = bpmem.texscale[0].getScaleS(i & 1); - f[2 * i + 1] = bpmem.texscale[0].getScaleT(i & 1); - PRIM_LOG("tex indscale%d: %f %f\n", i, f[2 * i], f[2 * i + 1]); - } + f[2 * i] = bpmem.texscale[0].getScaleS(i & 1); + f[2 * i + 1] = bpmem.texscale[0].getScaleT(i & 1); + PRIM_LOG("tex indscale%d: %f %f\n", i, f[2 * i], f[2 * i + 1]); + } SetPSConstant4fv(C_INDTEXSCALE, f); - } - - if (s_nIndTexScaleChanged & 0x0c) { - for (u32 i = 2; i < 4; ++i) { - f[2 * i] = bpmem.texscale[1].getScaleS(i & 1); - f[2 * i + 1] = bpmem.texscale[1].getScaleT(i & 1); - PRIM_LOG("tex indscale%d: %f %f\n", i, f[2 * i], f[2 * i + 1]); - } + } + + if (s_nIndTexScaleChanged & 0x0c) { + for (u32 i = 2; i < 4; ++i) { + f[2 * i] = bpmem.texscale[1].getScaleS(i & 1); + f[2 * i + 1] = bpmem.texscale[1].getScaleT(i & 1); + PRIM_LOG("tex indscale%d: %f %f\n", i, f[2 * i], f[2 * i + 1]); + } SetPSConstant4fv(C_INDTEXSCALE+1, &f[4]); - } + } - s_nIndTexScaleChanged = 0; - } + s_nIndTexScaleChanged = 0; + } - if (s_nIndTexMtxChanged) + if (s_nIndTexMtxChanged) { - for (int i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) { - if (s_nIndTexMtxChanged & (1 << i)) + if (s_nIndTexMtxChanged & (1 << i)) { - int scale = ((u32)bpmem.indmtx[i].col0.s0 << 0) | - ((u32)bpmem.indmtx[i].col1.s1 << 2) | - ((u32)bpmem.indmtx[i].col2.s2 << 4); - float fscale = powf(2.0f, (float)(scale - 17)) / 1024.0f; - - // xyz - static matrix - // TODO w - dynamic matrix scale / 256...... somehow / 4 works better - // rev 2972 - now using / 256.... verify that this works + int scale = ((u32)bpmem.indmtx[i].col0.s0 << 0) | + ((u32)bpmem.indmtx[i].col1.s1 << 2) | + ((u32)bpmem.indmtx[i].col2.s2 << 4); + float fscale = powf(2.0f, (float)(scale - 17)) / 1024.0f; + + // xyz - static matrix + // TODO w - dynamic matrix scale / 256...... somehow / 4 works better + // rev 2972 - now using / 256.... verify that this works SetPSConstant4f(C_INDTEXMTX + 2 * i, - bpmem.indmtx[i].col0.ma * fscale, + bpmem.indmtx[i].col0.ma * fscale, bpmem.indmtx[i].col1.mc * fscale, bpmem.indmtx[i].col2.me * fscale, fscale * 4.0f); - SetPSConstant4f(C_INDTEXMTX + 2 * i + 1, - bpmem.indmtx[i].col0.mb * fscale, + SetPSConstant4f(C_INDTEXMTX + 2 * i + 1, + bpmem.indmtx[i].col0.mb * fscale, bpmem.indmtx[i].col1.md * fscale, bpmem.indmtx[i].col2.mf * fscale, fscale * 4.0f); - PRIM_LOG("indmtx%d: scale=%f, mat=(%f %f %f; %f %f %f)\n", - i, 1024.0f*fscale, - bpmem.indmtx[i].col0.ma * fscale, bpmem.indmtx[i].col1.mc * fscale, bpmem.indmtx[i].col2.me * fscale, - bpmem.indmtx[i].col0.mb * fscale, bpmem.indmtx[i].col1.md * fscale, bpmem.indmtx[i].col2.mf * fscale); - } - } - s_nIndTexMtxChanged = 0; - } + PRIM_LOG("indmtx%d: scale=%f, mat=(%f %f %f; %f %f %f)\n", + i, 1024.0f*fscale, + bpmem.indmtx[i].col0.ma * fscale, bpmem.indmtx[i].col1.mc * fscale, bpmem.indmtx[i].col2.me * fscale, + bpmem.indmtx[i].col0.mb * fscale, bpmem.indmtx[i].col1.md * fscale, bpmem.indmtx[i].col2.mf * fscale); + } + } + s_nIndTexMtxChanged = 0; + } - if (s_bFogColorChanged) + if (s_bFogColorChanged) { SetPSConstant4f(C_FOG, bpmem.fog.color.r / 255.0f, bpmem.fog.color.g / 255.0f, bpmem.fog.color.b / 255.0f, 0); s_bFogColorChanged = false; - } + } - if (s_bFogParamChanged) + if (s_bFogParamChanged) { if(!g_ActiveConfig.bDisableFog) { @@ -234,8 +236,8 @@ void PixelShaderManager::SetConstants() else SetPSConstant4f(C_FOG + 1, 0.0, 1.0, 0.0, 1.0); - s_bFogParamChanged = false; - } + s_bFogParamChanged = false; + } if (s_bFogRangeAdjustChanged) { @@ -339,11 +341,11 @@ void PixelShaderManager::SetConstants() void PixelShaderManager::SetPSTextureDims(int texid) { - // texdims.xy are reciprocals of the real texture dimensions - // texdims.zw are the scaled dimensions - float fdims[4]; + // texdims.xy are reciprocals of the real texture dimensions + // texdims.zw are the scaled dimensions + float fdims[4]; - TCoordInfo& tc = bpmem.texcoords[texid]; + TCoordInfo& tc = bpmem.texcoords[texid]; fdims[0] = 1.0f / (float)(lastTexDims[texid] & 0xffff); fdims[1] = 1.0f / (float)((lastTexDims[texid] >> 16) & 0xfff); fdims[2] = (float)(tc.s.scale_minus_1 + 1); @@ -357,7 +359,7 @@ void PixelShaderManager::SetPSTextureDims(int texid) // and update it when the shader constant is set, only. void PixelShaderManager::SetColorChanged(int type, int num, bool high) { - float *pf = &lastRGBAfull[type][num][0]; + float *pf = &lastRGBAfull[type][num][0]; if (!high) { int r = bpmem.tevregs[num].low.a; int a = bpmem.tevregs[num].low.b; @@ -369,60 +371,61 @@ void PixelShaderManager::SetColorChanged(int type, int num, bool high) pf[1] = (float)g * (1.0f / 255.0f); pf[2] = (float)b * (1.0f / 255.0f); } - s_nColorsChanged[type] |= 1 << num; - PRIM_LOG("pixel %scolor%d: %f %f %f %f\n", type?"k":"", num, pf[0], pf[1], pf[2], pf[3]); + s_nColorsChanged[type] |= 1 << num; + PRIM_LOG("pixel %scolor%d: %f %f %f %f\n", type?"k":"", num, pf[0], pf[1], pf[2], pf[3]); } void PixelShaderManager::SetAlpha(const AlphaTest& alpha) { - if ((alpha.hex & 0xffff) != lastAlpha) + if ((alpha.hex & 0xffff) != lastAlpha) { - lastAlpha = (lastAlpha & ~0xffff) | (alpha.hex & 0xffff); - s_bAlphaChanged = true; - } + lastAlpha = (lastAlpha & ~0xffff) | (alpha.hex & 0xffff); + s_bAlphaChanged = true; + } } void PixelShaderManager::SetDestAlpha(const ConstantAlpha& alpha) { - if (alpha.alpha != (lastAlpha >> 16)) + if (alpha.alpha != (lastAlpha >> 16)) { - lastAlpha = (lastAlpha & ~0xff0000) | ((alpha.hex & 0xff) << 16); - s_bAlphaChanged = true; - } + lastAlpha = (lastAlpha & ~0xff0000) | ((alpha.hex & 0xff) << 16); + s_bAlphaChanged = true; + } } void PixelShaderManager::SetTexDims(int texmapid, u32 width, u32 height, u32 wraps, u32 wrapt) { - u32 wh = width | (height << 16) | (wraps << 28) | (wrapt << 30); - if (lastTexDims[texmapid] != wh) + u32 wh = width | (height << 16) | (wraps << 28) | (wrapt << 30); + if (lastTexDims[texmapid] != wh) { - lastTexDims[texmapid] = wh; + lastTexDims[texmapid] = wh; s_nTexDimsChanged |= 1 << texmapid; - } + } } void PixelShaderManager::SetZTextureBias(u32 bias) { - if (lastZBias != bias) + if (lastZBias != bias) { - s_bZBiasChanged = true; - lastZBias = bias; - } + s_bZBiasChanged = true; + lastZBias = bias; + } } void PixelShaderManager::SetViewportChanged() { s_bDepthRangeChanged = true; + s_bFogRangeAdjustChanged = true; // TODO: Shouldn't be necessary with an accurate fog range adjust implementation } void PixelShaderManager::SetIndTexScaleChanged(u8 stagemask) { - s_nIndTexScaleChanged |= stagemask; + s_nIndTexScaleChanged |= stagemask; } void PixelShaderManager::SetIndMatrixChanged(int matrixidx) { - s_nIndTexMtxChanged |= 1 << matrixidx; + s_nIndTexMtxChanged |= 1 << matrixidx; } void PixelShaderManager::SetZTextureTypeChanged() @@ -432,22 +435,22 @@ void PixelShaderManager::SetZTextureTypeChanged() void PixelShaderManager::SetTexCoordChanged(u8 texmapid) { - s_nTexDimsChanged |= 1 << texmapid; + s_nTexDimsChanged |= 1 << texmapid; } void PixelShaderManager::SetFogColorChanged() { - s_bFogColorChanged = true; + s_bFogColorChanged = true; } void PixelShaderManager::SetFogParamChanged() { - s_bFogParamChanged = true; + s_bFogParamChanged = true; } void PixelShaderManager::SetFogRangeAdjustChanged() { - s_bFogRangeAdjustChanged = true; + s_bFogRangeAdjustChanged = true; } void PixelShaderManager::SetColorMatrix(const float* pmatrix) diff --git a/Source/Core/VideoCommon/Src/PixelShaderManager.h b/Source/Core/VideoCommon/Src/PixelShaderManager.h index 12d749c871..8e663653f8 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderManager.h +++ b/Source/Core/VideoCommon/Src/PixelShaderManager.h @@ -54,7 +54,6 @@ public: static void SetColorMatrix(const float* pmatrix); static void InvalidateXFRange(int start, int end); static void SetMaterialColorChanged(int index); - }; diff --git a/Source/Core/VideoCommon/Src/RenderBase.cpp b/Source/Core/VideoCommon/Src/RenderBase.cpp index 8e1d012fa2..90a09aec43 100644 --- a/Source/Core/VideoCommon/Src/RenderBase.cpp +++ b/Source/Core/VideoCommon/Src/RenderBase.cpp @@ -83,7 +83,9 @@ unsigned int Renderer::efb_scale_denominatorY = 1; unsigned int Renderer::ssaa_multiplier = 1; -Renderer::Renderer() : frame_data(NULL), bLastFrameDumped(false) +Renderer::Renderer() + : frame_data() + , bLastFrameDumped(false) { UpdateActiveConfig(); TextureCache::OnConfigChanged(g_ActiveConfig); @@ -110,7 +112,6 @@ Renderer::~Renderer() if (pFrameDump.IsOpen()) pFrameDump.Close(); #endif - delete[] frame_data; } void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma) diff --git a/Source/Core/VideoCommon/Src/RenderBase.h b/Source/Core/VideoCommon/Src/RenderBase.h index 5376577cbd..55678f3f5a 100644 --- a/Source/Core/VideoCommon/Src/RenderBase.h +++ b/Source/Core/VideoCommon/Src/RenderBase.h @@ -52,6 +52,15 @@ public: Renderer(); virtual ~Renderer(); + enum PixelPerfQuery { + PP_ZCOMP_INPUT_ZCOMPLOC, + PP_ZCOMP_OUTPUT_ZCOMPLOC, + PP_ZCOMP_INPUT, + PP_ZCOMP_OUTPUT, + PP_BLEND_INPUT, + PP_EFB_COPY_CLOCKS + }; + virtual void SetColorMask() = 0; virtual void SetBlendMode(bool forceUpdate) = 0; virtual void SetScissorRect(const TargetRectangle& rc) = 0; @@ -147,7 +156,7 @@ protected: #else File::IOFile pFrameDump; #endif - char* frame_data; + std::vector<u8> frame_data; bool bLastFrameDumped; // The framebuffer size diff --git a/Source/Core/VideoCommon/Src/Statistics.cpp b/Source/Core/VideoCommon/Src/Statistics.cpp index 202769c55f..5f3240f44e 100644 --- a/Source/Core/VideoCommon/Src/Statistics.cpp +++ b/Source/Core/VideoCommon/Src/Statistics.cpp @@ -53,8 +53,8 @@ char *Statistics::ToString(char *ptr) ptr+=sprintf(ptr,"pshaders (unique, delete cache first): %i\n",stats.numUniquePixelShaders); ptr+=sprintf(ptr,"vshaders created: %i\n",stats.numVertexShadersCreated); ptr+=sprintf(ptr,"vshaders alive: %i\n",stats.numVertexShadersAlive); - ptr+=sprintf(ptr,"dlists called: %i\n",stats.numDListsCalled); - ptr+=sprintf(ptr,"dlists called(f): %i\n",stats.thisFrame.numDListsCalled); + ptr+=sprintf(ptr,"dlists called: %i\n",stats.numDListsCalled); + ptr+=sprintf(ptr,"dlists called(f): %i\n",stats.thisFrame.numDListsCalled); ptr+=sprintf(ptr,"dlists alive: %i\n",stats.numDListsAlive); ptr+=sprintf(ptr,"primitive joins: %i\n",stats.thisFrame.numPrimitiveJoins); ptr+=sprintf(ptr,"draw calls: %i\n",stats.thisFrame.numDrawCalls); diff --git a/Source/Core/VideoCommon/Src/Statistics.h b/Source/Core/VideoCommon/Src/Statistics.h index e173bfc682..fac7691b35 100644 --- a/Source/Core/VideoCommon/Src/Statistics.h +++ b/Source/Core/VideoCommon/Src/Statistics.h @@ -24,20 +24,20 @@ struct Statistics { - int numPixelShadersCreated; - int numPixelShadersAlive; - int numVertexShadersCreated; - int numVertexShadersAlive; + int numPixelShadersCreated; + int numPixelShadersAlive; + int numVertexShadersCreated; + int numVertexShadersAlive; - int numTexturesCreated; - int numTexturesAlive; + int numTexturesCreated; + int numTexturesAlive; - int numRenderTargetsCreated; - int numRenderTargetsAlive; - - int numDListsCalled; - int numDListsCreated; - int numDListsAlive; + int numRenderTargetsCreated; + int numRenderTargetsAlive; + + int numDListsCalled; + int numDListsCreated; + int numDListsAlive; int numVertexLoaders; @@ -52,30 +52,30 @@ struct Statistics std::vector<EFBRectangle> efb_regions; - struct ThisFrame - { - int numBPLoads; - int numCPLoads; - int numXFLoads; - - int numBPLoadsInDL; - int numCPLoadsInDL; - int numXFLoadsInDL; - - int numDLs; - int numPrims; - int numDLPrims; - int numShaderChanges; - - int numPrimitiveJoins; - int numDrawCalls; - int numIndexedDrawCalls; - int numBufferSplits; + struct ThisFrame + { + int numBPLoads; + int numCPLoads; + int numXFLoads; + + int numBPLoadsInDL; + int numCPLoadsInDL; + int numXFLoadsInDL; + + int numDLs; + int numPrims; + int numDLPrims; + int numShaderChanges; + + int numPrimitiveJoins; + int numDrawCalls; + int numIndexedDrawCalls; + int numBufferSplits; int numDListsCalled; - }; - ThisFrame thisFrame; - void ResetFrame(); + }; + ThisFrame thisFrame; + void ResetFrame(); static void SwapDL(); // Yeah, this is unsafe, but we really don't wanna faff around allocating diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp index fda4f21a7e..319c014f22 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp @@ -56,7 +56,7 @@ TextureCache::TextureCache() if (!temp) temp = (u8*)AllocateAlignedMemory(temp_size, 16); TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter); - if(g_ActiveConfig.bHiresTextures && !g_ActiveConfig.bDumpTextures) + if(g_ActiveConfig.bHiresTextures && !g_ActiveConfig.bDumpTextures) HiresTextures::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str()); SetHash64Function(g_ActiveConfig.bHiresTextures || g_ActiveConfig.bDumpTextures); } @@ -129,7 +129,10 @@ void TextureCache::Cleanup() TexCache::iterator tcend = textures.end(); while (iter != tcend) { - if (frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount) // TODO: Deleting EFB copies might not be a good idea here... + if ( frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount + + // EFB copies living on the host GPU are unrecoverable and thus shouldn't be deleted + && ! iter->second->IsEfbCopy() ) { delete iter->second; textures.erase(iter++); @@ -722,7 +725,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat case 1: // R8 case 8: // R8 colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1; - cbufid = 13; + cbufid = 13; break; case 2: // RA4 @@ -743,11 +746,11 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat case 9: // G8 colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f; - cbufid = 17; + cbufid = 17; break; case 10: // B8 colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f; - cbufid = 18; + cbufid = 18; break; case 11: // RG8 @@ -756,7 +759,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat break; case 12: // GB8 - colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1.0f; + colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1.0f; cbufid = 20; break; @@ -828,9 +831,5 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat entry->frameCount = frameCount; - g_renderer->ResetAPIState(); // reset any game specific settings - entry->FromRenderTarget(dstAddr, dstFormat, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat); - - g_renderer->RestoreAPIState(); } diff --git a/Source/Core/VideoCommon/Src/TextureConversionShader.cpp b/Source/Core/VideoCommon/Src/TextureConversionShader.cpp index 2132a25258..5a81c9e7d5 100644 --- a/Source/Core/VideoCommon/Src/TextureConversionShader.cpp +++ b/Source/Core/VideoCommon/Src/TextureConversionShader.cpp @@ -26,6 +26,7 @@ #include "PixelShaderGen.h" #include "BPMemory.h" #include "RenderBase.h" +#include "VideoConfig.h" #define WRITE p+=sprintf @@ -38,23 +39,23 @@ namespace TextureConversionShader u16 GetEncodedSampleCount(u32 format) { - switch (format) { - case GX_TF_I4: return 8; + switch (format) { + case GX_TF_I4: return 8; case GX_TF_I8: return 4; case GX_TF_IA4: return 4; - case GX_TF_IA8: return 2; + case GX_TF_IA8: return 2; case GX_TF_RGB565: return 2; case GX_TF_RGB5A3: return 2; case GX_TF_RGBA8: return 1; case GX_CTF_R4: return 8; - case GX_CTF_RA4: return 4; - case GX_CTF_RA8: return 2; - case GX_CTF_A8: return 4; - case GX_CTF_R8: return 4; - case GX_CTF_G8: return 4; - case GX_CTF_B8: return 4; - case GX_CTF_RG8: return 2; - case GX_CTF_GB8: return 2; + case GX_CTF_RA4: return 4; + case GX_CTF_RA8: return 2; + case GX_CTF_A8: return 4; + case GX_CTF_R8: return 4; + case GX_CTF_G8: return 4; + case GX_CTF_B8: return 4; + case GX_CTF_RG8: return 2; + case GX_CTF_GB8: return 2; case GX_TF_Z8: return 4; case GX_TF_Z16: return 2; case GX_TF_Z24X8: return 1; @@ -62,23 +63,35 @@ u16 GetEncodedSampleCount(u32 format) case GX_CTF_Z8M: return 4; case GX_CTF_Z8L: return 4; case GX_CTF_Z16L: return 2; - default: return 1; - } + default: return 1; + } +} + +const char* WriteRegister(API_TYPE ApiType, const char *prefix, const u32 num) +{ + if (ApiType == API_OPENGL) + return ""; // Once we switch to GLSL 1.3 we can do something here + static char result[64]; + sprintf(result, " : register(%s%d)", prefix, num); + return result; } // block dimensions : widthStride, heightStride // texture dims : width, height, x offset, y offset void WriteSwizzler(char*& p, u32 format, API_TYPE ApiType) { - WRITE(p, "uniform float4 blkDims : register(c%d);\n", C_COLORMATRIX); - WRITE(p, "uniform float4 textureDims : register(c%d);\n", C_COLORMATRIX + 1); + // [0] left, top, right, bottom of source rectangle within source texture + // [1] width and height of destination texture in pixels + // Two were merged for GLSL + WRITE(p, "uniform float4 " I_COLORS"[2] %s;\n", WriteRegister(ApiType, "c", C_COLORS)); - float blkW = (float)TexDecoder_GetBlockWidthInTexels(format); + float blkW = (float)TexDecoder_GetBlockWidthInTexels(format); float blkH = (float)TexDecoder_GetBlockHeightInTexels(format); float samples = (float)GetEncodedSampleCount(format); - if(ApiType == API_OPENGL) + if (ApiType == API_OPENGL) { - WRITE(p,"uniform samplerRECT samp0 : register(s0);\n"); + WRITE(p, "#define samp0 samp9\n"); + WRITE(p, "uniform sampler2DRect samp0;\n"); } else if (ApiType & API_D3D9) { @@ -87,23 +100,31 @@ void WriteSwizzler(char*& p, u32 format, API_TYPE ApiType) else { WRITE(p,"sampler samp0 : register(s0);\n"); - WRITE(p, "Texture2D Tex0 : register(t0);\n"); + WRITE(p, "Texture2D Tex0 : register(t0);\n"); } - - WRITE(p,"void main(\n"); - if(ApiType != API_D3D11) + if (ApiType == API_OPENGL) { - WRITE(p," out float4 ocol0 : COLOR0,\n"); + WRITE(p, " out float4 ocol0;\n"); + WRITE(p, " in float2 uv0;\n"); + WRITE(p, "void main()\n"); } else { - WRITE(p," out float4 ocol0 : SV_Target,\n"); + WRITE(p,"void main(\n"); + if (ApiType != API_D3D11) + { + WRITE(p," out float4 ocol0 : COLOR0,\n"); + } + else + { + WRITE(p," out float4 ocol0 : SV_Target,\n"); + } + WRITE(p," in float2 uv0 : TEXCOORD0)\n"); } - - WRITE(p," in float2 uv0 : TEXCOORD0)\n" - "{\n" - " float2 sampleUv;\n" + + WRITE(p, "{\n" + " float2 sampleUv;\n" " float2 uv1 = floor(uv0);\n"); WRITE(p, " uv1.x = uv1.x * %f;\n", samples); @@ -113,7 +134,7 @@ void WriteSwizzler(char*& p, u32 format, API_TYPE ApiType) WRITE(p, " float yl = floor(uv1.y / %f);\n", blkH); WRITE(p, " float yb = yl * %f;\n", blkH); WRITE(p, " float yoff = uv1.y - yb;\n"); - WRITE(p, " float xp = uv1.x + (yoff * textureDims.x);\n"); + WRITE(p, " float xp = uv1.x + (yoff * " I_COLORS"[1].x);\n"); WRITE(p, " float xel = floor(xp / %f);\n", blkW); WRITE(p, " float xb = floor(xel / %f);\n", blkH); WRITE(p, " float xoff = xel - (xb * %f);\n", blkH); @@ -121,34 +142,37 @@ void WriteSwizzler(char*& p, u32 format, API_TYPE ApiType) WRITE(p, " sampleUv.x = xib + (xb * %f);\n", blkW); WRITE(p, " sampleUv.y = yb + xoff;\n"); - WRITE(p, " sampleUv = sampleUv * blkDims.xy;\n"); + WRITE(p, " sampleUv = sampleUv * " I_COLORS"[0].xy;\n"); + + if (ApiType == API_OPENGL) + WRITE(p," sampleUv.y = " I_COLORS"[1].y - sampleUv.y;\n"); - if(ApiType == API_OPENGL) - WRITE(p," sampleUv.y = textureDims.y - sampleUv.y;\n"); - - WRITE(p, " sampleUv = sampleUv + textureDims.zw;\n"); + WRITE(p, " sampleUv = sampleUv + " I_COLORS"[1].zw;\n"); - if(ApiType != API_OPENGL) + if (ApiType != API_OPENGL) { WRITE(p, " sampleUv = sampleUv + float2(0.0f,1.0f);\n");// still to determine the reason for this - WRITE(p, " sampleUv = sampleUv / blkDims.zw;\n"); - } + WRITE(p, " sampleUv = sampleUv / " I_COLORS"[0].zw;\n"); + } } // block dimensions : widthStride, heightStride // texture dims : width, height, x offset, y offset void Write32BitSwizzler(char*& p, u32 format, API_TYPE ApiType) -{ - WRITE(p, "uniform float4 blkDims : register(c%d);\n", C_COLORMATRIX); - WRITE(p, "uniform float4 textureDims : register(c%d);\n", C_COLORMATRIX + 1); +{ + // [0] left, top, right, bottom of source rectangle within source texture + // [1] width and height of destination texture in pixels + // Two were merged for GLSL + WRITE(p, "uniform float4 " I_COLORS"[2] %s;\n", WriteRegister(ApiType, "c", C_COLORS)); - float blkW = (float)TexDecoder_GetBlockWidthInTexels(format); + float blkW = (float)TexDecoder_GetBlockWidthInTexels(format); float blkH = (float)TexDecoder_GetBlockHeightInTexels(format); // 32 bit textures (RGBA8 and Z24) are store in 2 cache line increments - if(ApiType == API_OPENGL) + if (ApiType == API_OPENGL) { - WRITE(p,"uniform samplerRECT samp0 : register(s0);\n"); + WRITE(p, "#define samp0 samp9\n"); + WRITE(p, "uniform sampler2DRect samp0;\n"); } else if (ApiType & API_D3D9) { @@ -157,53 +181,61 @@ void Write32BitSwizzler(char*& p, u32 format, API_TYPE ApiType) else { WRITE(p,"sampler samp0 : register(s0);\n"); - WRITE(p, "Texture2D Tex0 : register(t0);\n"); + WRITE(p, "Texture2D Tex0 : register(t0);\n"); } - - WRITE(p,"void main(\n"); - if(ApiType != API_D3D11) + if (ApiType == API_OPENGL) { - WRITE(p," out float4 ocol0 : COLOR0,\n"); + WRITE(p, " out float4 ocol0;\n"); + WRITE(p, " in float2 uv0;\n"); + WRITE(p, "void main()\n"); } else { - WRITE(p," out float4 ocol0 : SV_Target,\n"); + WRITE(p,"void main(\n"); + if(ApiType != API_D3D11) + { + WRITE(p," out float4 ocol0 : COLOR0,\n"); + } + else + { + WRITE(p," out float4 ocol0 : SV_Target,\n"); + } + WRITE(p," in float2 uv0 : TEXCOORD0)\n"); } - - WRITE(p," in float2 uv0 : TEXCOORD0)\n" - "{\n" - " float2 sampleUv;\n" + + + WRITE(p, "{\n" + " float2 sampleUv;\n" " float2 uv1 = floor(uv0);\n"); - + WRITE(p, " float yl = floor(uv1.y / %f);\n", blkH); WRITE(p, " float yb = yl * %f;\n", blkH); WRITE(p, " float yoff = uv1.y - yb;\n"); - WRITE(p, " float xp = uv1.x + (yoff * textureDims.x);\n"); + WRITE(p, " float xp = uv1.x + (yoff * " I_COLORS"[1].x);\n"); WRITE(p, " float xel = floor(xp / 2);\n"); WRITE(p, " float xb = floor(xel / %f);\n", blkH); WRITE(p, " float xoff = xel - (xb * %f);\n", blkH); - + WRITE(p, " float x2 = uv1.x * 2;\n"); WRITE(p, " float xl = floor(x2 / %f);\n", blkW); WRITE(p, " float xib = x2 - (xl * %f);\n", blkW); WRITE(p, " float halfxb = floor(xb / 2);\n"); - WRITE(p, " sampleUv.x = xib + (halfxb * %f);\n", blkW); WRITE(p, " sampleUv.y = yb + xoff;\n"); - WRITE(p, " sampleUv = sampleUv * blkDims.xy;\n"); - - if(ApiType == API_OPENGL) - WRITE(p," sampleUv.y = textureDims.y - sampleUv.y;\n"); - - WRITE(p, " sampleUv = sampleUv + textureDims.zw;\n"); - - if(ApiType != API_OPENGL) + WRITE(p, " sampleUv = sampleUv * " I_COLORS"[0].xy;\n"); + + if (ApiType == API_OPENGL) + WRITE(p," sampleUv.y = " I_COLORS"[1].y - sampleUv.y;\n"); + + WRITE(p, " sampleUv = sampleUv + " I_COLORS"[1].zw;\n"); + + if (ApiType != API_OPENGL) { WRITE(p, " sampleUv = sampleUv + float2(0.0f,1.0f);\n");// still to determine the reason for this - WRITE(p, " sampleUv = sampleUv / blkDims.zw;\n"); - } + WRITE(p, " sampleUv = sampleUv / " I_COLORS"[0].zw;\n"); + } } void WriteSampleColor(char*& p, const char* colorComp, const char* dest, API_TYPE ApiType) @@ -214,14 +246,14 @@ void WriteSampleColor(char*& p, const char* colorComp, const char* dest, API_TYP else if (ApiType == API_D3D11) texSampleOpName = "tex0.Sample"; else - texSampleOpName = "texRECT"; + texSampleOpName = "texture2DRect"; // the increment of sampleUv.x is delayed, so we perform it here. see WriteIncrementSampleX. const char* texSampleIncrementUnit; - if(ApiType != API_OPENGL) - texSampleIncrementUnit = "blkDims.x / blkDims.z"; + if (ApiType != API_OPENGL) + texSampleIncrementUnit = I_COLORS"[0].x / " I_COLORS"[0].z"; else - texSampleIncrementUnit = "blkDims.x"; + texSampleIncrementUnit = I_COLORS"[0].x"; WRITE(p, " %s = %s(samp0, sampleUv + float2(%d * (%s), 0)).%s;\n", dest, texSampleOpName, s_incrementSampleXCount, texSampleIncrementUnit, colorComp); @@ -229,7 +261,7 @@ void WriteSampleColor(char*& p, const char* colorComp, const char* dest, API_TYP void WriteColorToIntensity(char*& p, const char* src, const char* dest) { - if(!IntensityConstantAdded) + if (!IntensityConstantAdded) { WRITE(p, " float4 IntensityConst = float4(0.257f,0.504f,0.098f,0.0625f);\n"); IntensityConstantAdded = true; @@ -263,7 +295,7 @@ void WriteToBitDepth(char*& p, u8 depth, const char* src, const char* dest) WRITE(p, " %s = floor(%s * %ff);\n", dest, src, result); } -void WriteEncoderEnd(char* p) +void WriteEncoderEnd(char* p, API_TYPE ApiType) { WRITE(p, "}\n"); IntensityConstantAdded = false; @@ -272,65 +304,65 @@ void WriteEncoderEnd(char* p) void WriteI8Encoder(char* p, API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_I8,ApiType); + WriteSwizzler(p, GX_TF_I8, ApiType); WRITE(p, " float3 texSample;\n"); - WriteSampleColor(p, "rgb", "texSample",ApiType); + WriteSampleColor(p, "rgb", "texSample", ApiType); WriteColorToIntensity(p, "texSample", "ocol0.b"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgb", "texSample",ApiType); + WriteSampleColor(p, "rgb", "texSample", ApiType); WriteColorToIntensity(p, "texSample", "ocol0.g"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgb", "texSample",ApiType); + WriteSampleColor(p, "rgb", "texSample", ApiType); WriteColorToIntensity(p, "texSample", "ocol0.r"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgb", "texSample",ApiType); + WriteSampleColor(p, "rgb", "texSample", ApiType); WriteColorToIntensity(p, "texSample", "ocol0.a"); WRITE(p, " ocol0.rgba += IntensityConst.aaaa;\n"); // see WriteColorToIntensity - WriteEncoderEnd(p); + WriteEncoderEnd(p, ApiType); } void WriteI4Encoder(char* p, API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_I4,ApiType); + WriteSwizzler(p, GX_TF_I4, ApiType); WRITE(p, " float3 texSample;\n"); WRITE(p, " float4 color0;\n"); WRITE(p, " float4 color1;\n"); - WriteSampleColor(p, "rgb", "texSample",ApiType); + WriteSampleColor(p, "rgb", "texSample", ApiType); WriteColorToIntensity(p, "texSample", "color0.b"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgb", "texSample",ApiType); + WriteSampleColor(p, "rgb", "texSample", ApiType); WriteColorToIntensity(p, "texSample", "color1.b"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgb", "texSample",ApiType); + WriteSampleColor(p, "rgb", "texSample", ApiType); WriteColorToIntensity(p, "texSample", "color0.g"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgb", "texSample",ApiType); + WriteSampleColor(p, "rgb", "texSample", ApiType); WriteColorToIntensity(p, "texSample", "color1.g"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgb", "texSample",ApiType); + WriteSampleColor(p, "rgb", "texSample", ApiType); WriteColorToIntensity(p, "texSample", "color0.r"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgb", "texSample",ApiType); + WriteSampleColor(p, "rgb", "texSample", ApiType); WriteColorToIntensity(p, "texSample", "color1.r"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgb", "texSample",ApiType); + WriteSampleColor(p, "rgb", "texSample", ApiType); WriteColorToIntensity(p, "texSample", "color0.a"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgb", "texSample",ApiType); + WriteSampleColor(p, "rgb", "texSample", ApiType); WriteColorToIntensity(p, "texSample", "color1.a"); WRITE(p, " color0.rgba += IntensityConst.aaaa;\n"); @@ -340,51 +372,51 @@ void WriteI4Encoder(char* p, API_TYPE ApiType) WriteToBitDepth(p, 4, "color1", "color1"); WRITE(p, " ocol0 = (color0 * 16.0f + color1) / 255.0f;\n"); - WriteEncoderEnd(p); + WriteEncoderEnd(p, ApiType); } void WriteIA8Encoder(char* p,API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_IA8,ApiType); + WriteSwizzler(p, GX_TF_IA8, ApiType); WRITE(p, " float4 texSample;\n"); - WriteSampleColor(p, "rgba", "texSample",ApiType); + WriteSampleColor(p, "rgba", "texSample", ApiType); WRITE(p, " ocol0.b = texSample.a;\n"); WriteColorToIntensity(p, "texSample", "ocol0.g"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgba", "texSample",ApiType); + WriteSampleColor(p, "rgba", "texSample", ApiType); WRITE(p, " ocol0.r = texSample.a;\n"); WriteColorToIntensity(p, "texSample", "ocol0.a"); WRITE(p, " ocol0.ga += IntensityConst.aa;\n"); - WriteEncoderEnd(p); + WriteEncoderEnd(p, ApiType); } void WriteIA4Encoder(char* p,API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_IA4,ApiType); + WriteSwizzler(p, GX_TF_IA4, ApiType); WRITE(p, " float4 texSample;\n"); WRITE(p, " float4 color0;\n"); WRITE(p, " float4 color1;\n"); - WriteSampleColor(p, "rgba", "texSample",ApiType); + WriteSampleColor(p, "rgba", "texSample", ApiType); WRITE(p, " color0.b = texSample.a;\n"); WriteColorToIntensity(p, "texSample", "color1.b"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgba", "texSample",ApiType); + WriteSampleColor(p, "rgba", "texSample", ApiType); WRITE(p, " color0.g = texSample.a;\n"); WriteColorToIntensity(p, "texSample", "color1.g"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgba", "texSample",ApiType); + WriteSampleColor(p, "rgba", "texSample", ApiType); WRITE(p, " color0.r = texSample.a;\n"); WriteColorToIntensity(p, "texSample", "color1.r"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgba", "texSample",ApiType); + WriteSampleColor(p, "rgba", "texSample", ApiType); WRITE(p, " color0.a = texSample.a;\n"); WriteColorToIntensity(p, "texSample", "color1.a"); @@ -394,20 +426,19 @@ void WriteIA4Encoder(char* p,API_TYPE ApiType) WriteToBitDepth(p, 4, "color1", "color1"); WRITE(p, " ocol0 = (color0 * 16.0f + color1) / 255.0f;\n"); - WriteEncoderEnd(p); + WriteEncoderEnd(p, ApiType); } void WriteRGB565Encoder(char* p,API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_RGB565,ApiType); - - WriteSampleColor(p, "rgb", "float3 texSample0",ApiType); - WriteIncrementSampleX(p,ApiType); - WriteSampleColor(p, "rgb", "float3 texSample1",ApiType); - - WRITE(p, " float2 texRs = {texSample0.r, texSample1.r};\n"); - WRITE(p, " float2 texGs = {texSample0.g, texSample1.g};\n"); - WRITE(p, " float2 texBs = {texSample0.b, texSample1.b};\n"); + WriteSwizzler(p, GX_TF_RGB565, ApiType); + + WriteSampleColor(p, "rgb", "float3 texSample0", ApiType); + WriteIncrementSampleX(p, ApiType); + WriteSampleColor(p, "rgb", "float3 texSample1", ApiType); + WRITE(p, " float2 texRs = float2(texSample0.r, texSample1.r);\n"); + WRITE(p, " float2 texGs = float2(texSample0.g, texSample1.g);\n"); + WRITE(p, " float2 texBs = float2(texSample0.b, texSample1.b);\n"); WriteToBitDepth(p, 6, "texGs", "float2 gInt"); WRITE(p, " float2 gUpper = floor(gInt / 8.0f);\n"); @@ -419,25 +450,25 @@ void WriteRGB565Encoder(char* p,API_TYPE ApiType) WRITE(p, " ocol0.ga = ocol0.ga + gLower * 32.0f;\n"); WRITE(p, " ocol0 = ocol0 / 255.0f;\n"); - WriteEncoderEnd(p); + WriteEncoderEnd(p, ApiType); } void WriteRGB5A3Encoder(char* p,API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_RGB5A3,ApiType); + WriteSwizzler(p, GX_TF_RGB5A3, ApiType); WRITE(p, " float4 texSample;\n"); WRITE(p, " float color0;\n"); WRITE(p, " float gUpper;\n"); WRITE(p, " float gLower;\n"); - WriteSampleColor(p, "rgba", "texSample",ApiType); + WriteSampleColor(p, "rgba", "texSample", ApiType); - // 0.8784 = 224 / 255 which is the maximum alpha value that can be represented in 3 bits - WRITE(p, "if(texSample.a > 0.878f) {\n"); + // 0.8784 = 224 / 255 which is the maximum alpha value that can be represented in 3 bits + WRITE(p, "if(texSample.a > 0.878f) {\n"); WriteToBitDepth(p, 5, "texSample.g", "color0"); - WRITE(p, " gUpper = floor(color0 / 8.0f);\n"); + WRITE(p, " gUpper = floor(color0 / 8.0f);\n"); WRITE(p, " gLower = color0 - gUpper * 8.0f;\n"); WriteToBitDepth(p, 5, "texSample.r", "ocol0.b"); @@ -445,27 +476,27 @@ void WriteRGB5A3Encoder(char* p,API_TYPE ApiType) WriteToBitDepth(p, 5, "texSample.b", "ocol0.g"); WRITE(p, " ocol0.g = ocol0.g + gLower * 32.0f;\n"); - WRITE(p, "} else {\n"); + WRITE(p, "} else {\n"); - WriteToBitDepth(p, 4, "texSample.r", "ocol0.b"); - WriteToBitDepth(p, 4, "texSample.b", "ocol0.g"); + WriteToBitDepth(p, 4, "texSample.r", "ocol0.b"); + WriteToBitDepth(p, 4, "texSample.b", "ocol0.g"); - WriteToBitDepth(p, 3, "texSample.a", "color0"); - WRITE(p, "ocol0.b = ocol0.b + color0 * 16.0f;\n"); + WriteToBitDepth(p, 3, "texSample.a", "color0"); + WRITE(p, "ocol0.b = ocol0.b + color0 * 16.0f;\n"); WriteToBitDepth(p, 4, "texSample.g", "color0"); - WRITE(p, "ocol0.g = ocol0.g + color0 * 16.0f;\n"); + WRITE(p, "ocol0.g = ocol0.g + color0 * 16.0f;\n"); - WRITE(p, "}\n"); + WRITE(p, "}\n"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgba", "texSample",ApiType); + WriteSampleColor(p, "rgba", "texSample", ApiType); - WRITE(p, "if(texSample.a > 0.878f) {\n"); + WRITE(p, "if(texSample.a > 0.878f) {\n"); WriteToBitDepth(p, 5, "texSample.g", "color0"); - WRITE(p, " gUpper = floor(color0 / 8.0f);\n"); + WRITE(p, " gUpper = floor(color0 / 8.0f);\n"); WRITE(p, " gLower = color0 - gUpper * 8.0f;\n"); WriteToBitDepth(p, 5, "texSample.r", "ocol0.r"); @@ -473,51 +504,51 @@ void WriteRGB5A3Encoder(char* p,API_TYPE ApiType) WriteToBitDepth(p, 5, "texSample.b", "ocol0.a"); WRITE(p, " ocol0.a = ocol0.a + gLower * 32.0f;\n"); - WRITE(p, "} else {\n"); + WRITE(p, "} else {\n"); - WriteToBitDepth(p, 4, "texSample.r", "ocol0.r"); - WriteToBitDepth(p, 4, "texSample.b", "ocol0.a"); + WriteToBitDepth(p, 4, "texSample.r", "ocol0.r"); + WriteToBitDepth(p, 4, "texSample.b", "ocol0.a"); - WriteToBitDepth(p, 3, "texSample.a", "color0"); - WRITE(p, "ocol0.r = ocol0.r + color0 * 16.0f;\n"); + WriteToBitDepth(p, 3, "texSample.a", "color0"); + WRITE(p, "ocol0.r = ocol0.r + color0 * 16.0f;\n"); WriteToBitDepth(p, 4, "texSample.g", "color0"); - WRITE(p, "ocol0.a = ocol0.a + color0 * 16.0f;\n"); + WRITE(p, "ocol0.a = ocol0.a + color0 * 16.0f;\n"); - WRITE(p, "}\n"); + WRITE(p, "}\n"); WRITE(p, " ocol0 = ocol0 / 255.0f;\n"); - WriteEncoderEnd(p); + WriteEncoderEnd(p, ApiType); } void WriteRGBA4443Encoder(char* p,API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_RGB5A3,ApiType); + WriteSwizzler(p, GX_TF_RGB5A3, ApiType); WRITE(p, " float4 texSample;\n"); WRITE(p, " float4 color0;\n"); WRITE(p, " float4 color1;\n"); - WriteSampleColor(p, "rgba", "texSample",ApiType); + WriteSampleColor(p, "rgba", "texSample", ApiType); WriteToBitDepth(p, 3, "texSample.a", "color0.b"); WriteToBitDepth(p, 4, "texSample.r", "color1.b"); WriteToBitDepth(p, 4, "texSample.g", "color0.g"); WriteToBitDepth(p, 4, "texSample.b", "color1.g"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgba", "texSample",ApiType); + WriteSampleColor(p, "rgba", "texSample", ApiType); WriteToBitDepth(p, 3, "texSample.a", "color0.r"); WriteToBitDepth(p, 4, "texSample.r", "color1.r"); WriteToBitDepth(p, 4, "texSample.g", "color0.a"); WriteToBitDepth(p, 4, "texSample.b", "color1.a"); WRITE(p, " ocol0 = (color0 * 16.0f + color1) / 255.0f;\n"); - WriteEncoderEnd(p); + WriteEncoderEnd(p, ApiType); } void WriteRGBA8Encoder(char* p,API_TYPE ApiType) { - Write32BitSwizzler(p, GX_TF_RGBA8,ApiType); + Write32BitSwizzler(p, GX_TF_RGBA8, ApiType); WRITE(p, " float cl1 = xb - (halfxb * 2);\n"); WRITE(p, " float cl0 = 1.0f - cl1;\n"); @@ -526,15 +557,15 @@ void WriteRGBA8Encoder(char* p,API_TYPE ApiType) WRITE(p, " float4 color0;\n"); WRITE(p, " float4 color1;\n"); - WriteSampleColor(p, "rgba", "texSample",ApiType); + WriteSampleColor(p, "rgba", "texSample", ApiType); WRITE(p, " color0.b = texSample.a;\n"); WRITE(p, " color0.g = texSample.r;\n"); WRITE(p, " color1.b = texSample.g;\n"); WRITE(p, " color1.g = texSample.b;\n"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "rgba", "texSample",ApiType); + WriteSampleColor(p, "rgba", "texSample", ApiType); WRITE(p, " color0.r = texSample.a;\n"); WRITE(p, " color0.a = texSample.r;\n"); WRITE(p, " color1.r = texSample.g;\n"); @@ -542,86 +573,86 @@ void WriteRGBA8Encoder(char* p,API_TYPE ApiType) WRITE(p, " ocol0 = (cl0 * color0) + (cl1 * color1);\n"); - WriteEncoderEnd(p); + WriteEncoderEnd(p, ApiType); } void WriteC4Encoder(char* p, const char* comp,API_TYPE ApiType) { - WriteSwizzler(p, GX_CTF_R4,ApiType); + WriteSwizzler(p, GX_CTF_R4, ApiType); WRITE(p, " float4 color0;\n"); WRITE(p, " float4 color1;\n"); - WriteSampleColor(p, comp, "color0.b",ApiType); - WriteIncrementSampleX(p,ApiType); + WriteSampleColor(p, comp, "color0.b", ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, comp, "color1.b",ApiType); - WriteIncrementSampleX(p,ApiType); + WriteSampleColor(p, comp, "color1.b", ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, comp, "color0.g",ApiType); - WriteIncrementSampleX(p,ApiType); + WriteSampleColor(p, comp, "color0.g", ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, comp, "color1.g",ApiType); - WriteIncrementSampleX(p,ApiType); + WriteSampleColor(p, comp, "color1.g", ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, comp, "color0.r",ApiType); - WriteIncrementSampleX(p,ApiType); + WriteSampleColor(p, comp, "color0.r", ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, comp, "color1.r",ApiType); - WriteIncrementSampleX(p,ApiType); + WriteSampleColor(p, comp, "color1.r", ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, comp, "color0.a",ApiType); - WriteIncrementSampleX(p,ApiType); + WriteSampleColor(p, comp, "color0.a", ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, comp, "color1.a",ApiType); + WriteSampleColor(p, comp, "color1.a", ApiType); WriteToBitDepth(p, 4, "color0", "color0"); WriteToBitDepth(p, 4, "color1", "color1"); WRITE(p, " ocol0 = (color0 * 16.0f + color1) / 255.0f;\n"); - WriteEncoderEnd(p); + WriteEncoderEnd(p, ApiType); } void WriteC8Encoder(char* p, const char* comp,API_TYPE ApiType) { - WriteSwizzler(p, GX_CTF_R8,ApiType); + WriteSwizzler(p, GX_CTF_R8, ApiType); - WriteSampleColor(p, comp, "ocol0.b",ApiType); - WriteIncrementSampleX(p,ApiType); + WriteSampleColor(p, comp, "ocol0.b", ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, comp, "ocol0.g",ApiType); - WriteIncrementSampleX(p,ApiType); + WriteSampleColor(p, comp, "ocol0.g", ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, comp, "ocol0.r",ApiType); - WriteIncrementSampleX(p,ApiType); + WriteSampleColor(p, comp, "ocol0.r", ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, comp, "ocol0.a",ApiType); + WriteSampleColor(p, comp, "ocol0.a", ApiType); - WriteEncoderEnd(p); + WriteEncoderEnd(p, ApiType); } void WriteCC4Encoder(char* p, const char* comp,API_TYPE ApiType) { - WriteSwizzler(p, GX_CTF_RA4,ApiType); + WriteSwizzler(p, GX_CTF_RA4, ApiType); WRITE(p, " float2 texSample;\n"); WRITE(p, " float4 color0;\n"); WRITE(p, " float4 color1;\n"); - WriteSampleColor(p, comp, "texSample",ApiType); + WriteSampleColor(p, comp, "texSample", ApiType); WRITE(p, " color0.b = texSample.x;\n"); WRITE(p, " color1.b = texSample.y;\n"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, comp, "texSample",ApiType); + WriteSampleColor(p, comp, "texSample", ApiType); WRITE(p, " color0.g = texSample.x;\n"); WRITE(p, " color1.g = texSample.y;\n"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, comp, "texSample",ApiType); + WriteSampleColor(p, comp, "texSample", ApiType); WRITE(p, " color0.r = texSample.x;\n"); WRITE(p, " color1.r = texSample.y;\n"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, comp, "texSample",ApiType); + WriteSampleColor(p, comp, "texSample", ApiType); WRITE(p, " color0.a = texSample.x;\n"); WRITE(p, " color1.a = texSample.y;\n"); @@ -629,158 +660,158 @@ void WriteCC4Encoder(char* p, const char* comp,API_TYPE ApiType) WriteToBitDepth(p, 4, "color1", "color1"); WRITE(p, " ocol0 = (color0 * 16.0f + color1) / 255.0f;\n"); - WriteEncoderEnd(p); + WriteEncoderEnd(p, ApiType); } void WriteCC8Encoder(char* p, const char* comp, API_TYPE ApiType) { - WriteSwizzler(p, GX_CTF_RA8,ApiType); + WriteSwizzler(p, GX_CTF_RA8, ApiType); - WriteSampleColor(p, comp, "ocol0.bg",ApiType); - WriteIncrementSampleX(p,ApiType); + WriteSampleColor(p, comp, "ocol0.bg", ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, comp, "ocol0.ra",ApiType); + WriteSampleColor(p, comp, "ocol0.ra", ApiType); - WriteEncoderEnd(p); + WriteEncoderEnd(p, ApiType); } void WriteZ8Encoder(char* p, const char* multiplier,API_TYPE ApiType) { - WriteSwizzler(p, GX_CTF_Z8M,ApiType); + WriteSwizzler(p, GX_CTF_Z8M, ApiType); - WRITE(p, " float depth;\n"); + WRITE(p, " float depth;\n"); - WriteSampleColor(p, "b", "depth",ApiType); - WRITE(p, "ocol0.b = frac(depth * %s);\n", multiplier); - WriteIncrementSampleX(p,ApiType); + WriteSampleColor(p, "b", "depth", ApiType); + WRITE(p, "ocol0.b = frac(depth * %s);\n", multiplier); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "b", "depth",ApiType); - WRITE(p, "ocol0.g = frac(depth * %s);\n", multiplier); - WriteIncrementSampleX(p,ApiType); + WriteSampleColor(p, "b", "depth", ApiType); + WRITE(p, "ocol0.g = frac(depth * %s);\n", multiplier); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "b", "depth",ApiType); - WRITE(p, "ocol0.r = frac(depth * %s);\n", multiplier); - WriteIncrementSampleX(p,ApiType); + WriteSampleColor(p, "b", "depth", ApiType); + WRITE(p, "ocol0.r = frac(depth * %s);\n", multiplier); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "b", "depth",ApiType); - WRITE(p, "ocol0.a = frac(depth * %s);\n", multiplier); + WriteSampleColor(p, "b", "depth", ApiType); + WRITE(p, "ocol0.a = frac(depth * %s);\n", multiplier); - WriteEncoderEnd(p); + WriteEncoderEnd(p, ApiType); } void WriteZ16Encoder(char* p,API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_Z16,ApiType); + WriteSwizzler(p, GX_TF_Z16, ApiType); - WRITE(p, " float depth;\n"); - WRITE(p, " float3 expanded;\n"); + WRITE(p, " float depth;\n"); + WRITE(p, " float3 expanded;\n"); - // byte order is reversed + // byte order is reversed - WriteSampleColor(p, "b", "depth",ApiType); + WriteSampleColor(p, "b", "depth", ApiType); - WRITE(p, " depth *= 16777215.0f;\n"); - WRITE(p, " expanded.r = floor(depth / (256 * 256));\n"); - WRITE(p, " depth -= expanded.r * 256 * 256;\n"); - WRITE(p, " expanded.g = floor(depth / 256);\n"); + WRITE(p, " depth *= 16777215.0f;\n"); + WRITE(p, " expanded.r = floor(depth / (256 * 256));\n"); + WRITE(p, " depth -= expanded.r * 256 * 256;\n"); + WRITE(p, " expanded.g = floor(depth / 256);\n"); - WRITE(p, " ocol0.b = expanded.g / 255;\n"); - WRITE(p, " ocol0.g = expanded.r / 255;\n"); + WRITE(p, " ocol0.b = expanded.g / 255;\n"); + WRITE(p, " ocol0.g = expanded.r / 255;\n"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "b", "depth",ApiType); + WriteSampleColor(p, "b", "depth", ApiType); - WRITE(p, " depth *= 16777215.0f;\n"); - WRITE(p, " expanded.r = floor(depth / (256 * 256));\n"); - WRITE(p, " depth -= expanded.r * 256 * 256;\n"); - WRITE(p, " expanded.g = floor(depth / 256);\n"); + WRITE(p, " depth *= 16777215.0f;\n"); + WRITE(p, " expanded.r = floor(depth / (256 * 256));\n"); + WRITE(p, " depth -= expanded.r * 256 * 256;\n"); + WRITE(p, " expanded.g = floor(depth / 256);\n"); - WRITE(p, " ocol0.r = expanded.g / 255;\n"); - WRITE(p, " ocol0.a = expanded.r / 255;\n"); + WRITE(p, " ocol0.r = expanded.g / 255;\n"); + WRITE(p, " ocol0.a = expanded.r / 255;\n"); - WriteEncoderEnd(p); + WriteEncoderEnd(p, ApiType); } void WriteZ16LEncoder(char* p,API_TYPE ApiType) { - WriteSwizzler(p, GX_CTF_Z16L,ApiType); + WriteSwizzler(p, GX_CTF_Z16L, ApiType); - WRITE(p, " float depth;\n"); - WRITE(p, " float3 expanded;\n"); + WRITE(p, " float depth;\n"); + WRITE(p, " float3 expanded;\n"); - // byte order is reversed + // byte order is reversed - WriteSampleColor(p, "b", "depth",ApiType); + WriteSampleColor(p, "b", "depth", ApiType); - WRITE(p, " depth *= 16777215.0f;\n"); - WRITE(p, " expanded.r = floor(depth / (256 * 256));\n"); - WRITE(p, " depth -= expanded.r * 256 * 256;\n"); - WRITE(p, " expanded.g = floor(depth / 256);\n"); - WRITE(p, " depth -= expanded.g * 256;\n"); - WRITE(p, " expanded.b = depth;\n"); + WRITE(p, " depth *= 16777215.0f;\n"); + WRITE(p, " expanded.r = floor(depth / (256 * 256));\n"); + WRITE(p, " depth -= expanded.r * 256 * 256;\n"); + WRITE(p, " expanded.g = floor(depth / 256);\n"); + WRITE(p, " depth -= expanded.g * 256;\n"); + WRITE(p, " expanded.b = depth;\n"); - WRITE(p, " ocol0.b = expanded.b / 255;\n"); - WRITE(p, " ocol0.g = expanded.g / 255;\n"); + WRITE(p, " ocol0.b = expanded.b / 255;\n"); + WRITE(p, " ocol0.g = expanded.g / 255;\n"); - WriteIncrementSampleX(p,ApiType); + WriteIncrementSampleX(p, ApiType); - WriteSampleColor(p, "b", "depth",ApiType); + WriteSampleColor(p, "b", "depth", ApiType); - WRITE(p, " depth *= 16777215.0f;\n"); - WRITE(p, " expanded.r = floor(depth / (256 * 256));\n"); - WRITE(p, " depth -= expanded.r * 256 * 256;\n"); - WRITE(p, " expanded.g = floor(depth / 256);\n"); - WRITE(p, " depth -= expanded.g * 256;\n"); - WRITE(p, " expanded.b = depth;\n"); + WRITE(p, " depth *= 16777215.0f;\n"); + WRITE(p, " expanded.r = floor(depth / (256 * 256));\n"); + WRITE(p, " depth -= expanded.r * 256 * 256;\n"); + WRITE(p, " expanded.g = floor(depth / 256);\n"); + WRITE(p, " depth -= expanded.g * 256;\n"); + WRITE(p, " expanded.b = depth;\n"); - WRITE(p, " ocol0.r = expanded.b;\n"); - WRITE(p, " ocol0.a = expanded.g;\n"); + WRITE(p, " ocol0.r = expanded.b;\n"); + WRITE(p, " ocol0.a = expanded.g;\n"); - WriteEncoderEnd(p); + WriteEncoderEnd(p, ApiType); } void WriteZ24Encoder(char* p, API_TYPE ApiType) { - Write32BitSwizzler(p, GX_TF_Z24X8,ApiType); + Write32BitSwizzler(p, GX_TF_Z24X8, ApiType); WRITE(p, " float cl = xb - (halfxb * 2);\n"); WRITE(p, " float depth0;\n"); - WRITE(p, " float depth1;\n"); - WRITE(p, " float3 expanded0;\n"); - WRITE(p, " float3 expanded1;\n"); - - WriteSampleColor(p, "b", "depth0",ApiType); - WriteIncrementSampleX(p,ApiType); - WriteSampleColor(p, "b", "depth1",ApiType); - - for (int i = 0; i < 2; i++) - { - WRITE(p, " depth%i *= 16777215.0f;\n", i); - - WRITE(p, " expanded%i.r = floor(depth%i / (256 * 256));\n", i, i); - WRITE(p, " depth%i -= expanded%i.r * 256 * 256;\n", i, i); - WRITE(p, " expanded%i.g = floor(depth%i / 256);\n", i, i); - WRITE(p, " depth%i -= expanded%i.g * 256;\n", i, i); - WRITE(p, " expanded%i.b = depth%i;\n", i, i); - } - - WRITE(p, " if(cl > 0.5f) {\n"); - // upper 16 - WRITE(p, " ocol0.b = expanded0.g / 255;\n"); - WRITE(p, " ocol0.g = expanded0.b / 255;\n"); - WRITE(p, " ocol0.r = expanded1.g / 255;\n"); - WRITE(p, " ocol0.a = expanded1.b / 255;\n"); - WRITE(p, " } else {\n"); - // lower 8 - WRITE(p, " ocol0.b = 1.0f;\n"); - WRITE(p, " ocol0.g = expanded0.r / 255;\n"); - WRITE(p, " ocol0.r = 1.0f;\n"); - WRITE(p, " ocol0.a = expanded1.r / 255;\n"); - WRITE(p, " }\n"); - - WriteEncoderEnd(p); + WRITE(p, " float depth1;\n"); + WRITE(p, " float3 expanded0;\n"); + WRITE(p, " float3 expanded1;\n"); + + WriteSampleColor(p, "b", "depth0", ApiType); + WriteIncrementSampleX(p, ApiType); + WriteSampleColor(p, "b", "depth1", ApiType); + + for (int i = 0; i < 2; i++) + { + WRITE(p, " depth%i *= 16777215.0f;\n", i); + + WRITE(p, " expanded%i.r = floor(depth%i / (256 * 256));\n", i, i); + WRITE(p, " depth%i -= expanded%i.r * 256 * 256;\n", i, i); + WRITE(p, " expanded%i.g = floor(depth%i / 256);\n", i, i); + WRITE(p, " depth%i -= expanded%i.g * 256;\n", i, i); + WRITE(p, " expanded%i.b = depth%i;\n", i, i); + } + + WRITE(p, " if(cl > 0.5f) {\n"); + // upper 16 + WRITE(p, " ocol0.b = expanded0.g / 255;\n"); + WRITE(p, " ocol0.g = expanded0.b / 255;\n"); + WRITE(p, " ocol0.r = expanded1.g / 255;\n"); + WRITE(p, " ocol0.a = expanded1.b / 255;\n"); + WRITE(p, " } else {\n"); + // lower 8 + WRITE(p, " ocol0.b = 1.0f;\n"); + WRITE(p, " ocol0.g = expanded0.r / 255;\n"); + WRITE(p, " ocol0.r = 1.0f;\n"); + WRITE(p, " ocol0.a = expanded1.r / 255;\n"); + WRITE(p, " }\n"); + + WriteEncoderEnd(p, ApiType); } const char *GenerateEncodingShader(u32 format,API_TYPE ApiType) @@ -790,76 +821,76 @@ const char *GenerateEncodingShader(u32 format,API_TYPE ApiType) char *p = text; - switch(format) + switch (format) { case GX_TF_I4: - WriteI4Encoder(p,ApiType); + WriteI4Encoder(p, ApiType); break; case GX_TF_I8: - WriteI8Encoder(p,ApiType); + WriteI8Encoder(p, ApiType); break; case GX_TF_IA4: - WriteIA4Encoder(p,ApiType); + WriteIA4Encoder(p, ApiType); break; case GX_TF_IA8: - WriteIA8Encoder(p,ApiType); + WriteIA8Encoder(p, ApiType); break; case GX_TF_RGB565: - WriteRGB565Encoder(p,ApiType); + WriteRGB565Encoder(p, ApiType); break; case GX_TF_RGB5A3: - WriteRGB5A3Encoder(p,ApiType); + WriteRGB5A3Encoder(p, ApiType); break; case GX_TF_RGBA8: - WriteRGBA8Encoder(p,ApiType); + WriteRGBA8Encoder(p, ApiType); break; case GX_CTF_R4: - WriteC4Encoder(p, "r",ApiType); + WriteC4Encoder(p, "r", ApiType); break; case GX_CTF_RA4: - WriteCC4Encoder(p, "ar",ApiType); + WriteCC4Encoder(p, "ar", ApiType); break; case GX_CTF_RA8: - WriteCC8Encoder(p, "ar",ApiType); + WriteCC8Encoder(p, "ar", ApiType); break; case GX_CTF_A8: - WriteC8Encoder(p, "a",ApiType); + WriteC8Encoder(p, "a", ApiType); break; case GX_CTF_R8: - WriteC8Encoder(p, "r",ApiType); + WriteC8Encoder(p, "r", ApiType); break; case GX_CTF_G8: - WriteC8Encoder(p, "g",ApiType); + WriteC8Encoder(p, "g", ApiType); break; case GX_CTF_B8: - WriteC8Encoder(p, "b",ApiType); + WriteC8Encoder(p, "b", ApiType); break; case GX_CTF_RG8: - WriteCC8Encoder(p, "rg",ApiType); + WriteCC8Encoder(p, "rg", ApiType); break; case GX_CTF_GB8: - WriteCC8Encoder(p, "gb",ApiType); + WriteCC8Encoder(p, "gb", ApiType); break; case GX_TF_Z8: - WriteC8Encoder(p, "b",ApiType); + WriteC8Encoder(p, "b", ApiType); break; case GX_TF_Z16: - WriteZ16Encoder(p,ApiType); + WriteZ16Encoder(p, ApiType); break; case GX_TF_Z24X8: - WriteZ24Encoder(p,ApiType); + WriteZ24Encoder(p, ApiType); break; case GX_CTF_Z4: - WriteC4Encoder(p, "b",ApiType); + WriteC4Encoder(p, "b", ApiType); break; case GX_CTF_Z8M: - WriteZ8Encoder(p, "256.0f",ApiType); + WriteZ8Encoder(p, "256.0f", ApiType); break; case GX_CTF_Z8L: - WriteZ8Encoder(p, "65536.0f" ,ApiType); + WriteZ8Encoder(p, "65536.0f" , ApiType); break; case GX_CTF_Z16L: - WriteZ16LEncoder(p,ApiType); + WriteZ16LEncoder(p, ApiType); break; default: PanicAlert("Unknown texture copy format: 0x%x\n", format); @@ -870,7 +901,7 @@ const char *GenerateEncodingShader(u32 format,API_TYPE ApiType) PanicAlert("TextureConversionShader generator - buffer too small, canary has been eaten!"); setlocale(LC_NUMERIC, ""); // restore locale - return text; + return text; } void SetShaderParameters(float width, float height, float offsetX, float offsetY, float widthStride, float heightStride,float buffW,float buffH) diff --git a/Source/Core/VideoCommon/Src/TextureDecoder.h b/Source/Core/VideoCommon/Src/TextureDecoder.h index fae70897f5..e9154763cb 100644 --- a/Source/Core/VideoCommon/Src/TextureDecoder.h +++ b/Source/Core/VideoCommon/Src/TextureDecoder.h @@ -27,41 +27,41 @@ extern GC_ALIGNED16(u8 texMem[TMEM_SIZE]); enum TextureFormat { - GX_TF_I4 = 0x0, - GX_TF_I8 = 0x1, - GX_TF_IA4 = 0x2, - GX_TF_IA8 = 0x3, - GX_TF_RGB565 = 0x4, - GX_TF_RGB5A3 = 0x5, - GX_TF_RGBA8 = 0x6, - GX_TF_C4 = 0x8, - GX_TF_C8 = 0x9, - GX_TF_C14X2 = 0xA, - GX_TF_CMPR = 0xE, + GX_TF_I4 = 0x0, + GX_TF_I8 = 0x1, + GX_TF_IA4 = 0x2, + GX_TF_IA8 = 0x3, + GX_TF_RGB565 = 0x4, + GX_TF_RGB5A3 = 0x5, + GX_TF_RGBA8 = 0x6, + GX_TF_C4 = 0x8, + GX_TF_C8 = 0x9, + GX_TF_C14X2 = 0xA, + GX_TF_CMPR = 0xE, - _GX_TF_CTF = 0x20, // copy-texture-format only (simply means linear?) - _GX_TF_ZTF = 0x10, // Z-texture-format + _GX_TF_CTF = 0x20, // copy-texture-format only (simply means linear?) + _GX_TF_ZTF = 0x10, // Z-texture-format - // these formats are also valid when copying targets - GX_CTF_R4 = 0x0 | _GX_TF_CTF, - GX_CTF_RA4 = 0x2 | _GX_TF_CTF, - GX_CTF_RA8 = 0x3 | _GX_TF_CTF, - GX_CTF_YUVA8 = 0x6 | _GX_TF_CTF, - GX_CTF_A8 = 0x7 | _GX_TF_CTF, - GX_CTF_R8 = 0x8 | _GX_TF_CTF, - GX_CTF_G8 = 0x9 | _GX_TF_CTF, - GX_CTF_B8 = 0xA | _GX_TF_CTF, - GX_CTF_RG8 = 0xB | _GX_TF_CTF, - GX_CTF_GB8 = 0xC | _GX_TF_CTF, + // these formats are also valid when copying targets + GX_CTF_R4 = 0x0 | _GX_TF_CTF, + GX_CTF_RA4 = 0x2 | _GX_TF_CTF, + GX_CTF_RA8 = 0x3 | _GX_TF_CTF, + GX_CTF_YUVA8 = 0x6 | _GX_TF_CTF, + GX_CTF_A8 = 0x7 | _GX_TF_CTF, + GX_CTF_R8 = 0x8 | _GX_TF_CTF, + GX_CTF_G8 = 0x9 | _GX_TF_CTF, + GX_CTF_B8 = 0xA | _GX_TF_CTF, + GX_CTF_RG8 = 0xB | _GX_TF_CTF, + GX_CTF_GB8 = 0xC | _GX_TF_CTF, - GX_TF_Z8 = 0x1 | _GX_TF_ZTF, - GX_TF_Z16 = 0x3 | _GX_TF_ZTF, - GX_TF_Z24X8 = 0x6 | _GX_TF_ZTF, + GX_TF_Z8 = 0x1 | _GX_TF_ZTF, + GX_TF_Z16 = 0x3 | _GX_TF_ZTF, + GX_TF_Z24X8 = 0x6 | _GX_TF_ZTF, - GX_CTF_Z4 = 0x0 | _GX_TF_ZTF | _GX_TF_CTF, - GX_CTF_Z8M = 0x9 | _GX_TF_ZTF | _GX_TF_CTF, - GX_CTF_Z8L = 0xA | _GX_TF_ZTF | _GX_TF_CTF, - GX_CTF_Z16L = 0xC | _GX_TF_ZTF | _GX_TF_CTF, + GX_CTF_Z4 = 0x0 | _GX_TF_ZTF | _GX_TF_CTF, + GX_CTF_Z8M = 0x9 | _GX_TF_ZTF | _GX_TF_CTF, + GX_CTF_Z8L = 0xA | _GX_TF_ZTF | _GX_TF_CTF, + GX_CTF_Z16L = 0xC | _GX_TF_ZTF | _GX_TF_CTF, }; int TexDecoder_GetTexelSizeInNibbles(int format); diff --git a/Source/Core/VideoCommon/Src/VertexLoader.cpp b/Source/Core/VideoCommon/Src/VertexLoader.cpp index 5bffab8ee7..5df495a44c 100644 --- a/Source/Core/VideoCommon/Src/VertexLoader.cpp +++ b/Source/Core/VideoCommon/Src/VertexLoader.cpp @@ -23,7 +23,7 @@ #include "MemoryUtil.h" #include "StringUtil.h" #include "x64Emitter.h" -#include "ABI.h" +#include "x64ABI.h" #include "PixelEngine.h" #include "Host.h" @@ -43,8 +43,11 @@ //BBox #include "XFMemory.h" extern float GC_ALIGNED16(g_fProjectionMatrix[16]); - +#ifndef _M_GENERIC +#ifndef __APPLE__ #define USE_JIT +#endif +#endif #define COMPILED_CODE_SIZE 4096 @@ -72,6 +75,10 @@ int colElements[2]; float posScale; float tcScale[8]; +// bbox must read vertex position, so convert it to this buffer +static float s_bbox_vertex_buffer[3]; +static u8 *s_bbox_pCurBufferPointer_orig; + static const float fractionTable[32] = { 1.0f / (1U << 0), 1.0f / (1U << 1), 1.0f / (1U << 2), 1.0f / (1U << 3), 1.0f / (1U << 4), 1.0f / (1U << 5), 1.0f / (1U << 6), 1.0f / (1U << 7), @@ -93,10 +100,21 @@ void LOADERDECL PosMtx_ReadDirect_UByte() void LOADERDECL PosMtx_Write() { - *VertexManager::s_pCurBufferPointer++ = s_curposmtx; - *VertexManager::s_pCurBufferPointer++ = 0; - *VertexManager::s_pCurBufferPointer++ = 0; - *VertexManager::s_pCurBufferPointer++ = 0; + DataWrite<u8>(s_curposmtx); + DataWrite<u8>(0); + DataWrite<u8>(0); + DataWrite<u8>(0); +} + +void LOADERDECL UpdateBoundingBoxPrepare() +{ + if (!PixelEngine::bbox_active) + return; + + // set our buffer as videodata buffer, so we will get a copy of the vertex positions + // this is a big hack, but so we can use the same converting function then without bbox + s_bbox_pCurBufferPointer_orig = VertexManager::s_pCurBufferPointer; + VertexManager::s_pCurBufferPointer = (u8*)s_bbox_vertex_buffer; } void LOADERDECL UpdateBoundingBox() @@ -104,12 +122,16 @@ void LOADERDECL UpdateBoundingBox() if (!PixelEngine::bbox_active) return; - // Truly evil hack, reading backwards from the write pointer. If we were writing to write-only - // memory like we might have been with a D3D vertex buffer, this would have been a bad idea. - float *data = (float *)(VertexManager::s_pCurBufferPointer - 12); + // reset videodata pointer + VertexManager::s_pCurBufferPointer = s_bbox_pCurBufferPointer_orig; + + // copy vertex pointers + memcpy(VertexManager::s_pCurBufferPointer, s_bbox_vertex_buffer, 12); + VertexManager::s_pCurBufferPointer += 12; + // We must transform the just loaded point by the current world and projection matrix - in software. // Then convert to screen space and update the bounding box. - float p[3] = {data[0], data[1], data[2]}; + float p[3] = {s_bbox_vertex_buffer[0], s_bbox_vertex_buffer[1], s_bbox_vertex_buffer[2]}; const float *world_matrix = (float*)xfmem + MatrixIndexA.PosNormalMtxIdx * 4; const float *proj_matrix = &g_fProjectionMatrix[0]; @@ -147,24 +169,22 @@ void LOADERDECL TexMtx_ReadDirect_UByte() void LOADERDECL TexMtx_Write_Float() { - *(float*)VertexManager::s_pCurBufferPointer = (float)s_curtexmtx[s_texmtxwrite++]; - VertexManager::s_pCurBufferPointer += 4; + DataWrite(float(s_curtexmtx[s_texmtxwrite++])); } void LOADERDECL TexMtx_Write_Float2() { - ((float*)VertexManager::s_pCurBufferPointer)[0] = 0; - ((float*)VertexManager::s_pCurBufferPointer)[1] = (float)s_curtexmtx[s_texmtxwrite++]; - VertexManager::s_pCurBufferPointer += 8; + DataWrite(0.f); + DataWrite(float(s_curtexmtx[s_texmtxwrite++])); } void LOADERDECL TexMtx_Write_Float4() { - ((float*)VertexManager::s_pCurBufferPointer)[0] = 0; - ((float*)VertexManager::s_pCurBufferPointer)[1] = 0; - ((float*)VertexManager::s_pCurBufferPointer)[2] = s_curtexmtx[s_texmtxwrite++]; - ((float*)VertexManager::s_pCurBufferPointer)[3] = 0; // Just to fill out with 0. - VertexManager::s_pCurBufferPointer += 16; + DataWrite(0.f); + DataWrite(0.f); + DataWrite(float(s_curtexmtx[s_texmtxwrite++])); + // Just to fill out with 0. + DataWrite(0.f); } VertexLoader::VertexLoader(const TVtxDesc &vtx_desc, const VAT &vtx_attr) @@ -182,14 +202,21 @@ VertexLoader::VertexLoader(const TVtxDesc &vtx_desc, const VAT &vtx_attr) m_VtxDesc = vtx_desc; SetVAT(vtx_attr.g0.Hex, vtx_attr.g1.Hex, vtx_attr.g2.Hex); + #ifdef USE_JIT AllocCodeSpace(COMPILED_CODE_SIZE); CompileVertexTranslator(); WriteProtect(); + #else + CompileVertexTranslator(); + #endif + } VertexLoader::~VertexLoader() { + #ifdef USE_JIT FreeCodeSpace(); + #endif delete m_NativeFmt; } @@ -267,15 +294,16 @@ void VertexLoader::CompileVertexTranslator() if (m_VtxDesc.Tex7MatIdx) {m_VertexSize += 1; m_NativeFmt->m_components |= VB_HAS_TEXMTXIDX7; WriteCall(TexMtx_ReadDirect_UByte); } // Write vertex position loader - WriteCall(VertexLoader_Position::GetFunction(m_VtxDesc.Position, m_VtxAttr.PosFormat, m_VtxAttr.PosElements)); + if(g_ActiveConfig.bUseBBox) { + WriteCall(UpdateBoundingBoxPrepare); + WriteCall(VertexLoader_Position::GetFunction(m_VtxDesc.Position, m_VtxAttr.PosFormat, m_VtxAttr.PosElements)); + WriteCall(UpdateBoundingBox); + } else { + WriteCall(VertexLoader_Position::GetFunction(m_VtxDesc.Position, m_VtxAttr.PosFormat, m_VtxAttr.PosElements)); + } m_VertexSize += VertexLoader_Position::GetSize(m_VtxDesc.Position, m_VtxAttr.PosFormat, m_VtxAttr.PosElements); nat_offset += 12; - // OK, so we just got a point. Let's go back and read it for the bounding box. - - if(g_ActiveConfig.bUseBBox) - WriteCall(UpdateBoundingBox); - // Normals vtx_decl.num_normals = 0; if (m_VtxDesc.Normal != NOT_PRESENT) @@ -307,7 +335,7 @@ void VertexLoader::CompileVertexTranslator() nat_offset += 12; vtx_decl.normal_offset[2] = nat_offset; nat_offset += 12; - } + } int numNormals = (m_VtxAttr.NormalElements == 1) ? NRM_THREE : NRM_ONE; m_NativeFmt->m_components |= VB_HAS_NRM0; @@ -339,7 +367,7 @@ void VertexLoader::CompileVertexTranslator() default: _assert_(0); break; } break; - case INDEX8: + case INDEX8: m_VertexSize += 1; switch (m_VtxAttr.color[i].Comp) { @@ -474,7 +502,8 @@ void VertexLoader::WriteCall(TPipelineFunction func) m_PipelineStages[m_numPipelineStages++] = func; #endif } - +// ARMTODO: This should be done in a better way +#ifndef _M_GENERIC void VertexLoader::WriteGetVariable(int bits, OpArg dest, void *address) { #ifdef USE_JIT @@ -498,8 +527,9 @@ void VertexLoader::WriteSetVariable(int bits, void *address, OpArg value) #endif #endif } +#endif -void VertexLoader::RunVertices(int vtx_attr_group, int primitive, int count) +int VertexLoader::SetupRunVertices(int vtx_attr_group, int primitive, int const count) { m_numLoadedVertices += count; @@ -518,7 +548,7 @@ void VertexLoader::RunVertices(int vtx_attr_group, int primitive, int count) { // if cull mode is none, ignore triangles and quads DataSkip(count * m_VertexSize); - return; + return 0; } m_NativeFmt->EnableComponents(m_NativeFmt->m_components); @@ -528,7 +558,7 @@ void VertexLoader::RunVertices(int vtx_attr_group, int primitive, int count) m_VtxAttr.texCoord[0].Frac = g_VtxAttr[vtx_attr_group].g0.Tex0Frac; m_VtxAttr.texCoord[1].Frac = g_VtxAttr[vtx_attr_group].g1.Tex1Frac; m_VtxAttr.texCoord[2].Frac = g_VtxAttr[vtx_attr_group].g1.Tex2Frac; - m_VtxAttr.texCoord[3].Frac = g_VtxAttr[vtx_attr_group].g1.Tex3Frac; + m_VtxAttr.texCoord[3].Frac = g_VtxAttr[vtx_attr_group].g1.Tex3Frac; m_VtxAttr.texCoord[4].Frac = g_VtxAttr[vtx_attr_group].g2.Tex4Frac; m_VtxAttr.texCoord[5].Frac = g_VtxAttr[vtx_attr_group].g2.Tex5Frac; m_VtxAttr.texCoord[6].Frac = g_VtxAttr[vtx_attr_group].g2.Tex6Frac; @@ -542,158 +572,49 @@ void VertexLoader::RunVertices(int vtx_attr_group, int primitive, int count) for (int i = 0; i < 2; i++) colElements[i] = m_VtxAttr.color[i].Elements; - // if strips or fans, make sure all vertices can fit in buffer, otherwise flush - int granularity = 1; - switch (primitive) { - case 3: // strip .. hm, weird - case 4: // fan - if (VertexManager::GetRemainingSize() < 3 * native_stride) - VertexManager::Flush(); - break; - case 6: // line strip - if (VertexManager::GetRemainingSize() < 2 * native_stride) - VertexManager::Flush(); - break; - case 0: granularity = 4; break; // quads - case 2: granularity = 3; break; // tris - case 5: granularity = 2; break; // lines - } - - int startv = 0, extraverts = 0; - int v = 0; - - //int remainingVerts2 = VertexManager::GetRemainingVertices(primitive); - while (v < count) - { - int remainingVerts = VertexManager::GetRemainingSize() / native_stride; - //if (remainingVerts2 - v + startv < remainingVerts) - //remainingVerts = remainingVerts2 - v + startv; - if (remainingVerts < granularity) { - INCSTAT(stats.thisFrame.numBufferSplits); - // This buffer full - break current primitive and flush, to switch to the next buffer. - u8* plastptr = VertexManager::s_pCurBufferPointer; - if (v - startv > 0) - VertexManager::AddVertices(primitive, v - startv + extraverts); - VertexManager::Flush(); - //remainingVerts2 = VertexManager::GetRemainingVertices(primitive); - // Why does this need to be so complicated? - switch (primitive) { - case 3: // triangle strip, copy last two vertices - // a little trick since we have to keep track of signs - if (v & 1) { - memcpy_gc(VertexManager::s_pCurBufferPointer, plastptr-2*native_stride, native_stride); - memcpy_gc(VertexManager::s_pCurBufferPointer+native_stride, plastptr-native_stride*2, 2*native_stride); - VertexManager::s_pCurBufferPointer += native_stride*3; - extraverts = 3; - } - else { - memcpy_gc(VertexManager::s_pCurBufferPointer, plastptr-native_stride*2, native_stride*2); - VertexManager::s_pCurBufferPointer += native_stride*2; - extraverts = 2; - } - break; - case 4: // tri fan, copy first and last vert - memcpy_gc(VertexManager::s_pCurBufferPointer, plastptr-native_stride*(v-startv+extraverts), native_stride); - VertexManager::s_pCurBufferPointer += native_stride; - memcpy_gc(VertexManager::s_pCurBufferPointer, plastptr-native_stride, native_stride); - VertexManager::s_pCurBufferPointer += native_stride; - extraverts = 2; - break; - case 6: // line strip - memcpy_gc(VertexManager::s_pCurBufferPointer, plastptr-native_stride, native_stride); - VertexManager::s_pCurBufferPointer += native_stride; - extraverts = 1; - break; - default: - extraverts = 0; - break; - } - startv = v; - } - int remainingPrims = remainingVerts / granularity; - remainingVerts = remainingPrims * granularity; - if (count - v < remainingVerts) - remainingVerts = count - v; - - #ifdef USE_JIT - if (remainingVerts > 0) { - loop_counter = remainingVerts; - ((void (*)())(void*)m_compiledCode)(); - } - #else - for (int s = 0; s < remainingVerts; s++) - { - tcIndex = 0; - colIndex = 0; - s_texmtxwrite = s_texmtxread = 0; - for (int i = 0; i < m_numPipelineStages; i++) - m_PipelineStages[i](); - PRIM_LOG("\n"); - } - #endif - v += remainingVerts; - } - - if (startv < count) - VertexManager::AddVertices(primitive, count - startv + extraverts); + VertexManager::PrepareForAdditionalData(primitive, count, native_stride); + + return count; } - - - -void VertexLoader::RunCompiledVertices(int vtx_attr_group, int primitive, int count, u8* Data) +void VertexLoader::RunVertices(int vtx_attr_group, int primitive, int const count) { - m_numLoadedVertices += count; + auto const new_count = SetupRunVertices(vtx_attr_group, primitive, count); + ConvertVertices(new_count); + VertexManager::AddVertices(primitive, new_count); +} - // Flush if our vertex format is different from the currently set. - if (g_nativeVertexFmt != NULL && g_nativeVertexFmt != m_NativeFmt) - { - // We really must flush here. It's possible that the native representations - // of the two vtx formats are the same, but we have no way to easily check that - // now. - VertexManager::Flush(); - // Also move the Set() here? +void VertexLoader::ConvertVertices ( int count ) +{ +#ifdef USE_JIT + if (count > 0) { + loop_counter = count; + ((void (*)())(void*)m_compiledCode)(); } - g_nativeVertexFmt = m_NativeFmt; - - if (bpmem.genMode.cullmode == 3 && primitive < 5) +#else + for (int s = 0; s < count; s++) { - // if cull mode is none, ignore triangles and quads - DataSkip(count * m_VertexSize); - return; + tcIndex = 0; + colIndex = 0; + s_texmtxwrite = s_texmtxread = 0; + for (int i = 0; i < m_numPipelineStages; i++) + m_PipelineStages[i](); + PRIM_LOG("\n"); } +#endif +} - m_NativeFmt->EnableComponents(m_NativeFmt->m_components); - - // Load position and texcoord scale factors. - m_VtxAttr.PosFrac = g_VtxAttr[vtx_attr_group].g0.PosFrac; - m_VtxAttr.texCoord[0].Frac = g_VtxAttr[vtx_attr_group].g0.Tex0Frac; - m_VtxAttr.texCoord[1].Frac = g_VtxAttr[vtx_attr_group].g1.Tex1Frac; - m_VtxAttr.texCoord[2].Frac = g_VtxAttr[vtx_attr_group].g1.Tex2Frac; - m_VtxAttr.texCoord[3].Frac = g_VtxAttr[vtx_attr_group].g1.Tex3Frac; - m_VtxAttr.texCoord[4].Frac = g_VtxAttr[vtx_attr_group].g2.Tex4Frac; - m_VtxAttr.texCoord[5].Frac = g_VtxAttr[vtx_attr_group].g2.Tex5Frac; - m_VtxAttr.texCoord[6].Frac = g_VtxAttr[vtx_attr_group].g2.Tex6Frac; - m_VtxAttr.texCoord[7].Frac = g_VtxAttr[vtx_attr_group].g2.Tex7Frac; +void VertexLoader::RunCompiledVertices(int vtx_attr_group, int primitive, int const count, u8* Data) +{ + auto const new_count = SetupRunVertices(vtx_attr_group, primitive, count); - pVtxAttr = &m_VtxAttr; - posScale = fractionTable[m_VtxAttr.PosFrac]; - if (m_NativeFmt->m_components & VB_HAS_UVALL) - for (int i = 0; i < 8; i++) - tcScale[i] = fractionTable[m_VtxAttr.texCoord[i].Frac]; - for (int i = 0; i < 2; i++) - colElements[i] = m_VtxAttr.color[i].Elements; + memcpy_gc(VertexManager::s_pCurBufferPointer, Data, native_stride * new_count); + VertexManager::s_pCurBufferPointer += native_stride * new_count; + DataSkip(new_count * m_VertexSize); - if(VertexManager::GetRemainingSize() < native_stride * count) - VertexManager::Flush(); - memcpy_gc(VertexManager::s_pCurBufferPointer, Data, native_stride * count); - VertexManager::s_pCurBufferPointer += native_stride * count; - DataSkip(count * m_VertexSize); - VertexManager::AddVertices(primitive, count); + VertexManager::AddVertices(primitive, new_count); } - - void VertexLoader::SetVAT(u32 _group0, u32 _group1, u32 _group2) { VAT vat; @@ -724,7 +645,7 @@ void VertexLoader::SetVAT(u32 _group0, u32 _group1, u32 _group2) m_VtxAttr.texCoord[2].Frac = vat.g1.Tex2Frac; m_VtxAttr.texCoord[3].Elements = vat.g1.Tex3CoordElements; m_VtxAttr.texCoord[3].Format = vat.g1.Tex3CoordFormat; - m_VtxAttr.texCoord[3].Frac = vat.g1.Tex3Frac; + m_VtxAttr.texCoord[3].Frac = vat.g1.Tex3Frac; m_VtxAttr.texCoord[4].Elements = vat.g1.Tex4CoordElements; m_VtxAttr.texCoord[4].Format = vat.g1.Tex4CoordFormat; diff --git a/Source/Core/VideoCommon/Src/VertexLoader.h b/Source/Core/VideoCommon/Src/VertexLoader.h index 98a57cb9ff..862eabff3e 100644 --- a/Source/Core/VideoCommon/Src/VertexLoader.h +++ b/Source/Core/VideoCommon/Src/VertexLoader.h @@ -76,13 +76,20 @@ private: } }; +// ARMTODO: This should be done in a better way +#ifndef _M_GENERIC class VertexLoader : public Gen::XCodeBlock, NonCopyable +#else +class VertexLoader +#endif { public: VertexLoader(const TVtxDesc &vtx_desc, const VAT &vtx_attr); ~VertexLoader(); int GetVertexSize() const {return m_VertexSize;} + + int SetupRunVertices(int vtx_attr_group, int primitive, int const count); void RunVertices(int vtx_attr_group, int primitive, int count); void RunCompiledVertices(int vtx_attr_group, int primitive, int count, u8* Data); @@ -119,11 +126,14 @@ private: void SetVAT(u32 _group0, u32 _group1, u32 _group2); void CompileVertexTranslator(); + void ConvertVertices(int count); void WriteCall(TPipelineFunction); +#ifndef _M_GENERIC void WriteGetVariable(int bits, Gen::OpArg dest, void *address); void WriteSetVariable(int bits, void *address, Gen::OpArg dest); -}; +#endif +}; #endif diff --git a/Source/Core/VideoCommon/Src/VertexLoader_Color.cpp b/Source/Core/VideoCommon/Src/VertexLoader_Color.cpp index 9cfa5efc31..fa1ecbe973 100644 --- a/Source/Core/VideoCommon/Src/VertexLoader_Color.cpp +++ b/Source/Core/VideoCommon/Src/VertexLoader_Color.cpp @@ -15,9 +15,6 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ -#ifndef _VERTEXLOADERCOLOR_H -#define _VERTEXLOADERCOLOR_H - #include "Common.h" #include "VideoCommon.h" #include "LookUpTables.h" @@ -37,8 +34,7 @@ extern int colElements[2]; __forceinline void _SetCol(u32 val) { - *(u32*)VertexManager::s_pCurBufferPointer = val; - VertexManager::s_pCurBufferPointer += 4; + DataWrite(val); colIndex++; } @@ -132,80 +128,65 @@ void LOADERDECL Color_ReadDirect_32b_8888() _SetCol(col); } - - -void LOADERDECL Color_ReadIndex8_16b_565() +template <typename I> +void Color_ReadIndex_16b_565() { - u8 Index = DataReadU8(); + auto const Index = DataRead<I>(); u16 val = Common::swap16(*(const u16 *)(cached_arraybases[ARRAY_COLOR+colIndex] + (Index * arraystrides[ARRAY_COLOR+colIndex]))); _SetCol565(val); } -void LOADERDECL Color_ReadIndex8_24b_888() + +template <typename I> +void Color_ReadIndex_24b_888() { - u8 Index = DataReadU8(); + auto const Index = DataRead<I>(); const u8 *iAddress = cached_arraybases[ARRAY_COLOR+colIndex] + (Index * arraystrides[ARRAY_COLOR+colIndex]); _SetCol(_Read24(iAddress)); } -void LOADERDECL Color_ReadIndex8_32b_888x() + +template <typename I> +void Color_ReadIndex_32b_888x() { - u8 Index = DataReadU8(); + auto const Index = DataRead<I>(); const u8 *iAddress = cached_arraybases[ARRAY_COLOR+colIndex] + (Index * arraystrides[ARRAY_COLOR+colIndex]); _SetCol(_Read24(iAddress)); } -void LOADERDECL Color_ReadIndex8_16b_4444() + +template <typename I> +void Color_ReadIndex_16b_4444() { - u8 Index = DataReadU8(); + auto const Index = DataRead<I>(); u16 val = *(const u16 *)(cached_arraybases[ARRAY_COLOR+colIndex] + (Index * arraystrides[ARRAY_COLOR+colIndex])); _SetCol4444(val); } -void LOADERDECL Color_ReadIndex8_24b_6666() + +template <typename I> +void Color_ReadIndex_24b_6666() { - u8 Index = DataReadU8(); + auto const Index = DataRead<I>(); const u8* pData = cached_arraybases[ARRAY_COLOR+colIndex] + (Index * arraystrides[ARRAY_COLOR+colIndex]) - 1; u32 val = Common::swap32(pData); _SetCol6666(val); } -void LOADERDECL Color_ReadIndex8_32b_8888() -{ - u8 Index = DataReadU8(); - const u8 *iAddress = cached_arraybases[ARRAY_COLOR+colIndex] + (Index * arraystrides[ARRAY_COLOR+colIndex]); - _SetCol(_Read32(iAddress)); -} -void LOADERDECL Color_ReadIndex16_16b_565() -{ - u16 Index = DataReadU16(); - u16 val = Common::swap16(*(const u16 *)(cached_arraybases[ARRAY_COLOR+colIndex] + (Index * arraystrides[ARRAY_COLOR+colIndex]))); - _SetCol565(val); -} -void LOADERDECL Color_ReadIndex16_24b_888() -{ - u16 Index = DataReadU16(); - const u8 *iAddress = cached_arraybases[ARRAY_COLOR+colIndex] + (Index * arraystrides[ARRAY_COLOR+colIndex]); - _SetCol(_Read24(iAddress)); -} -void LOADERDECL Color_ReadIndex16_32b_888x() -{ - u16 Index = DataReadU16(); - const u8 *iAddress = cached_arraybases[ARRAY_COLOR+colIndex] + (Index * arraystrides[ARRAY_COLOR+colIndex]); - _SetCol(_Read24(iAddress)); -} -void LOADERDECL Color_ReadIndex16_16b_4444() -{ - u16 Index = DataReadU16(); - u16 val = *(const u16 *)(cached_arraybases[ARRAY_COLOR+colIndex] + (Index * arraystrides[ARRAY_COLOR+colIndex])); - _SetCol4444(val); -} -void LOADERDECL Color_ReadIndex16_24b_6666() -{ - u16 Index = DataReadU16(); - const u8 *pData = cached_arraybases[ARRAY_COLOR+colIndex] + (Index * arraystrides[ARRAY_COLOR+colIndex]) - 1; - u32 val = Common::swap32(pData); - _SetCol6666(val); -} -void LOADERDECL Color_ReadIndex16_32b_8888() + +template <typename I> +void Color_ReadIndex_32b_8888() { - u16 Index = DataReadU16(); + auto const Index = DataRead<I>(); const u8 *iAddress = cached_arraybases[ARRAY_COLOR+colIndex] + (Index * arraystrides[ARRAY_COLOR+colIndex]); _SetCol(_Read32(iAddress)); } -#endif + +void LOADERDECL Color_ReadIndex8_16b_565() { Color_ReadIndex_16b_565<u8>(); } +void LOADERDECL Color_ReadIndex8_24b_888() { Color_ReadIndex_24b_888<u8>(); } +void LOADERDECL Color_ReadIndex8_32b_888x() { Color_ReadIndex_32b_888x<u8>(); } +void LOADERDECL Color_ReadIndex8_16b_4444() { Color_ReadIndex_16b_4444<u8>(); } +void LOADERDECL Color_ReadIndex8_24b_6666() { Color_ReadIndex_24b_6666<u8>(); } +void LOADERDECL Color_ReadIndex8_32b_8888() { Color_ReadIndex_32b_8888<u8>(); } + +void LOADERDECL Color_ReadIndex16_16b_565() { Color_ReadIndex_16b_565<u16>(); } +void LOADERDECL Color_ReadIndex16_24b_888() { Color_ReadIndex_24b_888<u16>(); } +void LOADERDECL Color_ReadIndex16_32b_888x() { Color_ReadIndex_32b_888x<u16>(); } +void LOADERDECL Color_ReadIndex16_16b_4444() { Color_ReadIndex_16b_4444<u16>(); } +void LOADERDECL Color_ReadIndex16_24b_6666() { Color_ReadIndex_24b_6666<u16>(); } +void LOADERDECL Color_ReadIndex16_32b_8888() { Color_ReadIndex_32b_8888<u16>(); } diff --git a/Source/Core/VideoCommon/Src/VertexLoader_Normal.cpp b/Source/Core/VideoCommon/Src/VertexLoader_Normal.cpp index 830bd3de13..a5ea1981da 100644 --- a/Source/Core/VideoCommon/Src/VertexLoader_Normal.cpp +++ b/Source/Core/VideoCommon/Src/VertexLoader_Normal.cpp @@ -22,6 +22,7 @@ #include "VertexManagerBase.h" #include "CPUDetect.h" #include <cmath> +#include <limits> #if _M_SSE >= 0x401 #include <smmintrin.h> @@ -30,398 +31,174 @@ #include <tmmintrin.h> #endif +// warning: mapping buffer should be disabled to use this #define LOG_NORM() // PRIM_LOG("norm: %f %f %f, ", ((float*)VertexManager::s_pCurBufferPointer)[-3], ((float*)VertexManager::s_pCurBufferPointer)[-2], ((float*)VertexManager::s_pCurBufferPointer)[-1]); VertexLoader_Normal::Set VertexLoader_Normal::m_Table[NUM_NRM_TYPE][NUM_NRM_INDICES][NUM_NRM_ELEMENTS][NUM_NRM_FORMAT]; -void VertexLoader_Normal::Init(void) -{ - // HACK is for signed instead of unsigned to prevent crashes. - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT] [FORMAT_UBYTE] = Set(3, Normal_DirectByte); //HACK - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT] [FORMAT_BYTE] = Set(3, Normal_DirectByte); - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT] [FORMAT_USHORT] = Set(6, Normal_DirectShort); //HACK - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT] [FORMAT_SHORT] = Set(6, Normal_DirectShort); - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT] [FORMAT_FLOAT] = Set(12, Normal_DirectFloat); - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT3][FORMAT_UBYTE] = Set(9, Normal_DirectByte3); //HACK - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT3][FORMAT_BYTE] = Set(9, Normal_DirectByte3); - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT3][FORMAT_USHORT] = Set(18, Normal_DirectShort3); //HACK - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT3][FORMAT_SHORT] = Set(18, Normal_DirectShort3); - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT3][FORMAT_FLOAT] = Set(36, Normal_DirectFloat3); - - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT] [FORMAT_UBYTE] = Set(3, Normal_DirectByte); //HACK - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT] [FORMAT_BYTE] = Set(3, Normal_DirectByte); - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT] [FORMAT_USHORT] = Set(6, Normal_DirectShort); //HACK - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT] [FORMAT_SHORT] = Set(6, Normal_DirectShort); - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT] [FORMAT_FLOAT] = Set(12, Normal_DirectFloat); - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT3][FORMAT_UBYTE] = Set(9, Normal_DirectByte3); //HACK - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT3][FORMAT_BYTE] = Set(9, Normal_DirectByte3); - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT3][FORMAT_USHORT] = Set(18, Normal_DirectShort3); //HACK - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT3][FORMAT_SHORT] = Set(18, Normal_DirectShort3); - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT3][FORMAT_FLOAT] = Set(36, Normal_DirectFloat3); - - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT] [FORMAT_UBYTE] = Set(1, Normal_Index8_Byte); //HACK - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT] [FORMAT_BYTE] = Set(1, Normal_Index8_Byte); - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT] [FORMAT_USHORT] = Set(1, Normal_Index8_Short); //HACK - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT] [FORMAT_SHORT] = Set(1, Normal_Index8_Short); - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT] [FORMAT_FLOAT] = Set(1, Normal_Index8_Float); - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT3][FORMAT_UBYTE] = Set(1, Normal_Index8_Byte3_Indices1); //HACK - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT3][FORMAT_BYTE] = Set(1, Normal_Index8_Byte3_Indices1); - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT3][FORMAT_USHORT] = Set(1, Normal_Index8_Short3_Indices1); //HACK - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT3][FORMAT_SHORT] = Set(1, Normal_Index8_Short3_Indices1); - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT3][FORMAT_FLOAT] = Set(1, Normal_Index8_Float3_Indices1); - - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT] [FORMAT_UBYTE] = Set(1, Normal_Index8_Byte); //HACK - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT] [FORMAT_BYTE] = Set(1, Normal_Index8_Byte); - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT] [FORMAT_USHORT] = Set(1, Normal_Index8_Short); //HACK - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT] [FORMAT_SHORT] = Set(1, Normal_Index8_Short); - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT] [FORMAT_FLOAT] = Set(1, Normal_Index8_Float); - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT3][FORMAT_UBYTE] = Set(3, Normal_Index8_Byte3_Indices3); //HACK - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT3][FORMAT_BYTE] = Set(3, Normal_Index8_Byte3_Indices3); - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT3][FORMAT_USHORT] = Set(3, Normal_Index8_Short3_Indices3); //HACK - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT3][FORMAT_SHORT] = Set(3, Normal_Index8_Short3_Indices3); - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT3][FORMAT_FLOAT] = Set(3, Normal_Index8_Float3_Indices3); - - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT] [FORMAT_UBYTE] = Set(2, Normal_Index16_Byte); //HACK - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT] [FORMAT_BYTE] = Set(2, Normal_Index16_Byte); - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT] [FORMAT_USHORT] = Set(2, Normal_Index16_Short); //HACK - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT] [FORMAT_SHORT] = Set(2, Normal_Index16_Short); - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT] [FORMAT_FLOAT] = Set(2, Normal_Index16_Float); - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_UBYTE] = Set(2, Normal_Index16_Byte3_Indices1); //HACK - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_BYTE] = Set(2, Normal_Index16_Byte3_Indices1); - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_USHORT] = Set(2, Normal_Index16_Short3_Indices1); //HACK - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_SHORT] = Set(2, Normal_Index16_Short3_Indices1); - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_FLOAT] = Set(2, Normal_Index16_Float3_Indices1); - - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT] [FORMAT_UBYTE] = Set(2, Normal_Index16_Byte); //HACK - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT] [FORMAT_BYTE] = Set(2, Normal_Index16_Byte); - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT] [FORMAT_USHORT] = Set(2, Normal_Index16_Short); //HACK - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT] [FORMAT_SHORT] = Set(2, Normal_Index16_Short); - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT] [FORMAT_FLOAT] = Set(2, Normal_Index16_Float); - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_UBYTE] = Set(6, Normal_Index16_Byte3_Indices3); //HACK - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_BYTE] = Set(6, Normal_Index16_Byte3_Indices3); - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_USHORT] = Set(6, Normal_Index16_Short3_Indices3); //HACK - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_SHORT] = Set(6, Normal_Index16_Short3_Indices3); - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_FLOAT] = Set(6, Normal_Index16_Float3_Indices3); -} - -unsigned int VertexLoader_Normal::GetSize(unsigned int _type, - unsigned int _format, unsigned int _elements, unsigned int _index3) +namespace { - return m_Table[_type][_index3][_elements][_format].gc_size; -} - -TPipelineFunction VertexLoader_Normal::GetFunction(unsigned int _type, - unsigned int _format, unsigned int _elements, unsigned int _index3) -{ - TPipelineFunction pFunc = m_Table[_type][_index3][_elements][_format].function; - return pFunc; -} -// This fracs are fixed acording to format -#define S8FRAC 0.015625f; // 1.0f / (1U << 6) -#define S16FRAC 0.00006103515625f; // 1.0f / (1U << 14) -// --- Direct --- - -inline void ReadIndirectS8x3(const s8* pData) +template <typename T> +__forceinline float FracAdjust(T val) { - ((float*)VertexManager::s_pCurBufferPointer)[0] = pData[0] * S8FRAC; - ((float*)VertexManager::s_pCurBufferPointer)[1] = pData[1] * S8FRAC; - ((float*)VertexManager::s_pCurBufferPointer)[2] = pData[2] * S8FRAC; - VertexManager::s_pCurBufferPointer += 12; - LOG_NORM(); -} + //auto const S8FRAC = 1.f / (1u << 6); + //auto const U8FRAC = 1.f / (1u << 7); + //auto const S16FRAC = 1.f / (1u << 14); + //auto const U16FRAC = 1.f / (1u << 15); -inline void ReadIndirectS8x9(const s8* pData) -{ - ((float*)VertexManager::s_pCurBufferPointer)[0] = pData[0] * S8FRAC; - ((float*)VertexManager::s_pCurBufferPointer)[1] = pData[1] * S8FRAC; - ((float*)VertexManager::s_pCurBufferPointer)[2] = pData[2] * S8FRAC; - LOG_NORM(); - ((float*)VertexManager::s_pCurBufferPointer)[3] = pData[3] * S8FRAC; - ((float*)VertexManager::s_pCurBufferPointer)[4] = pData[4] * S8FRAC; - ((float*)VertexManager::s_pCurBufferPointer)[5] = pData[5] * S8FRAC; - LOG_NORM(); - ((float*)VertexManager::s_pCurBufferPointer)[6] = pData[6] * S8FRAC; - ((float*)VertexManager::s_pCurBufferPointer)[7] = pData[7] * S8FRAC; - ((float*)VertexManager::s_pCurBufferPointer)[8] = pData[8] * S8FRAC; - LOG_NORM(); - VertexManager::s_pCurBufferPointer += 36; + // TODO: is this right? + return val / float(1u << (sizeof(T) * 8 - std::numeric_limits<T>::is_signed - 1)); } -inline void ReadIndirectS16x3(const u16* pData) -{ - ((float*)VertexManager::s_pCurBufferPointer)[0] = ((s16)Common::swap16(pData[0])) * S16FRAC; - ((float*)VertexManager::s_pCurBufferPointer)[1] = ((s16)Common::swap16(pData[1])) * S16FRAC; - ((float*)VertexManager::s_pCurBufferPointer)[2] = ((s16)Common::swap16(pData[2])) * S16FRAC; - VertexManager::s_pCurBufferPointer += 12; - LOG_NORM() -} +template <> +__forceinline float FracAdjust(float val) +{ return val; } -inline void ReadIndirectS16x9(const u16* pData) +template <typename T, int N> +__forceinline void ReadIndirect(const T* data) { - ((float*)VertexManager::s_pCurBufferPointer)[0] = ((s16)Common::swap16(pData[0])) * S16FRAC; - ((float*)VertexManager::s_pCurBufferPointer)[1] = ((s16)Common::swap16(pData[1])) * S16FRAC; - ((float*)VertexManager::s_pCurBufferPointer)[2] = ((s16)Common::swap16(pData[2])) * S16FRAC; - LOG_NORM() - ((float*)VertexManager::s_pCurBufferPointer)[3] = ((s16)Common::swap16(pData[3])) * S16FRAC; - ((float*)VertexManager::s_pCurBufferPointer)[4] = ((s16)Common::swap16(pData[4])) * S16FRAC; - ((float*)VertexManager::s_pCurBufferPointer)[5] = ((s16)Common::swap16(pData[5])) * S16FRAC; - LOG_NORM() - ((float*)VertexManager::s_pCurBufferPointer)[6] = ((s16)Common::swap16(pData[6])) * S16FRAC; - ((float*)VertexManager::s_pCurBufferPointer)[7] = ((s16)Common::swap16(pData[7])) * S16FRAC; - ((float*)VertexManager::s_pCurBufferPointer)[8] = ((s16)Common::swap16(pData[8])) * S16FRAC; - LOG_NORM() - VertexManager::s_pCurBufferPointer += 36; -} + static_assert(3 == N || 9 == N, "N is only sane as 3 or 9!"); -inline void ReadIndirectFloatx3(const u32* pData) -{ - ((u32*)VertexManager::s_pCurBufferPointer)[0] = Common::swap32(pData[0]); - ((u32*)VertexManager::s_pCurBufferPointer)[1] = Common::swap32(pData[1]); - ((u32*)VertexManager::s_pCurBufferPointer)[2] = Common::swap32(pData[2]); - VertexManager::s_pCurBufferPointer += 12; - LOG_NORM(); -} + for (int i = 0; i != N; ++i) + { + DataWrite(FracAdjust(Common::FromBigEndian(data[i]))); + } -inline void ReadIndirectFloatx9(const u32* pData) -{ - ((u32*)VertexManager::s_pCurBufferPointer)[0] = Common::swap32(pData[0]); - ((u32*)VertexManager::s_pCurBufferPointer)[1] = Common::swap32(pData[1]); - ((u32*)VertexManager::s_pCurBufferPointer)[2] = Common::swap32(pData[2]); - LOG_NORM(); - ((u32*)VertexManager::s_pCurBufferPointer)[3] = Common::swap32(pData[3]); - ((u32*)VertexManager::s_pCurBufferPointer)[4] = Common::swap32(pData[4]); - ((u32*)VertexManager::s_pCurBufferPointer)[5] = Common::swap32(pData[5]); LOG_NORM(); - ((u32*)VertexManager::s_pCurBufferPointer)[6] = Common::swap32(pData[6]); - ((u32*)VertexManager::s_pCurBufferPointer)[7] = Common::swap32(pData[7]); - ((u32*)VertexManager::s_pCurBufferPointer)[8] = Common::swap32(pData[8]); - LOG_NORM(); - VertexManager::s_pCurBufferPointer += 36; -} - -inline void ReadDirectS8x3() -{ - const s8* Source = (const s8*)DataGetPosition(); - ReadIndirectS8x3(Source); - DataSkip(3); } -inline void ReadDirectS8x9() +template <typename T, int N> +struct Normal_Direct { - const s8* Source = (const s8*)DataGetPosition(); - ReadIndirectS8x9(Source); - DataSkip(9); -} - -inline void ReadDirectS16x3() -{ - const u16* Source = (const u16*)DataGetPosition(); - ReadIndirectS16x3(Source); - DataSkip(6); -} - -inline void ReadDirectS16x9() -{ - const u16* Source = (const u16*)DataGetPosition(); - ReadIndirectS16x9(Source); - DataSkip(18); -} - -inline void ReadDirectFloatx3() -{ - const u32* Source = (const u32*)DataGetPosition(); - ReadIndirectFloatx3(Source); - DataSkip(12); -} - -inline void ReadDirectFloatx9() -{ - const u32* Source = (const u32*)DataGetPosition(); - ReadIndirectFloatx9(Source); - DataSkip(36); -} - - - -void LOADERDECL VertexLoader_Normal::Normal_DirectByte() -{ - ReadDirectS8x3(); -} - -void LOADERDECL VertexLoader_Normal::Normal_DirectShort() -{ - ReadDirectS16x3(); -} - -void LOADERDECL VertexLoader_Normal::Normal_DirectFloat() -{ - ReadDirectFloatx3(); -} - -void LOADERDECL VertexLoader_Normal::Normal_DirectByte3() -{ - ReadDirectS8x9(); -} - -void LOADERDECL VertexLoader_Normal::Normal_DirectShort3() -{ - ReadDirectS16x9(); -} - -void LOADERDECL VertexLoader_Normal::Normal_DirectFloat3() -{ - ReadDirectFloatx9(); -} - - -// --- Index8 --- - -void LOADERDECL VertexLoader_Normal::Normal_Index8_Byte() -{ - u8 Index = DataReadU8(); - const s8* pData = (const s8 *)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL])); - ReadIndirectS8x3(pData); -} - -void LOADERDECL VertexLoader_Normal::Normal_Index8_Short() -{ - u8 Index = DataReadU8(); - const u16* pData = (const u16 *)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL])); - ReadIndirectS16x3(pData); -} - -void LOADERDECL VertexLoader_Normal::Normal_Index8_Float() -{ - u8 Index = DataReadU8(); - const u32* pData = (const u32 *)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL])); - ReadIndirectFloatx3(pData); -} - -void LOADERDECL VertexLoader_Normal::Normal_Index8_Byte3_Indices1() -{ - u8 Index = DataReadU8(); - const s8* pData = (const s8 *)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL])); - ReadIndirectS8x9(pData); -} - -void LOADERDECL VertexLoader_Normal::Normal_Index8_Short3_Indices1() -{ - u8 Index = DataReadU8(); - const u16* pData = (const u16 *)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL])); - ReadIndirectS16x9(pData); -} - -void LOADERDECL VertexLoader_Normal::Normal_Index8_Float3_Indices1() -{ - u8 Index = DataReadU8(); - const u32* pData = (const u32 *)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL])); - ReadIndirectFloatx9(pData); -} - -void LOADERDECL VertexLoader_Normal::Normal_Index8_Byte3_Indices3() -{ - for (int i = 0; i < 3; i++) + static void LOADERDECL function() { - u8 Index = DataReadU8(); - const s8* pData = (const s8*)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL]) + 1*3*i); - ReadIndirectS8x3(pData); - } -} + auto const source = reinterpret_cast<const T*>(DataGetPosition()); + ReadIndirect<T, N * 3>(source); + DataSkip<N * 3 * sizeof(T)>(); + } + static const int size = sizeof(T) * N * 3; +}; -void LOADERDECL VertexLoader_Normal::Normal_Index8_Short3_Indices3() +template <typename I, typename T, int N, int Offset> +__forceinline void Normal_Index_Offset() { - for (int i = 0; i < 3; i++) - { - u8 Index = DataReadU8(); - const u16* pData = (const u16 *)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL]) + 2*3*i); - ReadIndirectS16x3(pData); - } + static_assert(!std::numeric_limits<I>::is_signed, "Only unsigned I is sane!"); + + auto const index = DataRead<I>(); + auto const data = reinterpret_cast<const T*>(cached_arraybases[ARRAY_NORMAL] + + (index * arraystrides[ARRAY_NORMAL]) + sizeof(T) * 3 * Offset); + ReadIndirect<T, N * 3>(data); } -void LOADERDECL VertexLoader_Normal::Normal_Index8_Float3_Indices3() +template <typename I, typename T, int N> +struct Normal_Index { - for (int i = 0; i < 3; i++) + static void LOADERDECL function() { - u8 Index = DataReadU8(); - const u32* pData = (const u32 *)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL]) + 4*3*i); - ReadIndirectFloatx3(pData); - } -} + Normal_Index_Offset<I, T, N, 0>(); + } + static const int size = sizeof(I); +}; -// --- Index16 --- - - -void LOADERDECL VertexLoader_Normal::Normal_Index16_Byte() -{ - u16 Index = DataReadU16(); - const s8* pData = (const s8 *)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL])); - ReadIndirectS8x3(pData); -} - -void LOADERDECL VertexLoader_Normal::Normal_Index16_Short() -{ - u16 Index = DataReadU16(); - const u16* pData = (const u16 *)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL])); - ReadIndirectS16x3(pData); -} - -void LOADERDECL VertexLoader_Normal::Normal_Index16_Float() -{ - u16 Index = DataReadU16(); - const u32* pData = (const u32 *)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL])); - ReadIndirectFloatx3(pData); -} - -void LOADERDECL VertexLoader_Normal::Normal_Index16_Byte3_Indices1() +template <typename I, typename T> +struct Normal_Index_Indices3 { - u16 Index = DataReadU16(); - const s8* pData = (const s8 *)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL])); - ReadIndirectS8x9(pData); -} + static void LOADERDECL function() + { + Normal_Index_Offset<I, T, 1, 0>(); + Normal_Index_Offset<I, T, 1, 1>(); + Normal_Index_Offset<I, T, 1, 2>(); + } -void LOADERDECL VertexLoader_Normal::Normal_Index16_Short3_Indices1() -{ - u16 Index = DataReadU16(); - const u16* pData = (const u16 *)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL])); - ReadIndirectS16x9(pData); -} + static const int size = sizeof(I) * 3; +}; -void LOADERDECL VertexLoader_Normal::Normal_Index16_Float3_Indices1() -{ - u16 Index = DataReadU16(); - const u32* pData = (const u32 *)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL])); - ReadIndirectFloatx9(pData); } -void LOADERDECL VertexLoader_Normal::Normal_Index16_Byte3_Indices3() +void VertexLoader_Normal::Init(void) { - for (int i = 0; i < 3; i++) - { - u16 Index = DataReadU16(); - const s8* pData = (const s8*)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL]) + 1*3*i); - ReadIndirectS8x3(pData); - } + m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT] [FORMAT_UBYTE] = Normal_Direct<u8, 1>(); + m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT] [FORMAT_BYTE] = Normal_Direct<s8, 1>(); + m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT] [FORMAT_USHORT] = Normal_Direct<u16, 1>(); + m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT] [FORMAT_SHORT] = Normal_Direct<s16, 1>(); + m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT] [FORMAT_FLOAT] = Normal_Direct<float, 1>(); + m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT3][FORMAT_UBYTE] = Normal_Direct<u8, 3>(); + m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT3][FORMAT_BYTE] = Normal_Direct<s8, 3>(); + m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT3][FORMAT_USHORT] = Normal_Direct<u16, 3>(); + m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT3][FORMAT_SHORT] = Normal_Direct<s16, 3>(); + m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT3][FORMAT_FLOAT] = Normal_Direct<float, 3>(); + + // Same as above + m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT] [FORMAT_UBYTE] = Normal_Direct<u8, 1>(); + m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT] [FORMAT_BYTE] = Normal_Direct<s8, 1>(); + m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT] [FORMAT_USHORT] = Normal_Direct<u16, 1>(); + m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT] [FORMAT_SHORT] = Normal_Direct<s16, 1>(); + m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT] [FORMAT_FLOAT] = Normal_Direct<float, 1>(); + m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT3][FORMAT_UBYTE] = Normal_Direct<u8, 3>(); + m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT3][FORMAT_BYTE] = Normal_Direct<s8, 3>(); + m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT3][FORMAT_USHORT] = Normal_Direct<u16, 3>(); + m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT3][FORMAT_SHORT] = Normal_Direct<s16, 3>(); + m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT3][FORMAT_FLOAT] = Normal_Direct<float, 3>(); + + m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT] [FORMAT_UBYTE] = Normal_Index<u8, u8, 1>(); + m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT] [FORMAT_BYTE] = Normal_Index<u8, s8, 1>(); + m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT] [FORMAT_USHORT] = Normal_Index<u8, u16, 1>(); + m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT] [FORMAT_SHORT] = Normal_Index<u8, s16, 1>(); + m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT] [FORMAT_FLOAT] = Normal_Index<u8, float, 1>(); + m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT3][FORMAT_UBYTE] = Normal_Index<u8, u8, 3>(); + m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT3][FORMAT_BYTE] = Normal_Index<u8, s8, 3>(); + m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT3][FORMAT_USHORT] = Normal_Index<u8, u16, 3>(); + m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT3][FORMAT_SHORT] = Normal_Index<u8, s16, 3>(); + m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT3][FORMAT_FLOAT] = Normal_Index<u8, float, 3>(); + + // Same as above for NRM_NBT + m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT] [FORMAT_UBYTE] = Normal_Index<u8, u8, 1>(); + m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT] [FORMAT_BYTE] = Normal_Index<u8, s8, 1>(); + m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT] [FORMAT_USHORT] = Normal_Index<u8, u16, 1>(); + m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT] [FORMAT_SHORT] = Normal_Index<u8, s16, 1>(); + m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT] [FORMAT_FLOAT] = Normal_Index<u8, float, 1>(); + m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT3][FORMAT_UBYTE] = Normal_Index_Indices3<u8, u8>(); + m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT3][FORMAT_BYTE] = Normal_Index_Indices3<u8, s8>(); + m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT3][FORMAT_USHORT] = Normal_Index_Indices3<u8, u16>(); + m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT3][FORMAT_SHORT] = Normal_Index_Indices3<u8, s16>(); + m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT3][FORMAT_FLOAT] = Normal_Index_Indices3<u8, float>(); + + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT] [FORMAT_UBYTE] = Normal_Index<u16, u8, 1>(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT] [FORMAT_BYTE] = Normal_Index<u16, s8, 1>(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT] [FORMAT_USHORT] = Normal_Index<u16, u16, 1>(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT] [FORMAT_SHORT] = Normal_Index<u16, s16, 1>(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT] [FORMAT_FLOAT] = Normal_Index<u16, float, 1>(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_UBYTE] = Normal_Index<u16, u8, 3>(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_BYTE] = Normal_Index<u16, s8, 3>(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_USHORT] = Normal_Index<u16, u16, 3>(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_SHORT] = Normal_Index<u16, s16, 3>(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_FLOAT] = Normal_Index<u16, float, 3>(); + + // Same as above for NRM_NBT + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT] [FORMAT_UBYTE] = Normal_Index<u16, u8, 1>(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT] [FORMAT_BYTE] = Normal_Index<u16, s8, 1>(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT] [FORMAT_USHORT] = Normal_Index<u16, u16, 1>(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT] [FORMAT_SHORT] = Normal_Index<u16, s16, 1>(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT] [FORMAT_FLOAT] = Normal_Index<u16, float, 1>(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_UBYTE] = Normal_Index_Indices3<u16, u8>(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_BYTE] = Normal_Index_Indices3<u16, s8>(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_USHORT] = Normal_Index_Indices3<u16, u16>(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_SHORT] = Normal_Index_Indices3<u16, s16>(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_FLOAT] = Normal_Index_Indices3<u16, float>(); } -void LOADERDECL VertexLoader_Normal::Normal_Index16_Short3_Indices3() +unsigned int VertexLoader_Normal::GetSize(unsigned int _type, + unsigned int _format, unsigned int _elements, unsigned int _index3) { - for (int i = 0; i < 3; i++) - { - u16 Index = DataReadU16(); - const u16* pData = (const u16 *)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL]) + 2*3*i); - ReadIndirectS16x3(pData); - } + return m_Table[_type][_index3][_elements][_format].gc_size; } -void LOADERDECL VertexLoader_Normal::Normal_Index16_Float3_Indices3() +TPipelineFunction VertexLoader_Normal::GetFunction(unsigned int _type, + unsigned int _format, unsigned int _elements, unsigned int _index3) { - for (int i = 0; i < 3; i++) - { - u16 Index = DataReadU16(); - const u32* pData = (const u32 *)(cached_arraybases[ARRAY_NORMAL] + (Index * arraystrides[ARRAY_NORMAL]) + 4*3*i); - ReadIndirectFloatx3(pData); - } + TPipelineFunction pFunc = m_Table[_type][_index3][_elements][_format].function; + return pFunc; } diff --git a/Source/Core/VideoCommon/Src/VertexLoader_Normal.h b/Source/Core/VideoCommon/Src/VertexLoader_Normal.h index 934cd1ec43..a631ab9751 100644 --- a/Source/Core/VideoCommon/Src/VertexLoader_Normal.h +++ b/Source/Core/VideoCommon/Src/VertexLoader_Normal.h @@ -25,43 +25,43 @@ class VertexLoader_Normal { public: - // Init - static void Init(void); + // Init + static void Init(void); - // GetSize - static unsigned int GetSize(unsigned int _type, unsigned int _format, + // GetSize + static unsigned int GetSize(unsigned int _type, unsigned int _format, unsigned int _elements, unsigned int _index3); - // GetFunction - static TPipelineFunction GetFunction(unsigned int _type, + // GetFunction + static TPipelineFunction GetFunction(unsigned int _type, unsigned int _format, unsigned int _elements, unsigned int _index3); private: - enum ENormalType - { - NRM_NOT_PRESENT = 0, - NRM_DIRECT = 1, - NRM_INDEX8 = 2, - NRM_INDEX16 = 3, - NUM_NRM_TYPE - }; - - enum ENormalFormat - { - FORMAT_UBYTE = 0, - FORMAT_BYTE = 1, - FORMAT_USHORT = 2, - FORMAT_SHORT = 3, - FORMAT_FLOAT = 4, - NUM_NRM_FORMAT - }; - - enum ENormalElements - { - NRM_NBT = 0, - NRM_NBT3 = 1, - NUM_NRM_ELEMENTS - }; + enum ENormalType + { + NRM_NOT_PRESENT = 0, + NRM_DIRECT = 1, + NRM_INDEX8 = 2, + NRM_INDEX16 = 3, + NUM_NRM_TYPE + }; + + enum ENormalFormat + { + FORMAT_UBYTE = 0, + FORMAT_BYTE = 1, + FORMAT_USHORT = 2, + FORMAT_SHORT = 3, + FORMAT_FLOAT = 4, + NUM_NRM_FORMAT + }; + + enum ENormalElements + { + NRM_NBT = 0, + NRM_NBT3 = 1, + NUM_NRM_ELEMENTS + }; enum ENormalIndices { @@ -70,45 +70,20 @@ private: NUM_NRM_INDICES }; - struct Set { - Set() {} - Set(int gc_size_, TPipelineFunction function_) : gc_size(gc_size_), function(function_) {} + struct Set + { + template <typename T> + void operator=(const T&) + { + gc_size = T::size; + function = T::function; + } + int gc_size; TPipelineFunction function; -// int pc_size; }; static Set m_Table[NUM_NRM_TYPE][NUM_NRM_INDICES][NUM_NRM_ELEMENTS][NUM_NRM_FORMAT]; - - // direct - static void LOADERDECL Normal_DirectByte(); - static void LOADERDECL Normal_DirectShort(); - static void LOADERDECL Normal_DirectFloat(); - static void LOADERDECL Normal_DirectByte3(); - static void LOADERDECL Normal_DirectShort3(); - static void LOADERDECL Normal_DirectFloat3(); - - // index8 - static void LOADERDECL Normal_Index8_Byte(); - static void LOADERDECL Normal_Index8_Short(); - static void LOADERDECL Normal_Index8_Float(); - static void LOADERDECL Normal_Index8_Byte3_Indices1(); - static void LOADERDECL Normal_Index8_Short3_Indices1(); - static void LOADERDECL Normal_Index8_Float3_Indices1(); - static void LOADERDECL Normal_Index8_Byte3_Indices3(); - static void LOADERDECL Normal_Index8_Short3_Indices3(); - static void LOADERDECL Normal_Index8_Float3_Indices3(); - - // index16 - static void LOADERDECL Normal_Index16_Byte(); - static void LOADERDECL Normal_Index16_Short(); - static void LOADERDECL Normal_Index16_Float(); - static void LOADERDECL Normal_Index16_Byte3_Indices1(); - static void LOADERDECL Normal_Index16_Short3_Indices1(); - static void LOADERDECL Normal_Index16_Float3_Indices1(); - static void LOADERDECL Normal_Index16_Byte3_Indices3(); - static void LOADERDECL Normal_Index16_Short3_Indices3(); - static void LOADERDECL Normal_Index16_Float3_Indices3(); }; #endif diff --git a/Source/Core/VideoCommon/Src/VertexLoader_Position.cpp b/Source/Core/VideoCommon/Src/VertexLoader_Position.cpp index 06481f9ddf..fd902767be 100644 --- a/Source/Core/VideoCommon/Src/VertexLoader_Position.cpp +++ b/Source/Core/VideoCommon/Src/VertexLoader_Position.cpp @@ -15,6 +15,8 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ +#include <limits> + #include "Common.h" #include "VideoCommon.h" #include "VertexLoader.h" @@ -71,101 +73,42 @@ MOVUPS(MOffset(EDI, 0), XMM0); */ -// ============================================================================== -// Direct -// ============================================================================== - -template <class T, bool three> -void Pos_ReadDirect() +template <typename T> +float PosScale(T val) { - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(T)DataRead<T>() * posScale; - ((float*)VertexManager::s_pCurBufferPointer)[1] = (float)(T)DataRead<T>() * posScale; - if (three) - ((float*)VertexManager::s_pCurBufferPointer)[2] = (float)(T)DataRead<T>() * posScale; - else - ((float*)VertexManager::s_pCurBufferPointer)[2] = 0.0f; - LOG_VTX(); - VertexManager::s_pCurBufferPointer += 12; + return val * posScale; } -void LOADERDECL Pos_ReadDirect_UByte3() { Pos_ReadDirect<u8, true>(); } -void LOADERDECL Pos_ReadDirect_Byte3() { Pos_ReadDirect<s8, true>(); } -void LOADERDECL Pos_ReadDirect_UShort3() { Pos_ReadDirect<u16, true>(); } -void LOADERDECL Pos_ReadDirect_Short3() { Pos_ReadDirect<s16, true>(); } -void LOADERDECL Pos_ReadDirect_UByte2() { Pos_ReadDirect<u8, false>(); } -void LOADERDECL Pos_ReadDirect_Byte2() { Pos_ReadDirect<s8, false>(); } -void LOADERDECL Pos_ReadDirect_UShort2() { Pos_ReadDirect<u16, false>(); } -void LOADERDECL Pos_ReadDirect_Short2() { Pos_ReadDirect<s16, false>(); } +template <> +float PosScale(float val) +{ return val; } -void LOADERDECL Pos_ReadDirect_Float3() +template <typename T, int N> +void LOADERDECL Pos_ReadDirect() { - // No need to use floating point here. - ((u32 *)VertexManager::s_pCurBufferPointer)[0] = DataReadU32(); - ((u32 *)VertexManager::s_pCurBufferPointer)[1] = DataReadU32(); - ((u32 *)VertexManager::s_pCurBufferPointer)[2] = DataReadU32(); - LOG_VTX(); - VertexManager::s_pCurBufferPointer += 12; -} + static_assert(N <= 3, "N > 3 is not sane!"); + + for (int i = 0; i < 3; ++i) + DataWrite(i<N ? PosScale(DataRead<T>()) : 0.f); -void LOADERDECL Pos_ReadDirect_Float2() -{ - // No need to use floating point here. - ((u32 *)VertexManager::s_pCurBufferPointer)[0] = DataReadU32(); - ((u32 *)VertexManager::s_pCurBufferPointer)[1] = DataReadU32(); - ((u32 *)VertexManager::s_pCurBufferPointer)[2] = 0; LOG_VTX(); - VertexManager::s_pCurBufferPointer += 12; } - -template<class T, bool three,int MaxSize> -inline void Pos_ReadIndex_Byte(int Index) +template <typename I, typename T, int N> +void LOADERDECL Pos_ReadIndex() { - if(Index < MaxSize) - { - const u8* pData = cached_arraybases[ARRAY_POSITION] + ((u32)Index * arraystrides[ARRAY_POSITION]); - ((float*)VertexManager::s_pCurBufferPointer)[0] = ((float)(T)(pData[0])) * posScale; - ((float*)VertexManager::s_pCurBufferPointer)[1] = ((float)(T)(pData[1])) * posScale; - if (three) - ((float*)VertexManager::s_pCurBufferPointer)[2] = ((float)(T)(pData[2])) * posScale; - else - ((float*)VertexManager::s_pCurBufferPointer)[2] = 0.0f; - LOG_VTX(); - VertexManager::s_pCurBufferPointer += 12; - } -} + static_assert(!std::numeric_limits<I>::is_signed, "Only unsigned I is sane!"); + static_assert(N <= 3, "N > 3 is not sane!"); -template<class T, bool three,int MaxSize> -inline void Pos_ReadIndex_Short(int Index) -{ - if(Index < MaxSize) + auto const index = DataRead<I>(); + if (index < std::numeric_limits<I>::max()) { - const u16* pData = (const u16 *)(cached_arraybases[ARRAY_POSITION] + ((u32)Index * arraystrides[ARRAY_POSITION])); - ((float*)VertexManager::s_pCurBufferPointer)[0] = ((float)(T)Common::swap16(pData[0])) * posScale; - ((float*)VertexManager::s_pCurBufferPointer)[1] = ((float)(T)Common::swap16(pData[1])) * posScale; - if (three) - ((float*)VertexManager::s_pCurBufferPointer)[2] = ((float)(T)Common::swap16(pData[2])) * posScale; - else - ((float*)VertexManager::s_pCurBufferPointer)[2] = 0.0f; - LOG_VTX(); - VertexManager::s_pCurBufferPointer += 12; - } -} + auto const data = reinterpret_cast<const T*>(cached_arraybases[ARRAY_POSITION] + (index * arraystrides[ARRAY_POSITION])); + + for (int i = 0; i < 3; ++i) + DataWrite(i<N ? PosScale(Common::FromBigEndian(data[i])) : 0.f); -template<bool three,int MaxSize> -void Pos_ReadIndex_Float(int Index) -{ - if(Index < MaxSize) - { - const u32* pData = (const u32 *)(cached_arraybases[ARRAY_POSITION] + (Index * arraystrides[ARRAY_POSITION])); - ((u32*)VertexManager::s_pCurBufferPointer)[0] = Common::swap32(pData[0]); - ((u32*)VertexManager::s_pCurBufferPointer)[1] = Common::swap32(pData[1]); - if (three) - ((u32*)VertexManager::s_pCurBufferPointer)[2] = Common::swap32(pData[2]); - else - ((float*)VertexManager::s_pCurBufferPointer)[2] = 0.0f; LOG_VTX(); - VertexManager::s_pCurBufferPointer += 12; } } @@ -173,87 +116,22 @@ void Pos_ReadIndex_Float(int Index) static const __m128i kMaskSwap32_3 = _mm_set_epi32(0xFFFFFFFFL, 0x08090A0BL, 0x04050607L, 0x00010203L); static const __m128i kMaskSwap32_2 = _mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x04050607L, 0x00010203L); -template<bool three,int MaxSize> -void Pos_ReadIndex_Float_SSSE3(int Index) +template <typename I, bool three> +void LOADERDECL Pos_ReadIndex_Float_SSSE3() { - if(Index < MaxSize) + auto const index = DataRead<I>(); + if (index < std::numeric_limits<I>::max()) { - const u32* pData = (const u32 *)(cached_arraybases[ARRAY_POSITION] + (Index * arraystrides[ARRAY_POSITION])); + const u32* pData = (const u32 *)(cached_arraybases[ARRAY_POSITION] + (index * arraystrides[ARRAY_POSITION])); GC_ALIGNED128(const __m128i a = _mm_loadu_si128((__m128i*)pData)); GC_ALIGNED128(__m128i b = _mm_shuffle_epi8(a, three ? kMaskSwap32_3 : kMaskSwap32_2)); _mm_storeu_si128((__m128i*)VertexManager::s_pCurBufferPointer, b); + VertexManager::s_pCurBufferPointer += sizeof(float) * 3; LOG_VTX(); - VertexManager::s_pCurBufferPointer += 12; } } #endif -// Explicitly instantiate these functions to decrease the possibility of -// symbol binding problems when (only) calling them from JIT compiled code. -template void Pos_ReadDirect<u8, true>(); -template void Pos_ReadDirect<s8, true>(); -template void Pos_ReadDirect<u16, true>(); -template void Pos_ReadDirect<s16, true>(); -template void Pos_ReadDirect<u8, false>(); -template void Pos_ReadDirect<s8, false>(); -template void Pos_ReadDirect<u16, false>(); -template void Pos_ReadDirect<s16, false>(); -template void Pos_ReadIndex_Byte<u8, true, 255>(int Index); -template void Pos_ReadIndex_Byte<s8, true, 255>(int Index); -template void Pos_ReadIndex_Short<u16, true, 255>(int Index); -template void Pos_ReadIndex_Short<s16, true, 255>(int Index); -template void Pos_ReadIndex_Float<true, 255>(int Index); -template void Pos_ReadIndex_Byte<u8, false, 255>(int Index); -template void Pos_ReadIndex_Byte<s8, false, 255>(int Index); -template void Pos_ReadIndex_Short<u16, false, 255>(int Index); -template void Pos_ReadIndex_Short<s16, false, 255>(int Index); -template void Pos_ReadIndex_Float<false, 255>(int Index); -template void Pos_ReadIndex_Byte<u8, true, 65535>(int Index); -template void Pos_ReadIndex_Byte<s8, true, 65535>(int Index); -template void Pos_ReadIndex_Short<u16, true, 65535>(int Index); -template void Pos_ReadIndex_Short<s16, true, 65535>(int Index); -template void Pos_ReadIndex_Float<true, 65535>(int Index); -template void Pos_ReadIndex_Byte<u8, false, 65535>(int Index); -template void Pos_ReadIndex_Byte<s8, false, 65535>(int Index); -template void Pos_ReadIndex_Short<u16, false, 65535>(int Index); -template void Pos_ReadIndex_Short<s16, false, 65535>(int Index); -template void Pos_ReadIndex_Float<false, 65535>(int Index); - -// ============================================================================== -// Index 8 -// ============================================================================== -void LOADERDECL Pos_ReadIndex8_UByte3() {Pos_ReadIndex_Byte<u8, true, 255> (DataReadU8());} -void LOADERDECL Pos_ReadIndex8_Byte3() {Pos_ReadIndex_Byte<s8, true, 255> (DataReadU8());} -void LOADERDECL Pos_ReadIndex8_UShort3() {Pos_ReadIndex_Short<u16, true, 255> (DataReadU8());} -void LOADERDECL Pos_ReadIndex8_Short3() {Pos_ReadIndex_Short<s16, true, 255> (DataReadU8());} -void LOADERDECL Pos_ReadIndex8_Float3() {Pos_ReadIndex_Float<true, 255> (DataReadU8());} -void LOADERDECL Pos_ReadIndex8_UByte2() {Pos_ReadIndex_Byte<u8, false, 255>(DataReadU8());} -void LOADERDECL Pos_ReadIndex8_Byte2() {Pos_ReadIndex_Byte<s8, false, 255>(DataReadU8());} -void LOADERDECL Pos_ReadIndex8_UShort2() {Pos_ReadIndex_Short<u16, false, 255>(DataReadU8());} -void LOADERDECL Pos_ReadIndex8_Short2() {Pos_ReadIndex_Short<s16, false, 255>(DataReadU8());} -void LOADERDECL Pos_ReadIndex8_Float2() {Pos_ReadIndex_Float<false, 255> (DataReadU8());} - -// ============================================================================== -// Index 16 -// ============================================================================== -void LOADERDECL Pos_ReadIndex16_UByte3() {Pos_ReadIndex_Byte<u8, true, 65535> (DataReadU16());} -void LOADERDECL Pos_ReadIndex16_Byte3() {Pos_ReadIndex_Byte<s8, true, 65535> (DataReadU16());} -void LOADERDECL Pos_ReadIndex16_UShort3() {Pos_ReadIndex_Short<u16, true, 65535> (DataReadU16());} -void LOADERDECL Pos_ReadIndex16_Short3() {Pos_ReadIndex_Short<s16, true, 65535> (DataReadU16());} -void LOADERDECL Pos_ReadIndex16_Float3() {Pos_ReadIndex_Float<true, 65535> (DataReadU16());} -void LOADERDECL Pos_ReadIndex16_UByte2() {Pos_ReadIndex_Byte<u8, false, 65535>(DataReadU16());} -void LOADERDECL Pos_ReadIndex16_Byte2() {Pos_ReadIndex_Byte<s8, false, 65535>(DataReadU16());} -void LOADERDECL Pos_ReadIndex16_UShort2() {Pos_ReadIndex_Short<u16, false, 65535>(DataReadU16());} -void LOADERDECL Pos_ReadIndex16_Short2() {Pos_ReadIndex_Short<s16, false, 65535>(DataReadU16());} -void LOADERDECL Pos_ReadIndex16_Float2() {Pos_ReadIndex_Float<false, 65535> (DataReadU16());} - -#if _M_SSE >= 0x301 -void LOADERDECL Pos_ReadIndex8_Float3_SSSE3() {Pos_ReadIndex_Float_SSSE3<true, 255> (DataReadU8());} -void LOADERDECL Pos_ReadIndex8_Float2_SSSE3() {Pos_ReadIndex_Float_SSSE3<false, 255> (DataReadU8());} -void LOADERDECL Pos_ReadIndex16_Float3_SSSE3() {Pos_ReadIndex_Float_SSSE3<true, 65535> (DataReadU16());} -void LOADERDECL Pos_ReadIndex16_Float2_SSSE3() {Pos_ReadIndex_Float_SSSE3<false, 65535> (DataReadU16());} -#endif - static TPipelineFunction tableReadPosition[4][8][2] = { { {NULL, NULL,}, @@ -263,56 +141,40 @@ static TPipelineFunction tableReadPosition[4][8][2] = { {NULL, NULL,}, }, { - {Pos_ReadDirect_UByte2, Pos_ReadDirect_UByte3,}, - {Pos_ReadDirect_Byte2, Pos_ReadDirect_Byte3,}, - {Pos_ReadDirect_UShort2, Pos_ReadDirect_UShort3,}, - {Pos_ReadDirect_Short2, Pos_ReadDirect_Short3,}, - {Pos_ReadDirect_Float2, Pos_ReadDirect_Float3,}, + {Pos_ReadDirect<u8, 2>, Pos_ReadDirect<u8, 3>,}, + {Pos_ReadDirect<s8, 2>, Pos_ReadDirect<s8, 3>,}, + {Pos_ReadDirect<u16, 2>, Pos_ReadDirect<u16, 3>,}, + {Pos_ReadDirect<s16, 2>, Pos_ReadDirect<s16, 3>,}, + {Pos_ReadDirect<float, 2>, Pos_ReadDirect<float, 3>,}, }, { - {Pos_ReadIndex8_UByte2, Pos_ReadIndex8_UByte3,}, - {Pos_ReadIndex8_Byte2, Pos_ReadIndex8_Byte3,}, - {Pos_ReadIndex8_UShort2, Pos_ReadIndex8_UShort3,}, - {Pos_ReadIndex8_Short2, Pos_ReadIndex8_Short3,}, - {Pos_ReadIndex8_Float2, Pos_ReadIndex8_Float3,}, + {Pos_ReadIndex<u8, u8, 2>, Pos_ReadIndex<u8, u8, 3>,}, + {Pos_ReadIndex<u8, s8, 2>, Pos_ReadIndex<u8, s8, 3>,}, + {Pos_ReadIndex<u8, u16, 2>, Pos_ReadIndex<u8, u16, 3>,}, + {Pos_ReadIndex<u8, s16, 2>, Pos_ReadIndex<u8, s16, 3>,}, + {Pos_ReadIndex<u8, float, 2>, Pos_ReadIndex<u8, float, 3>,}, }, { - {Pos_ReadIndex16_UByte2, Pos_ReadIndex16_UByte3,}, - {Pos_ReadIndex16_Byte2, Pos_ReadIndex16_Byte3,}, - {Pos_ReadIndex16_UShort2, Pos_ReadIndex16_UShort3,}, - {Pos_ReadIndex16_Short2, Pos_ReadIndex16_Short3,}, - {Pos_ReadIndex16_Float2, Pos_ReadIndex16_Float3,}, + {Pos_ReadIndex<u16, u8, 2>, Pos_ReadIndex<u16, u8, 3>,}, + {Pos_ReadIndex<u16, s8, 2>, Pos_ReadIndex<u16, s8, 3>,}, + {Pos_ReadIndex<u16, u16, 2>, Pos_ReadIndex<u16, u16, 3>,}, + {Pos_ReadIndex<u16, s16, 2>, Pos_ReadIndex<u16, s16, 3>,}, + {Pos_ReadIndex<u16, float, 2>, Pos_ReadIndex<u16, float, 3>,}, }, }; static int tableReadPositionVertexSize[4][8][2] = { { - {0, 0,}, - {0, 0,}, - {0, 0,}, - {0, 0,}, - {0, 0,}, + {0, 0,}, {0, 0,}, {0, 0,}, {0, 0,}, {0, 0,}, }, { - {2, 3,}, - {2, 3,}, - {4, 6,}, - {4, 6,}, - {8, 12,}, + {2, 3,}, {2, 3,}, {4, 6,}, {4, 6,}, {8, 12,}, }, { - {1, 1,}, - {1, 1,}, - {1, 1,}, - {1, 1,}, - {1, 1,}, + {1, 1,}, {1, 1,}, {1, 1,}, {1, 1,}, {1, 1,}, }, { - {2, 2,}, - {2, 2,}, - {2, 2,}, - {2, 2,}, - {2, 2,}, + {2, 2,}, {2, 2,}, {2, 2,}, {2, 2,}, {2, 2,}, }, }; @@ -322,10 +184,10 @@ void VertexLoader_Position::Init(void) { #if _M_SSE >= 0x301 if (cpu_info.bSSSE3) { - tableReadPosition[2][4][0] = Pos_ReadIndex8_Float2_SSSE3; - tableReadPosition[2][4][1] = Pos_ReadIndex8_Float3_SSSE3; - tableReadPosition[3][4][0] = Pos_ReadIndex16_Float2_SSSE3; - tableReadPosition[3][4][1] = Pos_ReadIndex16_Float3_SSSE3; + tableReadPosition[2][4][0] = Pos_ReadIndex_Float_SSSE3<u8, false>; + tableReadPosition[2][4][1] = Pos_ReadIndex_Float_SSSE3<u8, true>; + tableReadPosition[3][4][0] = Pos_ReadIndex_Float_SSSE3<u16, false>; + tableReadPosition[3][4][1] = Pos_ReadIndex_Float_SSSE3<u16, true>; } #endif diff --git a/Source/Core/VideoCommon/Src/VertexLoader_Position.h b/Source/Core/VideoCommon/Src/VertexLoader_Position.h index db8d8a38b5..c659e05487 100644 --- a/Source/Core/VideoCommon/Src/VertexLoader_Position.h +++ b/Source/Core/VideoCommon/Src/VertexLoader_Position.h @@ -21,14 +21,14 @@ class VertexLoader_Position { public: - // Init - static void Init(void); + // Init + static void Init(void); - // GetSize - static unsigned int GetSize(unsigned int _type, unsigned int _format, unsigned int _elements); + // GetSize + static unsigned int GetSize(unsigned int _type, unsigned int _format, unsigned int _elements); - // GetFunction - static TPipelineFunction GetFunction(unsigned int _type, unsigned int _format, unsigned int _elements); + // GetFunction + static TPipelineFunction GetFunction(unsigned int _type, unsigned int _format, unsigned int _elements); }; #endif diff --git a/Source/Core/VideoCommon/Src/VertexLoader_TextCoord.cpp b/Source/Core/VideoCommon/Src/VertexLoader_TextCoord.cpp index ba3bb73f43..f914226a63 100644 --- a/Source/Core/VideoCommon/Src/VertexLoader_TextCoord.cpp +++ b/Source/Core/VideoCommon/Src/VertexLoader_TextCoord.cpp @@ -28,290 +28,79 @@ #include <tmmintrin.h> #endif -#define LOG_TEX1() // PRIM_LOG("tex: %f, ", ((float*)VertexManager::s_pCurBufferPointer)[0]); -#define LOG_TEX2() // PRIM_LOG("tex: %f %f, ", ((float*)VertexManager::s_pCurBufferPointer)[0], ((float*)VertexManager::s_pCurBufferPointer)[1]); +template <int N> +void LOG_TEX(); -extern int tcIndex; -extern float tcScale[8]; - -void LOADERDECL TexCoord_Read_Dummy() +template <> +__forceinline void LOG_TEX<1>() { - tcIndex++; + // warning: mapping buffer should be disabled to use this + // PRIM_LOG("tex: %f, ", ((float*)VertexManager::s_pCurBufferPointer)[-1]); } -void LOADERDECL TexCoord_ReadDirect_UByte1() +template <> +__forceinline void LOG_TEX<2>() { - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)DataReadU8() * tcScale[tcIndex]; - LOG_TEX1(); - VertexManager::s_pCurBufferPointer += 4; - tcIndex++; -} -void LOADERDECL TexCoord_ReadDirect_UByte2() -{ - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)DataReadU8() * tcScale[tcIndex]; - ((float*)VertexManager::s_pCurBufferPointer)[1] = (float)DataReadU8() * tcScale[tcIndex]; - LOG_TEX2(); - VertexManager::s_pCurBufferPointer += 8; - tcIndex++; + // warning: mapping buffer should be disabled to use this + // PRIM_LOG("tex: %f %f, ", ((float*)VertexManager::s_pCurBufferPointer)[-2], ((float*)VertexManager::s_pCurBufferPointer)[-1]); } -void LOADERDECL TexCoord_ReadDirect_Byte1() -{ - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(s8)DataReadU8() * tcScale[tcIndex]; - LOG_TEX1(); - VertexManager::s_pCurBufferPointer += 4; - tcIndex++; -} -void LOADERDECL TexCoord_ReadDirect_Byte2() -{ - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(s8)DataReadU8() * tcScale[tcIndex]; - ((float*)VertexManager::s_pCurBufferPointer)[1] = (float)(s8)DataReadU8() * tcScale[tcIndex]; - LOG_TEX2(); - VertexManager::s_pCurBufferPointer += 8; - tcIndex++; -} +extern int tcIndex; +extern float tcScale[8]; -void LOADERDECL TexCoord_ReadDirect_UShort1() -{ - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)DataReadU16() * tcScale[tcIndex]; - LOG_TEX1(); - VertexManager::s_pCurBufferPointer += 4; - tcIndex++; -} -void LOADERDECL TexCoord_ReadDirect_UShort2() +void LOADERDECL TexCoord_Read_Dummy() { - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)DataReadU16() * tcScale[tcIndex]; - ((float*)VertexManager::s_pCurBufferPointer)[1] = (float)DataReadU16() * tcScale[tcIndex]; - LOG_TEX2(); - VertexManager::s_pCurBufferPointer += 8; tcIndex++; } -void LOADERDECL TexCoord_ReadDirect_Short1() -{ - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(s16)DataReadU16() * tcScale[tcIndex]; - LOG_TEX1(); - VertexManager::s_pCurBufferPointer += 4; - tcIndex++; -} -void LOADERDECL TexCoord_ReadDirect_Short2() +template <typename T> +float TCScale(T val) { - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(s16)DataReadU16() * tcScale[tcIndex]; - ((float*)VertexManager::s_pCurBufferPointer)[1] = (float)(s16)DataReadU16() * tcScale[tcIndex]; - LOG_TEX2(); - VertexManager::s_pCurBufferPointer += 8; - tcIndex++; + return val * tcScale[tcIndex]; } -void LOADERDECL TexCoord_ReadDirect_Float1() -{ - ((u32*)VertexManager::s_pCurBufferPointer)[0] = DataReadU32(); - LOG_TEX1(); - VertexManager::s_pCurBufferPointer += 4; - tcIndex++; -} -void LOADERDECL TexCoord_ReadDirect_Float2() -{ - ((u32*)VertexManager::s_pCurBufferPointer)[0] = DataReadU32(); - ((u32*)VertexManager::s_pCurBufferPointer)[1] = DataReadU32(); - LOG_TEX2(); - VertexManager::s_pCurBufferPointer += 8; - tcIndex++; -} +template <> +float TCScale(float val) +{ return val; } -// ================================================================================== -void LOADERDECL TexCoord_ReadIndex8_UByte1() +template <typename T, int N> +void LOADERDECL TexCoord_ReadDirect() { - u8 Index = DataReadU8(); - const u8 *pData = cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex]); - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(*pData) * tcScale[tcIndex]; - LOG_TEX1(); - VertexManager::s_pCurBufferPointer += 4; - tcIndex++; -} -void LOADERDECL TexCoord_ReadIndex8_UByte2() -{ - u8 Index = DataReadU8(); - const u8 *pData = cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex]); - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(u8)(pData[0]) * tcScale[tcIndex]; - ((float*)VertexManager::s_pCurBufferPointer)[1] = (float)(u8)(pData[1]) * tcScale[tcIndex]; - LOG_TEX2(); - VertexManager::s_pCurBufferPointer += 8; - tcIndex++; -} + for (int i = 0; i != N; ++i) + DataWrite(TCScale(DataRead<T>())); -void LOADERDECL TexCoord_ReadIndex8_Byte1() -{ - u8 Index = DataReadU8(); - const u8 *pData = cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex]); + LOG_TEX<N>(); - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(s8)(*pData) * tcScale[tcIndex]; - LOG_TEX1(); - VertexManager::s_pCurBufferPointer += 4; - tcIndex++; -} -void LOADERDECL TexCoord_ReadIndex8_Byte2() -{ - u8 Index = DataReadU8(); - const u8 *pData = cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex]); - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(s8)(pData[0]) * tcScale[tcIndex]; - ((float*)VertexManager::s_pCurBufferPointer)[1] = (float)(s8)(pData[1]) * tcScale[tcIndex]; - LOG_TEX2(); - VertexManager::s_pCurBufferPointer += 8; - tcIndex++; + ++tcIndex; } -void LOADERDECL TexCoord_ReadIndex8_UShort1() -{ - u8 Index = DataReadU8(); - const u16 *pData = (const u16 *)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex])); - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(u16)Common::swap16(*pData) * tcScale[tcIndex]; - LOG_TEX1(); - VertexManager::s_pCurBufferPointer += 4; - tcIndex++; -} -void LOADERDECL TexCoord_ReadIndex8_UShort2() +template <typename I, typename T, int N> +void LOADERDECL TexCoord_ReadIndex() { - u8 Index = DataReadU8(); - const u16 *pData = (const u16 *)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex])); - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(u16)Common::swap16(pData[0]) * tcScale[tcIndex]; - ((float*)VertexManager::s_pCurBufferPointer)[1] = (float)(u16)Common::swap16(pData[1]) * tcScale[tcIndex]; - LOG_TEX2(); - VertexManager::s_pCurBufferPointer += 8; - tcIndex++; -} + static_assert(!std::numeric_limits<I>::is_signed, "Only unsigned I is sane!"); + + auto const index = DataRead<I>(); + auto const data = reinterpret_cast<const T*>(cached_arraybases[ARRAY_TEXCOORD0 + tcIndex] + + (index * arraystrides[ARRAY_TEXCOORD0 + tcIndex])); -void LOADERDECL TexCoord_ReadIndex8_Short1() -{ - u8 Index = DataReadU8(); - const u16 *pData = (const u16 *)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex])); - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(s16)Common::swap16(pData[0]) * tcScale[tcIndex]; - LOG_TEX1(); - VertexManager::s_pCurBufferPointer += 4; - tcIndex++; -} -void LOADERDECL TexCoord_ReadIndex8_Short2() -{ - u8 Index = DataReadU8(); - const u16 *pData = (const u16 *)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex])); - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(s16)Common::swap16(pData[0]) * tcScale[tcIndex]; - ((float*)VertexManager::s_pCurBufferPointer)[1] = (float)(s16)Common::swap16(pData[1]) * tcScale[tcIndex]; - LOG_TEX2(); - VertexManager::s_pCurBufferPointer += 8; - tcIndex++; -} + for (int i = 0; i != N; ++i) + DataWrite(TCScale(Common::FromBigEndian(data[i]))); -void LOADERDECL TexCoord_ReadIndex8_Float1() -{ - u16 Index = DataReadU8(); - const u32 *pData = (const u32 *)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex])); - ((u32*)VertexManager::s_pCurBufferPointer)[0] = Common::swap32(pData[0]); - LOG_TEX1(); - VertexManager::s_pCurBufferPointer += 4; - tcIndex++; -} -void LOADERDECL TexCoord_ReadIndex8_Float2() -{ - u16 Index = DataReadU8(); - const u32 *pData = (const u32 *)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex])); - ((u32*)VertexManager::s_pCurBufferPointer)[0] = Common::swap32(pData[0]); - ((u32*)VertexManager::s_pCurBufferPointer)[1] = Common::swap32(pData[1]); - LOG_TEX2(); - VertexManager::s_pCurBufferPointer += 8; - tcIndex++; -} - -// ================================================================================== -void LOADERDECL TexCoord_ReadIndex16_UByte1() -{ - u16 Index = DataReadU16(); - const u8 *pData = cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex]); - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(u8)(pData[0]) * tcScale[tcIndex]; - LOG_TEX1(); - VertexManager::s_pCurBufferPointer += 4; - tcIndex++; -} -void LOADERDECL TexCoord_ReadIndex16_UByte2() -{ - u16 Index = DataReadU16(); - const u8 *pData = cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex]); - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(u8)(pData[0]) * tcScale[tcIndex]; - ((float*)VertexManager::s_pCurBufferPointer)[1] = (float)(u8)(pData[1]) * tcScale[tcIndex]; - LOG_TEX2(); - VertexManager::s_pCurBufferPointer += 8; - tcIndex++; -} - -void LOADERDECL TexCoord_ReadIndex16_Byte1() -{ - u16 Index = DataReadU16(); - const u8 *pData = cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex]); - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(s8)(pData[0]) * tcScale[tcIndex]; - LOG_TEX1(); - VertexManager::s_pCurBufferPointer += 4; - tcIndex++; -} -void LOADERDECL TexCoord_ReadIndex16_Byte2() -{ - u16 Index = DataReadU16(); - const u8 *pData = cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex]); - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(s8)(pData[0]) * tcScale[tcIndex]; - ((float*)VertexManager::s_pCurBufferPointer)[1] = (float)(s8)(pData[1]) * tcScale[tcIndex]; - LOG_TEX2(); - VertexManager::s_pCurBufferPointer += 8; - tcIndex++; -} - -void LOADERDECL TexCoord_ReadIndex16_UShort1() -{ - u16 Index = DataReadU16(); - const u16* pData = (const u16 *)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex])); - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(u16)Common::swap16(pData[0]) * tcScale[tcIndex]; - LOG_TEX1(); - VertexManager::s_pCurBufferPointer += 4; - tcIndex++; -} -void LOADERDECL TexCoord_ReadIndex16_UShort2() -{ - u16 Index = DataReadU16(); - const u16* pData = (const u16 *)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex])); - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(u16)Common::swap16(pData[0]) * tcScale[tcIndex]; - ((float*)VertexManager::s_pCurBufferPointer)[1] = (float)(u16)Common::swap16(pData[1]) * tcScale[tcIndex]; - LOG_TEX2(); - VertexManager::s_pCurBufferPointer += 8; - tcIndex++; -} - -void LOADERDECL TexCoord_ReadIndex16_Short1() -{ - u16 Index = DataReadU16(); - const u16 *pData = (const u16 *)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex])); - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(s16)Common::swap16(*pData) * tcScale[tcIndex]; - LOG_TEX1(); - VertexManager::s_pCurBufferPointer += 4; - tcIndex++; -} - -void LOADERDECL TexCoord_ReadIndex16_Short2() -{ - // Heavy in ZWW - u16 Index = DataReadU16(); - const u16 *pData = (const u16 *)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex])); - ((float*)VertexManager::s_pCurBufferPointer)[0] = (float)(s16)Common::swap16(pData[0]) * tcScale[tcIndex]; - ((float*)VertexManager::s_pCurBufferPointer)[1] = (float)(s16)Common::swap16(pData[1]) * tcScale[tcIndex]; - LOG_TEX2(); - VertexManager::s_pCurBufferPointer += 8; - tcIndex++; + LOG_TEX<N>(); + ++tcIndex; } #if _M_SSE >= 0x401 static const __m128i kMaskSwap16_2 = _mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0x02030001L); -void LOADERDECL TexCoord_ReadIndex16_Short2_SSE4() +template <typename I> +void LOADERDECL TexCoord_ReadIndex_Short2_SSE4() { + static_assert(!std::numeric_limits<I>::is_signed, "Only unsigned I is sane!"); + // Heavy in ZWW - u16 Index = DataReadU16(); - const s32 *pData = (const s32*)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex])); + auto const index = DataRead<I>(); + const s32 *pData = (const s32*)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (index * arraystrides[ARRAY_TEXCOORD0+tcIndex])); const __m128i a = _mm_cvtsi32_si128(*pData); const __m128i b = _mm_shuffle_epi8(a, kMaskSwap16_2); const __m128i c = _mm_cvtepi16_epi32(b); @@ -319,47 +108,27 @@ void LOADERDECL TexCoord_ReadIndex16_Short2_SSE4() const __m128 e = _mm_load1_ps(&tcScale[tcIndex]); const __m128 f = _mm_mul_ps(d, e); _mm_storeu_ps((float*)VertexManager::s_pCurBufferPointer, f); - LOG_TEX2(); - VertexManager::s_pCurBufferPointer += 8; + VertexManager::s_pCurBufferPointer += sizeof(float) * 2; + LOG_TEX<2>(); tcIndex++; } #endif -void LOADERDECL TexCoord_ReadIndex16_Float1() -{ - u16 Index = DataReadU16(); - const u32 *pData = (const u32 *)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex])); - ((u32*)VertexManager::s_pCurBufferPointer)[0] = Common::swap32(pData[0]); - LOG_TEX1(); - VertexManager::s_pCurBufferPointer += 4; - tcIndex++; -} - -void LOADERDECL TexCoord_ReadIndex16_Float2() -{ - u16 Index = DataReadU16(); - const u32 *pData = (const u32 *)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex])); - ((u32*)VertexManager::s_pCurBufferPointer)[0] = Common::swap32(pData[0]); - ((u32*)VertexManager::s_pCurBufferPointer)[1] = Common::swap32(pData[1]); - LOG_TEX2(); - VertexManager::s_pCurBufferPointer += 8; - tcIndex++; -} - #if _M_SSE >= 0x301 static const __m128i kMaskSwap32 = _mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x04050607L, 0x00010203L); -void LOADERDECL TexCoord_ReadIndex16_Float2_SSSE3() +template <typename I> +void LOADERDECL TexCoord_ReadIndex_Float2_SSSE3() { - u16 Index = DataReadU16(); - const u32 *pData = (const u32 *)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex])); + static_assert(!std::numeric_limits<I>::is_signed, "Only unsigned I is sane!"); + + auto const index = DataRead<I>(); + const u32 *pData = (const u32 *)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (index * arraystrides[ARRAY_TEXCOORD0+tcIndex])); GC_ALIGNED128(const __m128i a = _mm_loadl_epi64((__m128i*)pData)); GC_ALIGNED128(const __m128i b = _mm_shuffle_epi8(a, kMaskSwap32)); - u8* p = VertexManager::s_pCurBufferPointer; - _mm_storel_epi64((__m128i*)p, b); - LOG_TEX2(); - p += 8; - VertexManager::s_pCurBufferPointer = p; + _mm_storel_epi64((__m128i*)VertexManager::s_pCurBufferPointer, b); + VertexManager::s_pCurBufferPointer += sizeof(float) * 2; + LOG_TEX<2>(); tcIndex++; } #endif @@ -373,56 +142,40 @@ static TPipelineFunction tableReadTexCoord[4][8][2] = { {NULL, NULL,}, }, { - {TexCoord_ReadDirect_UByte1, TexCoord_ReadDirect_UByte2,}, - {TexCoord_ReadDirect_Byte1, TexCoord_ReadDirect_Byte2,}, - {TexCoord_ReadDirect_UShort1, TexCoord_ReadDirect_UShort2,}, - {TexCoord_ReadDirect_Short1, TexCoord_ReadDirect_Short2,}, - {TexCoord_ReadDirect_Float1, TexCoord_ReadDirect_Float2,}, + {TexCoord_ReadDirect<u8, 1>, TexCoord_ReadDirect<u8, 2>,}, + {TexCoord_ReadDirect<s8, 1>, TexCoord_ReadDirect<s8, 2>,}, + {TexCoord_ReadDirect<u16, 1>, TexCoord_ReadDirect<u16, 2>,}, + {TexCoord_ReadDirect<s16, 1>, TexCoord_ReadDirect<s16, 2>,}, + {TexCoord_ReadDirect<float, 1>, TexCoord_ReadDirect<float, 2>,}, }, { - {TexCoord_ReadIndex8_UByte1, TexCoord_ReadIndex8_UByte2,}, - {TexCoord_ReadIndex8_Byte1, TexCoord_ReadIndex8_Byte2,}, - {TexCoord_ReadIndex8_UShort1, TexCoord_ReadIndex8_UShort2,}, - {TexCoord_ReadIndex8_Short1, TexCoord_ReadIndex8_Short2,}, - {TexCoord_ReadIndex8_Float1, TexCoord_ReadIndex8_Float2,}, + {TexCoord_ReadIndex<u8, u8, 1>, TexCoord_ReadIndex<u8, u8, 2>,}, + {TexCoord_ReadIndex<u8, s8, 1>, TexCoord_ReadIndex<u8, s8, 2>,}, + {TexCoord_ReadIndex<u8, u16, 1>, TexCoord_ReadIndex<u8, u16, 2>,}, + {TexCoord_ReadIndex<u8, s16, 1>, TexCoord_ReadIndex<u8, s16, 2>,}, + {TexCoord_ReadIndex<u8, float, 1>, TexCoord_ReadIndex<u8, float, 2>,}, }, { - {TexCoord_ReadIndex16_UByte1, TexCoord_ReadIndex16_UByte2,}, - {TexCoord_ReadIndex16_Byte1, TexCoord_ReadIndex16_Byte2,}, - {TexCoord_ReadIndex16_UShort1, TexCoord_ReadIndex16_UShort2,}, - {TexCoord_ReadIndex16_Short1, TexCoord_ReadIndex16_Short2,}, - {TexCoord_ReadIndex16_Float1, TexCoord_ReadIndex16_Float2,}, + {TexCoord_ReadIndex<u16, u8, 1>, TexCoord_ReadIndex<u16, u8, 2>,}, + {TexCoord_ReadIndex<u16, s8, 1>, TexCoord_ReadIndex<u16, s8, 2>,}, + {TexCoord_ReadIndex<u16, u16, 1>, TexCoord_ReadIndex<u16, u16, 2>,}, + {TexCoord_ReadIndex<u16, s16, 1>, TexCoord_ReadIndex<u16, s16, 2>,}, + {TexCoord_ReadIndex<u16, float, 1>, TexCoord_ReadIndex<u16, float, 2>,}, }, }; static int tableReadTexCoordVertexSize[4][8][2] = { { - {0, 0,}, - {0, 0,}, - {0, 0,}, - {0, 0,}, - {0, 0,}, + {0, 0,}, {0, 0,}, {0, 0,}, {0, 0,}, {0, 0,}, }, { - {1, 2,}, - {1, 2,}, - {2, 4,}, - {2, 4,}, - {4, 8,}, + {1, 2,}, {1, 2,}, {2, 4,}, {2, 4,}, {4, 8,}, }, { - {1, 1,}, - {1, 1,}, - {1, 1,}, - {1, 1,}, - {1, 1,}, + {1, 1,}, {1, 1,}, {1, 1,}, {1, 1,}, {1, 1,}, }, { - {2, 2,}, - {2, 2,}, - {2, 2,}, - {2, 2,}, - {2, 2,}, + {2, 2,}, {2, 2,}, {2, 2,}, {2, 2,}, {2, 2,}, }, }; @@ -430,16 +183,20 @@ void VertexLoader_TextCoord::Init(void) { #if _M_SSE >= 0x301 - if (cpu_info.bSSSE3) { - tableReadTexCoord[3][4][1] = TexCoord_ReadIndex16_Float2_SSSE3; + if (cpu_info.bSSSE3) + { + tableReadTexCoord[2][4][1] = TexCoord_ReadIndex_Float2_SSSE3<u8>; + tableReadTexCoord[3][4][1] = TexCoord_ReadIndex_Float2_SSSE3<u16>; } #endif #if _M_SSE >= 0x401 - if (cpu_info.bSSE4_1) { - tableReadTexCoord[3][3][1] = TexCoord_ReadIndex16_Short2_SSE4; + if (cpu_info.bSSE4_1) + { + tableReadTexCoord[2][3][1] = TexCoord_ReadIndex_Short2_SSE4<u8>; + tableReadTexCoord[3][3][1] = TexCoord_ReadIndex_Short2_SSE4<u16>; } #endif diff --git a/Source/Core/VideoCommon/Src/VertexLoader_TextCoord.h b/Source/Core/VideoCommon/Src/VertexLoader_TextCoord.h index f7d5ee7ee7..8e9175d904 100644 --- a/Source/Core/VideoCommon/Src/VertexLoader_TextCoord.h +++ b/Source/Core/VideoCommon/Src/VertexLoader_TextCoord.h @@ -24,18 +24,18 @@ class VertexLoader_TextCoord { public: - // Init - static void Init(void); + // Init + static void Init(void); - // GetSize - static unsigned int GetSize(unsigned int _type, unsigned int _format, unsigned int _elements); + // GetSize + static unsigned int GetSize(unsigned int _type, unsigned int _format, unsigned int _elements); - // GetFunction - static TPipelineFunction GetFunction(unsigned int _type, unsigned int _format, unsigned int _elements); + // GetFunction + static TPipelineFunction GetFunction(unsigned int _type, unsigned int _format, unsigned int _elements); - // GetDummyFunction + // GetDummyFunction // It is important to synchronize tcIndex. - static TPipelineFunction GetDummyFunction(); + static TPipelineFunction GetDummyFunction(); }; #endif diff --git a/Source/Core/VideoCommon/Src/VertexManagerBase.cpp b/Source/Core/VideoCommon/Src/VertexManagerBase.cpp index cd5a01c6b3..87856b5aeb 100644 --- a/Source/Core/VideoCommon/Src/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/Src/VertexManagerBase.cpp @@ -12,171 +12,122 @@ #include "BPStructs.h" #include "VertexManagerBase.h" +#include "MainBase.h" #include "VideoConfig.h" VertexManager *g_vertex_manager; u8 *VertexManager::s_pCurBufferPointer; u8 *VertexManager::s_pBaseBufferPointer; - -u8 *VertexManager::LocalVBuffer; -u16 *VertexManager::TIBuffer; -u16 *VertexManager::LIBuffer; -u16 *VertexManager::PIBuffer; - -bool VertexManager::Flushed; +u8 *VertexManager::s_pEndBufferPointer; VertexManager::VertexManager() { - Flushed = false; + LocalVBuffer.resize(MAXVBUFFERSIZE); + s_pCurBufferPointer = s_pBaseBufferPointer = &LocalVBuffer[0]; + s_pEndBufferPointer = s_pBaseBufferPointer + LocalVBuffer.size(); - LocalVBuffer = new u8[MAXVBUFFERSIZE]; - s_pCurBufferPointer = s_pBaseBufferPointer = LocalVBuffer; + TIBuffer.resize(MAXIBUFFERSIZE); + LIBuffer.resize(MAXIBUFFERSIZE); + PIBuffer.resize(MAXIBUFFERSIZE); - TIBuffer = new u16[MAXIBUFFERSIZE]; - LIBuffer = new u16[MAXIBUFFERSIZE]; - PIBuffer = new u16[MAXIBUFFERSIZE]; - - IndexGenerator::Start(TIBuffer, LIBuffer, PIBuffer); + ResetBuffer(); } +VertexManager::~VertexManager() +{} + void VertexManager::ResetBuffer() { - s_pCurBufferPointer = LocalVBuffer; + s_pCurBufferPointer = s_pBaseBufferPointer; + IndexGenerator::Start(GetTriangleIndexBuffer(), GetLineIndexBuffer(), GetPointIndexBuffer()); } -VertexManager::~VertexManager() +u32 VertexManager::GetRemainingSize() { - delete[] LocalVBuffer; - - delete[] TIBuffer; - delete[] LIBuffer; - delete[] PIBuffer; - - // TODO: necessary?? - ResetBuffer(); + return (u32)(s_pEndBufferPointer - s_pCurBufferPointer); } -void VertexManager::AddIndices(int primitive, int numVertices) -{ - //switch (primitive) - //{ - //case GX_DRAW_QUADS: IndexGenerator::AddQuads(numVertices); break; - //case GX_DRAW_TRIANGLES: IndexGenerator::AddList(numVertices); break; - //case GX_DRAW_TRIANGLE_STRIP: IndexGenerator::AddStrip(numVertices); break; - //case GX_DRAW_TRIANGLE_FAN: IndexGenerator::AddFan(numVertices); break; - //case GX_DRAW_LINES: IndexGenerator::AddLineList(numVertices); break; - //case GX_DRAW_LINE_STRIP: IndexGenerator::AddLineStrip(numVertices); break; - //case GX_DRAW_POINTS: IndexGenerator::AddPoints(numVertices); break; - //} - - static void (*const primitive_table[])(int) = +void VertexManager::PrepareForAdditionalData(int primitive, u32 count, u32 stride) +{ + u32 const needed_vertex_bytes = count * stride; + + if (count > IndexGenerator::GetRemainingIndices() || count > GetRemainingIndices(primitive) || needed_vertex_bytes > GetRemainingSize()) { - IndexGenerator::AddQuads, - NULL, - IndexGenerator::AddList, - IndexGenerator::AddStrip, - IndexGenerator::AddFan, - IndexGenerator::AddLineList, - IndexGenerator::AddLineStrip, - IndexGenerator::AddPoints, - }; - - primitive_table[primitive](numVertices); + Flush(); + + if(count > IndexGenerator::GetRemainingIndices()) + ERROR_LOG(VIDEO, "Too less index values. Use 32bit or reset them on flush."); + if (count > GetRemainingIndices(primitive)) + ERROR_LOG(VIDEO, "VertexManager: Buffer not large enough for all indices! " + "Increase MAXIBUFFERSIZE or we need primitive breaking afterall."); + if (needed_vertex_bytes > GetRemainingSize()) + ERROR_LOG(VIDEO, "VertexManager: Buffer not large enough for all vertices! " + "Increase MAXVBUFFERSIZE or we need primitive breaking afterall."); + } } -int VertexManager::GetRemainingSize() +bool VertexManager::IsFlushed() const { - return MAXVBUFFERSIZE - (int)(s_pCurBufferPointer - LocalVBuffer); + return s_pBaseBufferPointer == s_pCurBufferPointer; } -int VertexManager::GetRemainingVertices(int primitive) +u32 VertexManager::GetRemainingIndices(int primitive) { switch (primitive) { case GX_DRAW_QUADS: + return (MAXIBUFFERSIZE - IndexGenerator::GetTriangleindexLen()) / 6 * 4; case GX_DRAW_TRIANGLES: + return (MAXIBUFFERSIZE - IndexGenerator::GetTriangleindexLen()); case GX_DRAW_TRIANGLE_STRIP: + return (MAXIBUFFERSIZE - IndexGenerator::GetTriangleindexLen()) / 3 + 2; case GX_DRAW_TRIANGLE_FAN: - return (MAXIBUFFERSIZE - IndexGenerator::GetTriangleindexLen()) / 3; - break; + return (MAXIBUFFERSIZE - IndexGenerator::GetTriangleindexLen()) / 3 + 2; case GX_DRAW_LINES: + return (MAXIBUFFERSIZE - IndexGenerator::GetLineindexLen()); case GX_DRAW_LINE_STRIP: - return (MAXIBUFFERSIZE - IndexGenerator::GetLineindexLen()) / 2; - break; + return (MAXIBUFFERSIZE - IndexGenerator::GetLineindexLen()) / 2 + 1; case GX_DRAW_POINTS: return (MAXIBUFFERSIZE - IndexGenerator::GetPointindexLen()); - break; default: return 0; - break; } } -void VertexManager::AddVertices(int primitive, int numVertices) +void VertexManager::AddVertices(int primitive, u32 numVertices) { if (numVertices <= 0) return; - switch (primitive) - { - case GX_DRAW_QUADS: - case GX_DRAW_TRIANGLES: - case GX_DRAW_TRIANGLE_STRIP: - case GX_DRAW_TRIANGLE_FAN: - if (MAXIBUFFERSIZE - IndexGenerator::GetTriangleindexLen() < 3 * numVertices) - Flush(); - break; - - case GX_DRAW_LINES: - case GX_DRAW_LINE_STRIP: - if (MAXIBUFFERSIZE - IndexGenerator::GetLineindexLen() < 2 * numVertices) - Flush(); - break; - - case GX_DRAW_POINTS: - if (MAXIBUFFERSIZE - IndexGenerator::GetPointindexLen() < numVertices) - Flush(); - break; - - default: - return; - break; - } - - if (Flushed) - { - IndexGenerator::Start(TIBuffer, LIBuffer, PIBuffer); - Flushed = false; - } - ADDSTAT(stats.thisFrame.numPrims, numVertices); INCSTAT(stats.thisFrame.numPrimitiveJoins); - AddIndices(primitive, numVertices); + + IndexGenerator::AddIndices(primitive, numVertices); } void VertexManager::Flush() { + if (g_vertex_manager->IsFlushed()) + return; + // loading a state will invalidate BP, so check for it g_video_backend->CheckInvalidState(); - + + VideoFifo_CheckEFBAccess(); + g_vertex_manager->vFlush(); + + g_vertex_manager->ResetBuffer(); } // TODO: need to merge more stuff into VideoCommon to use this #if (0) void VertexManager::Flush() { - if (LocalVBuffer == s_pCurBufferPointer || Flushed) - return; - - Flushed = true; - - VideoFifo_CheckEFBAccess(); - #if defined(_DEBUG) || defined(DEBUGFAST) PRIM_LOG("frame%d:\n texgen=%d, numchan=%d, dualtex=%d, ztex=%d, cole=%d, alpe=%d, ze=%d", g_ActiveConfig.iSaveTargetId, xfregs.numTexGens, xfregs.nNumChans, (int)xfregs.bEnableDualTexTransform, bpmem.ztex2.op, @@ -249,21 +200,23 @@ void VertexManager::Flush() // finally bind if (false == PixelShaderCache::SetShader(false, g_nativeVertexFmt->m_components)) - goto shader_fail; + return; if (false == VertexShaderCache::SetShader(g_nativeVertexFmt->m_components)) - goto shader_fail; + return; const int stride = g_nativeVertexFmt->GetVertexStride(); //if (g_nativeVertexFmt) g_nativeVertexFmt->SetupVertexPointers(); + g_renderer->ResumePixelPerf(false); g_vertex_manager->Draw(stride, false); + g_renderer->PausePixelPerf(false); // run through vertex groups again to set alpha if (false == g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate) { if (false == PixelShaderCache::SetShader(true, g_nativeVertexFmt->m_components)) - goto shader_fail; + return; g_vertex_manager->Draw(stride, true); } @@ -277,10 +230,12 @@ void VertexManager::Flush() // save the shaders char strfile[255]; sprintf(strfile, "%sps%.3d.txt", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_ActiveConfig.iSaveTargetId); - std::ofstream fps(strfile); + std::ofstream fps; + OpenFStream(fps, strfile, std::ios_base::out); fps << ps->strprog.c_str(); sprintf(strfile, "%svs%.3d.txt", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_ActiveConfig.iSaveTargetId); - std::ofstream fvs(strfile); + std::ofstream fvs; + OpenFStream(fvs, strfile, std::ios_base::out); fvs << vs->strprog.c_str(); } @@ -297,9 +252,6 @@ void VertexManager::Flush() } #endif ++g_Config.iSaveTargetId; - -shader_fail: - ResetBuffer(); } #endif @@ -310,12 +262,16 @@ void VertexManager::DoState(PointerWrap& p) void VertexManager::DoStateShared(PointerWrap& p) { - p.DoPointer(s_pCurBufferPointer, LocalVBuffer); - p.DoArray(LocalVBuffer, MAXVBUFFERSIZE); - p.DoArray(TIBuffer, MAXIBUFFERSIZE); - p.DoArray(LIBuffer, MAXIBUFFERSIZE); - p.DoArray(PIBuffer, MAXIBUFFERSIZE); - - if (p.GetMode() == PointerWrap::MODE_READ) - Flushed = false; + // It seems we half-assume to be flushed here + // We update s_pCurBufferPointer yet don't worry about IndexGenerator's outdated pointers + // and maybe other things are overlooked + + p.Do(LocalVBuffer); + p.Do(TIBuffer); + p.Do(LIBuffer); + p.Do(PIBuffer); + + s_pBaseBufferPointer = &LocalVBuffer[0]; + s_pEndBufferPointer = s_pBaseBufferPointer + LocalVBuffer.size(); + p.DoPointer(s_pCurBufferPointer, s_pBaseBufferPointer); } diff --git a/Source/Core/VideoCommon/Src/VertexManagerBase.h b/Source/Core/VideoCommon/Src/VertexManagerBase.h index f3a4aa72e3..fafde8de44 100644 --- a/Source/Core/VideoCommon/Src/VertexManagerBase.h +++ b/Source/Core/VideoCommon/Src/VertexManagerBase.h @@ -2,72 +2,70 @@ #ifndef _VERTEXMANAGERBASE_H #define _VERTEXMANAGERBASE_H +#include "Common.h" +#include <vector> + class NativeVertexFormat; class PointerWrap; class VertexManager { +private: + static const u32 SMALLEST_POSSIBLE_VERTEX = sizeof(float)*3; // 3 pos + static const u32 LARGEST_POSSIBLE_VERTEX = sizeof(float)*45 + sizeof(u32)*2; // 3 pos, 3*3 normal, 2*u32 color, 8*4 tex, 1 posMat + + static const u32 MAX_PRIMITIVES_PER_COMMAND = (u16)-1; + public: - - enum - { - // values from OGL backend - //MAXVBUFFERSIZE = 0x1FFFF, - //MAXIBUFFERSIZE = 0xFFFF, - - // values from DX9 backend - //MAXVBUFFERSIZE = 0x50000, - //MAXIBUFFERSIZE = 0xFFFF, - - // values from DX11 backend - MAXVBUFFERSIZE = 0x50000, - MAXIBUFFERSIZE = 0xFFFF, - }; + static const u32 MAXVBUFFERSIZE = ROUND_UP_POW2 (MAX_PRIMITIVES_PER_COMMAND * LARGEST_POSSIBLE_VERTEX); + + // We may convert triangle-fans to triangle-lists, almost 3x as many indices. + static const u32 MAXIBUFFERSIZE = ROUND_UP_POW2 (MAX_PRIMITIVES_PER_COMMAND * 3); VertexManager(); - virtual ~VertexManager(); // needs to be virtual for DX11's dtor + // needs to be virtual for DX11's dtor + virtual ~VertexManager(); - static void AddVertices(int _primitive, int _numVertices); + static void AddVertices(int _primitive, u32 _numVertices); - // TODO: protected? static u8 *s_pCurBufferPointer; static u8 *s_pBaseBufferPointer; + static u8 *s_pEndBufferPointer; - static int GetRemainingSize(); - static int GetRemainingVertices(int primitive); + static u32 GetRemainingSize(); + static void PrepareForAdditionalData(int primitive, u32 count, u32 stride); + static u32 GetRemainingIndices(int primitive); static void Flush(); virtual ::NativeVertexFormat* CreateNativeVertexFormat() = 0; - static u16* GetTriangleIndexBuffer() { return TIBuffer; } - static u16* GetLineIndexBuffer() { return LIBuffer; } - static u16* GetPointIndexBuffer() { return PIBuffer; } - static u8* GetVertexBuffer() { return LocalVBuffer; } - static void DoState(PointerWrap& p); virtual void CreateDeviceObjects(){}; virtual void DestroyDeviceObjects(){}; + protected: - // TODO: make private after Flush() is merged - static void ResetBuffer(); - - static u8 *LocalVBuffer; - static u16 *TIBuffer; - static u16 *LIBuffer; - static u16 *PIBuffer; - - static bool Flushed; + u16* GetTriangleIndexBuffer() { return &TIBuffer[0]; } + u16* GetLineIndexBuffer() { return &LIBuffer[0]; } + u16* GetPointIndexBuffer() { return &PIBuffer[0]; } + u8* GetVertexBuffer() { return &s_pBaseBufferPointer[0]; } virtual void vDoState(PointerWrap& p) { DoStateShared(p); } void DoStateShared(PointerWrap& p); private: - static void AddIndices(int primitive, int numVertices); + bool IsFlushed() const; + + void ResetBuffer(); + //virtual void Draw(u32 stride, bool alphapass) = 0; // temp virtual void vFlush() = 0; - + + std::vector<u8> LocalVBuffer; + std::vector<u16> TIBuffer; + std::vector<u16> LIBuffer; + std::vector<u16> PIBuffer; }; extern VertexManager *g_vertex_manager; diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp index cad117c2c8..2c0f5676ed 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp @@ -114,7 +114,8 @@ void ValidateVertexShaderIDs(API_TYPE api, VERTEXSHADERUIDSAFE old_id, const std static int num_failures = 0; char szTemp[MAX_PATH]; sprintf(szTemp, "%svsuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); - std::ofstream file(szTemp); + std::ofstream file; + OpenFStream(file, szTemp, std::ios_base::out); file << msg; file << "\n\nOld shader code:\n" << old_code; file << "\n\nNew shader code:\n" << new_code; @@ -130,46 +131,51 @@ static char text[16384]; #define WRITE p+=sprintf -char* GenerateVSOutputStruct(char* p, u32 components, API_TYPE api_type) +char* GenerateVSOutputStruct(char* p, u32 components, API_TYPE ApiType) { + // GLSL makes this ugly + // TODO: Make pretty WRITE(p, "struct VS_OUTPUT {\n"); - WRITE(p, " float4 pos : POSITION;\n"); - WRITE(p, " float4 colors_0 : COLOR0;\n"); - WRITE(p, " float4 colors_1 : COLOR1;\n"); + WRITE(p, " float4 pos %s POSITION;\n", ApiType == API_OPENGL ? ";//" : ":"); + WRITE(p, " float4 colors_0 %s COLOR0;\n", ApiType == API_OPENGL ? ";//" : ":"); + WRITE(p, " float4 colors_1 %s COLOR1;\n", ApiType == API_OPENGL ? ";//" : ":"); if (xfregs.numTexGen.numTexGens < 7) { for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) - WRITE(p, " float3 tex%d : TEXCOORD%d;\n", i, i); - WRITE(p, " float4 clipPos : TEXCOORD%d;\n", xfregs.numTexGen.numTexGens); + WRITE(p, " float3 tex%d %s TEXCOORD%d;\n", i, ApiType == API_OPENGL ? ";//" : ":", i); + WRITE(p, " float4 clipPos %s TEXCOORD%d;\n", ApiType == API_OPENGL ? ";//" : ":", xfregs.numTexGen.numTexGens); if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - WRITE(p, " float4 Normal : TEXCOORD%d;\n", xfregs.numTexGen.numTexGens + 1); + WRITE(p, " float4 Normal %s TEXCOORD%d;\n", ApiType == API_OPENGL ? ";//" : ":", xfregs.numTexGen.numTexGens + 1); } else { // clip position is in w of first 4 texcoords if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) { for (int i = 0; i < 8; ++i) - WRITE(p, " float4 tex%d : TEXCOORD%d;\n", i, i); + WRITE(p, " float4 tex%d %s TEXCOORD%d;\n", i, ApiType == API_OPENGL? ";//" : ":", i); } else { for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) - WRITE(p, " float%d tex%d : TEXCOORD%d;\n", i < 4 ? 4 : 3 , i, i); + WRITE(p, " float%d tex%d %s TEXCOORD%d;\n", i < 4 ? 4 : 3 , i, ApiType == API_OPENGL ? ";//" : ":", i); } - } + } WRITE(p, "};\n"); return p; } -const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) +extern const char* WriteRegister(API_TYPE ApiType, const char *prefix, const u32 num); +extern const char *WriteLocation(API_TYPE ApiType); + +const char *GenerateVertexShaderCode(u32 components, API_TYPE ApiType) { setlocale(LC_NUMERIC, "C"); // Reset locale for compilation text[sizeof(text) - 1] = 0x7C; // canary _assert_(bpmem.genMode.numtexgens == xfregs.numTexGen.numTexGens); _assert_(bpmem.genMode.numcolchans == xfregs.numChan.numColorChans); - - bool is_d3d = (api_type & API_D3D9 || api_type == API_D3D11); + + bool is_d3d = (ApiType & API_D3D9 || ApiType == API_D3D11); u32 lightMask = 0; if (xfregs.numChan.numColorChans > 0) lightMask |= xfregs.color[0].GetFullLightMask() | xfregs.alpha[0].GetFullLightMask(); @@ -178,91 +184,133 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) char *p = text; WRITE(p, "//Vertex Shader: comp:%x, \n", components); - WRITE(p, "typedef struct { float4 T0, T1, T2; float4 N0, N1, N2; } s_" I_POSNORMALMATRIX";\n" - "typedef struct { float4 t; } FLT4;\n" - "typedef struct { FLT4 T[24]; } s_" I_TEXMATRICES";\n" - "typedef struct { FLT4 T[64]; } s_" I_TRANSFORMMATRICES";\n" - "typedef struct { FLT4 T[32]; } s_" I_NORMALMATRICES";\n" - "typedef struct { FLT4 T[64]; } s_" I_POSTTRANSFORMMATRICES";\n" - "typedef struct { float4 col; float4 cosatt; float4 distatt; float4 pos; float4 dir; } Light;\n" - "typedef struct { Light lights[8]; } s_" I_LIGHTS";\n" - "typedef struct { float4 C0, C1, C2, C3; } s_" I_MATERIALS";\n" - "typedef struct { float4 T0, T1, T2, T3; } s_" I_PROJECTION";\n" - ); - - p = GenerateVSOutputStruct(p, components, api_type); // uniforms + if (g_ActiveConfig.backend_info.bSupportsGLSLUBO) + WRITE(p, "layout(std140) uniform VSBlock {\n"); - WRITE(p, "uniform s_" I_TRANSFORMMATRICES" " I_TRANSFORMMATRICES" : register(c%d);\n", C_TRANSFORMMATRICES); - WRITE(p, "uniform s_" I_TEXMATRICES" " I_TEXMATRICES" : register(c%d);\n", C_TEXMATRICES); // also using tex matrices - WRITE(p, "uniform s_" I_NORMALMATRICES" " I_NORMALMATRICES" : register(c%d);\n", C_NORMALMATRICES); - WRITE(p, "uniform s_" I_POSNORMALMATRIX" " I_POSNORMALMATRIX" : register(c%d);\n", C_POSNORMALMATRIX); - WRITE(p, "uniform s_" I_POSTTRANSFORMMATRICES" " I_POSTTRANSFORMMATRICES" : register(c%d);\n", C_POSTTRANSFORMMATRICES); - WRITE(p, "uniform s_" I_LIGHTS" " I_LIGHTS" : register(c%d);\n", C_LIGHTS); - WRITE(p, "uniform s_" I_MATERIALS" " I_MATERIALS" : register(c%d);\n", C_MATERIALS); - WRITE(p, "uniform s_" I_PROJECTION" " I_PROJECTION" : register(c%d);\n", C_PROJECTION); - WRITE(p, "uniform float4 " I_DEPTHPARAMS" : register(c%d);\n", C_DEPTHPARAMS); - - WRITE(p, "VS_OUTPUT main(\n"); - - // inputs - if (components & VB_HAS_NRM0) - WRITE(p, " float3 rawnorm0 : NORMAL0,\n"); - if (components & VB_HAS_NRM1) { - if (is_d3d) - WRITE(p, " float3 rawnorm1 : NORMAL1,\n"); - else - WRITE(p, " float3 rawnorm1 : ATTR%d,\n", SHADER_NORM1_ATTRIB); - } - if (components & VB_HAS_NRM2) { - if (is_d3d) - WRITE(p, " float3 rawnorm2 : NORMAL2,\n"); - else - WRITE(p, " float3 rawnorm2 : ATTR%d,\n", SHADER_NORM2_ATTRIB); - } - if (components & VB_HAS_COL0) - WRITE(p, " float4 color0 : COLOR0,\n"); - if (components & VB_HAS_COL1) - WRITE(p, " float4 color1 : COLOR1,\n"); - for (int i = 0; i < 8; ++i) { - u32 hastexmtx = (components & (VB_HAS_TEXMTXIDX0<<i)); - if ((components & (VB_HAS_UV0<<i)) || hastexmtx) - WRITE(p, " float%d tex%d : TEXCOORD%d,\n", hastexmtx ? 3 : 2, i, i); - } - if (components & VB_HAS_POSMTXIDX) { - if (is_d3d) + WRITE(p, "%sfloat4 " I_POSNORMALMATRIX"[6] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_POSNORMALMATRIX)); + WRITE(p, "%sfloat4 " I_PROJECTION"[4] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_PROJECTION)); + WRITE(p, "%sfloat4 " I_MATERIALS"[4] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_MATERIALS)); + WRITE(p, "%sfloat4 " I_LIGHTS"[40] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_LIGHTS)); + WRITE(p, "%sfloat4 " I_TEXMATRICES"[24] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_TEXMATRICES)); // also using tex matrices + WRITE(p, "%sfloat4 " I_TRANSFORMMATRICES"[64] %s;\n", WriteLocation(ApiType),WriteRegister(ApiType, "c", C_TRANSFORMMATRICES)); + WRITE(p, "%sfloat4 " I_NORMALMATRICES"[32] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_NORMALMATRICES)); + WRITE(p, "%sfloat4 " I_POSTTRANSFORMMATRICES"[64] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_POSTTRANSFORMMATRICES)); + WRITE(p, "%sfloat4 " I_DEPTHPARAMS" %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_DEPTHPARAMS)); + + if (g_ActiveConfig.backend_info.bSupportsGLSLUBO) + WRITE(p, "};\n"); + + p = GenerateVSOutputStruct(p, components, ApiType); + + if(ApiType == API_OPENGL) + { + WRITE(p, "ATTRIN float4 rawpos; // ATTR%d,\n", SHADER_POSITION_ATTRIB); + if (components & VB_HAS_POSMTXIDX) + WRITE(p, "ATTRIN int posmtx; // ATTR%d,\n", SHADER_POSMTX_ATTRIB); + if (components & VB_HAS_NRM0) + WRITE(p, "ATTRIN float3 rawnorm0; // ATTR%d,\n", SHADER_NORM0_ATTRIB); + if (components & VB_HAS_NRM1) + WRITE(p, "ATTRIN float3 rawnorm1; // ATTR%d,\n", SHADER_NORM1_ATTRIB); + if (components & VB_HAS_NRM2) + WRITE(p, "ATTRIN float3 rawnorm2; // ATTR%d,\n", SHADER_NORM2_ATTRIB); + + if (components & VB_HAS_COL0) + WRITE(p, "ATTRIN float4 color0; // ATTR%d,\n", SHADER_COLOR0_ATTRIB); + if (components & VB_HAS_COL1) + WRITE(p, "ATTRIN float4 color1; // ATTR%d,\n", SHADER_COLOR1_ATTRIB); + + for (int i = 0; i < 8; ++i) { + u32 hastexmtx = (components & (VB_HAS_TEXMTXIDX0<<i)); + if ((components & (VB_HAS_UV0<<i)) || hastexmtx) + WRITE(p, "ATTRIN float%d tex%d; // ATTR%d,\n", hastexmtx ? 3 : 2, i, SHADER_TEXTURE0_ATTRIB + i); + } + + // Let's set up attributes + if (xfregs.numTexGen.numTexGens < 7) { - WRITE(p, " float4 blend_indices : BLENDINDICES,\n"); + for (int i = 0; i < 8; ++i) + WRITE(p, "VARYOUT float3 uv%d_2;\n", i); + WRITE(p, "VARYOUT float4 clipPos_2;\n"); + if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + WRITE(p, "VARYOUT float4 Normal_2;\n"); } else - WRITE(p, " float fposmtx : ATTR%d,\n", SHADER_POSMTX_ATTRIB); + { + // wpos is in w of first 4 texcoords + if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + { + for (int i = 0; i < 8; ++i) + WRITE(p, "VARYOUT float4 uv%d_2;\n", i); + } + else + { + for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) + WRITE(p, "VARYOUT float%d uv%d_2;\n", i < 4 ? 4 : 3 , i); + } + } + WRITE(p, "VARYOUT float4 colors_02;\n"); + WRITE(p, "VARYOUT float4 colors_12;\n"); + + WRITE(p, "void main()\n{\n"); + } + else + { + WRITE(p, "VS_OUTPUT main(\n"); + + // inputs + if (components & VB_HAS_NRM0) + WRITE(p, " float3 rawnorm0 : NORMAL0,\n"); + if (components & VB_HAS_NRM1) { + if (is_d3d) + WRITE(p, " float3 rawnorm1 : NORMAL1,\n"); + else + WRITE(p, " float3 rawnorm1 : ATTR%d,\n", SHADER_NORM1_ATTRIB); + } + if (components & VB_HAS_NRM2) { + if (is_d3d) + WRITE(p, " float3 rawnorm2 : NORMAL2,\n"); + else + WRITE(p, " float3 rawnorm2 : ATTR%d,\n", SHADER_NORM2_ATTRIB); + } + if (components & VB_HAS_COL0) + WRITE(p, " float4 color0 : COLOR0,\n"); + if (components & VB_HAS_COL1) + WRITE(p, " float4 color1 : COLOR1,\n"); + for (int i = 0; i < 8; ++i) { + u32 hastexmtx = (components & (VB_HAS_TEXMTXIDX0<<i)); + if ((components & (VB_HAS_UV0<<i)) || hastexmtx) + WRITE(p, " float%d tex%d : TEXCOORD%d,\n", hastexmtx ? 3 : 2, i, i); + } + if (components & VB_HAS_POSMTXIDX) { + if (is_d3d) + WRITE(p, " float4 blend_indices : BLENDINDICES,\n"); + else + WRITE(p, " float fposmtx : ATTR%d,\n", SHADER_POSMTX_ATTRIB); + } + WRITE(p, " float4 rawpos : POSITION) {\n"); } - WRITE(p, " float4 rawpos : POSITION) {\n"); WRITE(p, "VS_OUTPUT o;\n"); // transforms if (components & VB_HAS_POSMTXIDX) { - if (api_type & API_D3D9) + if (ApiType & API_D3D9) { WRITE(p, "int4 indices = D3DCOLORtoUBYTE4(blend_indices);\n"); WRITE(p, "int posmtx = indices.x;\n"); } - else if (api_type == API_D3D11) + else if (ApiType == API_D3D11) { WRITE(p, "int posmtx = blend_indices.x * 255.0f;\n"); } - else - { - WRITE(p, "int posmtx = fposmtx;\n"); - } - WRITE(p, "float4 pos = float4(dot(" I_TRANSFORMMATRICES".T[posmtx].t, rawpos), dot(" I_TRANSFORMMATRICES".T[posmtx+1].t, rawpos), dot(" I_TRANSFORMMATRICES".T[posmtx+2].t, rawpos), 1);\n"); + WRITE(p, "float4 pos = float4(dot(" I_TRANSFORMMATRICES"[posmtx], rawpos), dot(" I_TRANSFORMMATRICES"[posmtx+1], rawpos), dot(" I_TRANSFORMMATRICES"[posmtx+2], rawpos), 1);\n"); if (components & VB_HAS_NRMALL) { WRITE(p, "int normidx = posmtx >= 32 ? (posmtx-32) : posmtx;\n"); - WRITE(p, "float3 N0 = " I_NORMALMATRICES".T[normidx].t.xyz, N1 = " I_NORMALMATRICES".T[normidx+1].t.xyz, N2 = " I_NORMALMATRICES".T[normidx+2].t.xyz;\n"); + WRITE(p, "float3 N0 = " I_NORMALMATRICES"[normidx].xyz, N1 = " I_NORMALMATRICES"[normidx+1].xyz, N2 = " I_NORMALMATRICES"[normidx+2].xyz;\n"); } if (components & VB_HAS_NRM0) @@ -274,27 +322,25 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) } else { - WRITE(p, "float4 pos = float4(dot(" I_POSNORMALMATRIX".T0, rawpos), dot(" I_POSNORMALMATRIX".T1, rawpos), dot(" I_POSNORMALMATRIX".T2, rawpos), 1.0f);\n"); + WRITE(p, "float4 pos = float4(dot(" I_POSNORMALMATRIX"[0], rawpos), dot(" I_POSNORMALMATRIX"[1], rawpos), dot(" I_POSNORMALMATRIX"[2], rawpos), 1.0f);\n"); if (components & VB_HAS_NRM0) - WRITE(p, "float3 _norm0 = normalize(float3(dot(" I_POSNORMALMATRIX".N0.xyz, rawnorm0), dot(" I_POSNORMALMATRIX".N1.xyz, rawnorm0), dot(" I_POSNORMALMATRIX".N2.xyz, rawnorm0)));\n"); + WRITE(p, "float3 _norm0 = normalize(float3(dot(" I_POSNORMALMATRIX"[3].xyz, rawnorm0), dot(" I_POSNORMALMATRIX"[4].xyz, rawnorm0), dot(" I_POSNORMALMATRIX"[5].xyz, rawnorm0)));\n"); if (components & VB_HAS_NRM1) - WRITE(p, "float3 _norm1 = float3(dot(" I_POSNORMALMATRIX".N0.xyz, rawnorm1), dot(" I_POSNORMALMATRIX".N1.xyz, rawnorm1), dot(" I_POSNORMALMATRIX".N2.xyz, rawnorm1));\n"); + WRITE(p, "float3 _norm1 = float3(dot(" I_POSNORMALMATRIX"[3].xyz, rawnorm1), dot(" I_POSNORMALMATRIX"[4].xyz, rawnorm1), dot(" I_POSNORMALMATRIX"[5].xyz, rawnorm1));\n"); if (components & VB_HAS_NRM2) - WRITE(p, "float3 _norm2 = float3(dot(" I_POSNORMALMATRIX".N0.xyz, rawnorm2), dot(" I_POSNORMALMATRIX".N1.xyz, rawnorm2), dot(" I_POSNORMALMATRIX".N2.xyz, rawnorm2));\n"); + WRITE(p, "float3 _norm2 = float3(dot(" I_POSNORMALMATRIX"[3].xyz, rawnorm2), dot(" I_POSNORMALMATRIX"[4].xyz, rawnorm2), dot(" I_POSNORMALMATRIX"[5].xyz, rawnorm2));\n"); } if (!(components & VB_HAS_NRM0)) WRITE(p, "float3 _norm0 = float3(0.0f, 0.0f, 0.0f);\n"); - - - WRITE(p, "o.pos = float4(dot(" I_PROJECTION".T0, pos), dot(" I_PROJECTION".T1, pos), dot(" I_PROJECTION".T2, pos), dot(" I_PROJECTION".T3, pos));\n"); + WRITE(p, "o.pos = float4(dot(" I_PROJECTION"[0], pos), dot(" I_PROJECTION"[1], pos), dot(" I_PROJECTION"[2], pos), dot(" I_PROJECTION"[3], pos));\n"); WRITE(p, "float4 mat, lacc;\n" "float3 ldir, h;\n" "float dist, dist2, attn;\n"); - if(xfregs.numChan.numColorChans == 0) + if (xfregs.numChan.numColorChans == 0) { if (components & VB_HAS_COL0) WRITE(p, "o.colors_0 = color0;\n"); @@ -305,7 +351,7 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) // TODO: This probably isn't necessary if pixel lighting is enabled. p = GenerateLightingShader(p, components, I_MATERIALS, I_LIGHTS, "color", "o.colors_"); - if(xfregs.numChan.numColorChans < 2) + if (xfregs.numChan.numColorChans < 2) { if (components & VB_HAS_COL1) WRITE(p, "o.colors_1 = color1;\n"); @@ -367,7 +413,7 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) if (components & (VB_HAS_NRM1|VB_HAS_NRM2)) { // transform the light dir into tangent space - WRITE(p, "ldir = normalize(" I_LIGHTS".lights[%d].pos.xyz - pos.xyz);\n", texinfo.embosslightshift); + WRITE(p, "ldir = normalize(" I_LIGHTS"[%d + 3].xyz - pos.xyz);\n", texinfo.embosslightshift); WRITE(p, "o.tex%d.xyz = o.tex%d.xyz + float3(dot(ldir, _norm1), dot(ldir, _norm2), 0.0f);\n", i, texinfo.embosssourceshift); } else @@ -387,18 +433,20 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) break; case XF_TEXGEN_REGULAR: default: - if (components & (VB_HAS_TEXMTXIDX0<<i)) { + if (components & (VB_HAS_TEXMTXIDX0<<i)) + { + WRITE(p, "int tmp = int(tex%d.z);\n", i); if (texinfo.projection == XF_TEXPROJ_STQ) - WRITE(p, "o.tex%d.xyz = float3(dot(coord, " I_TRANSFORMMATRICES".T[tex%d.z].t), dot(coord, " I_TRANSFORMMATRICES".T[tex%d.z+1].t), dot(coord, " I_TRANSFORMMATRICES".T[tex%d.z+2].t));\n", i, i, i, i); + WRITE(p, "o.tex%d.xyz = float3(dot(coord, " I_TRANSFORMMATRICES"[tmp]), dot(coord, " I_TRANSFORMMATRICES"[tmp+1]), dot(coord, " I_TRANSFORMMATRICES"[tmp+2]));\n", i); else { - WRITE(p, "o.tex%d.xyz = float3(dot(coord, " I_TRANSFORMMATRICES".T[tex%d.z].t), dot(coord, " I_TRANSFORMMATRICES".T[tex%d.z+1].t), 1);\n", i, i, i); + WRITE(p, "o.tex%d.xyz = float3(dot(coord, " I_TRANSFORMMATRICES"[tmp]), dot(coord, " I_TRANSFORMMATRICES"[tmp+1]), 1);\n", i); } } else { if (texinfo.projection == XF_TEXPROJ_STQ) - WRITE(p, "o.tex%d.xyz = float3(dot(coord, " I_TEXMATRICES".T[%d].t), dot(coord, " I_TEXMATRICES".T[%d].t), dot(coord, " I_TEXMATRICES".T[%d].t));\n", i, 3*i, 3*i+1, 3*i+2); + WRITE(p, "o.tex%d.xyz = float3(dot(coord, " I_TEXMATRICES"[%d]), dot(coord, " I_TEXMATRICES"[%d]), dot(coord, " I_TEXMATRICES"[%d]));\n", i, 3*i, 3*i+1, 3*i+2); else - WRITE(p, "o.tex%d.xyz = float3(dot(coord, " I_TEXMATRICES".T[%d].t), dot(coord, " I_TEXMATRICES".T[%d].t), 1);\n", i, 3*i, 3*i+1); + WRITE(p, "o.tex%d.xyz = float3(dot(coord, " I_TEXMATRICES"[%d]), dot(coord, " I_TEXMATRICES"[%d]), 1);\n", i, 3*i, 3*i+1); } break; } @@ -407,9 +455,9 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) const PostMtxInfo& postInfo = xfregs.postMtxInfo[i]; int postidx = postInfo.index; - WRITE(p, "float4 P0 = " I_POSTTRANSFORMMATRICES".T[%d].t;\n" - "float4 P1 = " I_POSTTRANSFORMMATRICES".T[%d].t;\n" - "float4 P2 = " I_POSTTRANSFORMMATRICES".T[%d].t;\n", + WRITE(p, "float4 P0 = " I_POSTTRANSFORMMATRICES"[%d];\n" + "float4 P1 = " I_POSTTRANSFORMMATRICES"[%d];\n" + "float4 P2 = " I_POSTTRANSFORMMATRICES"[%d];\n", postidx&0x3f, (postidx+1)&0x3f, (postidx+2)&0x3f); if (texGenSpecialCase) { @@ -455,9 +503,9 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) WRITE(p, "o.tex7 = pos.xyzz;\n"); else WRITE(p, "o.tex7.w = pos.z;\n"); - } + } if (components & VB_HAS_COL0) - WRITE(p, "o.colors_0 = color0;\n"); + WRITE(p, "o.colors_0 = color0;\n"); if (components & VB_HAS_COL1) WRITE(p, "o.colors_1 = color1;\n"); @@ -465,44 +513,77 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) //write the true depth value, if the game uses depth textures pixel shaders will override with the correct values //if not early z culling will improve speed - // TODO: Can probably be dropped? if (is_d3d) { WRITE(p, "o.pos.z = " I_DEPTHPARAMS".x * o.pos.w + o.pos.z * " I_DEPTHPARAMS".y;\n"); } else { - // this results in a scale from -1..0 to -1..1 after perspective - // divide - WRITE(p, "o.pos.z = o.pos.w + o.pos.z * 2.0f;\n"); - - // Sonic Unleashed puts its final rendering at the near or - // far plane of the viewing frustrum(actually box, they use - // orthogonal projection for that), and we end up putting it - // just beyond, and the rendering gets clipped away. (The - // primitive gets dropped) - WRITE(p, "o.pos.z = o.pos.z * 1048575.0f/1048576.0f;\n"); - - // the next steps of the OGL pipeline are: - // (x_c,y_c,z_c,w_c) = o.pos //switch to OGL spec terminology - // clipping to -w_c <= (x_c,y_c,z_c) <= w_c - // (x_d,y_d,z_d) = (x_c,y_c,z_c)/w_c//perspective divide - // z_w = (f-n)/2*z_d + (n+f)/2 - // z_w now contains the value to go to the 0..1 depth buffer - - //trying to get the correct semantic while not using glDepthRange - //seems to get rather complicated + // this results in a scale from -1..0 to -1..1 after perspective + // divide + WRITE(p, "o.pos.z = o.pos.w + o.pos.z * 2.0f;\n"); + + // Sonic Unleashed puts its final rendering at the near or + // far plane of the viewing frustrum(actually box, they use + // orthogonal projection for that), and we end up putting it + // just beyond, and the rendering gets clipped away. (The + // primitive gets dropped) + WRITE(p, "o.pos.z = o.pos.z * 1048575.0f/1048576.0f;\n"); + + // the next steps of the OGL pipeline are: + // (x_c,y_c,z_c,w_c) = o.pos //switch to OGL spec terminology + // clipping to -w_c <= (x_c,y_c,z_c) <= w_c + // (x_d,y_d,z_d) = (x_c,y_c,z_c)/w_c//perspective divide + // z_w = (f-n)/2*z_d + (n+f)/2 + // z_w now contains the value to go to the 0..1 depth buffer + + //trying to get the correct semantic while not using glDepthRange + //seems to get rather complicated } - if (api_type & API_D3D9) + if (ApiType & API_D3D9) { // D3D9 is addressing pixel centers instead of pixel boundaries in clip space. // Thus we need to offset the final position by half a pixel WRITE(p, "o.pos = o.pos + float4(" I_DEPTHPARAMS".z, " I_DEPTHPARAMS".w, 0.f, 0.f);\n"); } - WRITE(p, "return o;\n}\n"); + if(ApiType == API_OPENGL) + { + // Bit ugly here + // TODO: Make pretty + // Will look better when we bind uniforms in GLSL 1.3 + // clipPos/w needs to be done in pixel shader, not here + if (xfregs.numTexGen.numTexGens < 7) { + for (unsigned int i = 0; i < 8; ++i) + if(i < xfregs.numTexGen.numTexGens) + WRITE(p, " uv%d_2.xyz = o.tex%d;\n", i, i); + else + WRITE(p, " uv%d_2.xyz = float3(0.0f, 0.0f, 0.0f);\n", i); + WRITE(p, " clipPos_2 = o.clipPos;\n"); + if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + WRITE(p, " Normal_2 = o.Normal;\n"); + } else { + // clip position is in w of first 4 texcoords + if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + { + for (int i = 0; i < 8; ++i) + WRITE(p, " uv%d_2 = o.tex%d;\n", i, i); + } + else + { + for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) + WRITE(p, " uv%d_2%s = o.tex%d;\n", i, i < 4 ? ".xyzw" : ".xyz" , i); + } + } + WRITE(p, "colors_02 = o.colors_0;\n"); + WRITE(p, "colors_12 = o.colors_1;\n"); + WRITE(p, "gl_Position = o.pos;\n"); + WRITE(p, "}\n"); + } + else + WRITE(p, "return o;\n}\n"); if (text[sizeof(text) - 1] != 0x7C) PanicAlert("VertexShader generator - buffer too small, canary has been eaten!"); diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.h b/Source/Core/VideoCommon/Src/VertexShaderGen.h index cb253a9b6c..4d7ab68e11 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.h +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.h @@ -21,9 +21,24 @@ #include "XFMemory.h" #include "VideoCommon.h" -#define SHADER_POSMTX_ATTRIB 1 -#define SHADER_NORM1_ATTRIB 6 -#define SHADER_NORM2_ATTRIB 7 +// TODO should be reordered +#define SHADER_POSITION_ATTRIB 0 +#define SHADER_POSMTX_ATTRIB 1 +#define SHADER_NORM0_ATTRIB 2 +#define SHADER_NORM1_ATTRIB 3 +#define SHADER_NORM2_ATTRIB 4 +#define SHADER_COLOR0_ATTRIB 5 +#define SHADER_COLOR1_ATTRIB 6 + +#define SHADER_TEXTURE0_ATTRIB 8 +#define SHADER_TEXTURE1_ATTRIB 9 +#define SHADER_TEXTURE2_ATTRIB 10 +#define SHADER_TEXTURE3_ATTRIB 11 +#define SHADER_TEXTURE4_ATTRIB 12 +#define SHADER_TEXTURE5_ATTRIB 13 +#define SHADER_TEXTURE6_ATTRIB 14 +#define SHADER_TEXTURE7_ATTRIB 15 + // shader variables @@ -46,8 +61,17 @@ #define C_NORMALMATRICES (C_TRANSFORMMATRICES + 64) #define C_POSTTRANSFORMMATRICES (C_NORMALMATRICES + 32) #define C_DEPTHPARAMS (C_POSTTRANSFORMMATRICES + 64) -#define C_VENVCONST_END (C_DEPTHPARAMS + 4) - +#define C_VENVCONST_END (C_DEPTHPARAMS + 1) +const s_svar VSVar_Loc[] = { {I_POSNORMALMATRIX, C_POSNORMALMATRIX, 6 }, + {I_PROJECTION , C_PROJECTION, 4 }, + {I_MATERIALS, C_MATERIALS, 4 }, + {I_LIGHTS, C_LIGHTS, 40 }, + {I_TEXMATRICES, C_TEXMATRICES, 24 }, + {I_TRANSFORMMATRICES , C_TRANSFORMMATRICES, 64 }, + {I_NORMALMATRICES , C_NORMALMATRICES, 32 }, + {I_POSTTRANSFORMMATRICES, C_POSTTRANSFORMMATRICES, 64 }, + {I_DEPTHPARAMS, C_DEPTHPARAMS, 1 }, + }; template<bool safe> class _VERTEXSHADERUID { diff --git a/Source/Core/VideoCommon/Src/VertexShaderManager.cpp b/Source/Core/VideoCommon/Src/VertexShaderManager.cpp index 1dce567b0d..a5e84ee69b 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderManager.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderManager.cpp @@ -102,7 +102,7 @@ float PHackValue(std::string sValue) c[i] = (cStr[i] == ',') ? '.' : *(cStr+i); if (c[i] == '.') fp = true; - } + } cStr = c; sTof.str(cStr); sTof >> f; @@ -119,22 +119,22 @@ void UpdateProjectionHack(int iPhackvalue[], std::string sPhackvalue[]) float fhacksign1 = 1.0, fhacksign2 = 1.0; bool bProjHack3 = false; const char *sTemp[2]; - + if (iPhackvalue[0] == 1) { NOTICE_LOG(VIDEO, "\t\t--- Ortographic Projection Hack ON ---"); - + fhacksign1 *= (iPhackvalue[1] == 1) ? -1.0f : fhacksign1; sTemp[0] = (iPhackvalue[1] == 1) ? " * (-1)" : ""; fhacksign2 *= (iPhackvalue[2] == 1) ? -1.0f : fhacksign2; sTemp[1] = (iPhackvalue[2] == 1) ? " * (-1)" : ""; - + fhackvalue1 = PHackValue(sPhackvalue[0]); NOTICE_LOG(VIDEO, "- zNear Correction = (%f + zNear)%s", fhackvalue1, sTemp[0]); fhackvalue2 = PHackValue(sPhackvalue[1]); NOTICE_LOG(VIDEO, "- zFar Correction = (%f + zFar)%s", fhackvalue2, sTemp[1]); - + sTemp[0] = "DISABLED"; bProjHack3 = (iPhackvalue[3] == 1) ? true : bProjHack3; if (bProjHack3) @@ -171,22 +171,22 @@ void VertexShaderManager::Dirty() { nTransformMatricesChanged[0] = 0; nTransformMatricesChanged[1] = 256; - + nNormalMatricesChanged[0] = 0; nNormalMatricesChanged[1] = 96; - + nPostTransformMatricesChanged[0] = 0; nPostTransformMatricesChanged[1] = 256; - + nLightsChanged[0] = 0; nLightsChanged[1] = 0x80; - + bPosNormalMatrixChanged = true; bTexMatricesChanged[0] = true; bTexMatricesChanged[1] = true; - + bProjectionChanged = true; - + nMaterialsChanged = 15; } @@ -194,6 +194,8 @@ void VertexShaderManager::Dirty() // TODO: A cleaner way to control the matricies without making a mess in the parameters field void VertexShaderManager::SetConstants() { + if (g_ActiveConfig.backend_info.APIType == API_OPENGL && !g_ActiveConfig.backend_info.bSupportsGLSLUBO) + Dirty(); if (nTransformMatricesChanged[0] >= 0) { int startn = nTransformMatricesChanged[0] / 4; @@ -356,7 +358,7 @@ void VertexShaderManager::SetConstants() switch(xfregs.projection.type) { case GX_PERSPECTIVE: - + g_fProjectionMatrix[0] = rawProjection[0] * g_ActiveConfig.fAspectRatioHackW; g_fProjectionMatrix[1] = 0.0f; g_fProjectionMatrix[2] = rawProjection[1]; @@ -372,7 +374,7 @@ void VertexShaderManager::SetConstants() g_fProjectionMatrix[10] = rawProjection[4]; g_fProjectionMatrix[11] = rawProjection[5]; - + g_fProjectionMatrix[12] = 0.0f; g_fProjectionMatrix[13] = 0.0f; // donkopunchstania: GC GPU rounds differently? @@ -397,9 +399,9 @@ void VertexShaderManager::SetConstants() SETSTAT_FT(stats.gproj_14, g_fProjectionMatrix[14]); SETSTAT_FT(stats.gproj_15, g_fProjectionMatrix[15]); break; - + case GX_ORTHOGRAPHIC: - + g_fProjectionMatrix[0] = rawProjection[0]; g_fProjectionMatrix[1] = 0.0f; g_fProjectionMatrix[2] = 0.0f; @@ -424,10 +426,10 @@ void VertexShaderManager::SetConstants() this hack was added...setting g_fProjectionMatrix[14] to -1 might make the hack more stable, needs more testing. Only works for OGL and DX9...this is not helping DX11 */ - + g_fProjectionMatrix[14] = 0.0f; g_fProjectionMatrix[15] = (g_ProjHack3 && rawProjection[0] == 2.0f ? 0.0f : 1.0f); //causes either the efb copy or bloom layer not to show if proj hack enabled - + SETSTAT_FT(stats.g2proj_0, g_fProjectionMatrix[0]); SETSTAT_FT(stats.g2proj_1, g_fProjectionMatrix[1]); SETSTAT_FT(stats.g2proj_2, g_fProjectionMatrix[2]); @@ -451,7 +453,7 @@ void VertexShaderManager::SetConstants() SETSTAT_FT(stats.proj_4, rawProjection[4]); SETSTAT_FT(stats.proj_5, rawProjection[5]); break; - + default: ERROR_LOG(VIDEO, "unknown projection type: %d", xfregs.projection.type); } diff --git a/Source/Core/VideoCommon/Src/VertexShaderManager.h b/Source/Core/VideoCommon/Src/VertexShaderManager.h index 86f77ee3da..a0c89f1e60 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderManager.h +++ b/Source/Core/VideoCommon/Src/VertexShaderManager.h @@ -43,7 +43,7 @@ public: static void Dirty(); static void Shutdown(); static void DoState(PointerWrap &p); -; + // constant management static void SetConstants(); diff --git a/Source/Core/VideoCommon/Src/VideoCommon.h b/Source/Core/VideoCommon/Src/VideoCommon.h index 1eeed20b82..bf83235591 100644 --- a/Source/Core/VideoCommon/Src/VideoCommon.h +++ b/Source/Core/VideoCommon/Src/VideoCommon.h @@ -90,8 +90,8 @@ struct TargetRectangle : public MathUtil::Rectangle<int> #define PRIM_LOG(...) DEBUG_LOG(VIDEO, ##__VA_ARGS__) #endif - -// #define LOG_VTX() DEBUG_LOG(VIDEO, "vtx: %f %f %f, ", ((float*)VertexManager::s_pCurBufferPointer)[0], ((float*)VertexManager::s_pCurBufferPointer)[1], ((float*)VertexManager::s_pCurBufferPointer)[2]); +// warning: mapping buffer should be disabled to use this +// #define LOG_VTX() DEBUG_LOG(VIDEO, "vtx: %f %f %f, ", ((float*)VertexManager::s_pCurBufferPointer)[-3], ((float*)VertexManager::s_pCurBufferPointer)[-2], ((float*)VertexManager::s_pCurBufferPointer)[-1]); #define LOG_VTX() @@ -102,8 +102,7 @@ typedef enum API_D3D9_SM20 = 4, API_D3D9 = 6, API_D3D11 = 8, - API_GLSL = 16, - API_NONE = 32 + API_NONE = 16 } API_TYPE; inline u32 RGBA8ToRGBA6ToRGBA8(u32 src) @@ -149,5 +148,11 @@ inline unsigned int GetPow2(unsigned int val) ++ret; return ret; } +struct s_svar +{ + const char *name; + const unsigned int reg; + const unsigned int size; +}; #endif // _VIDEOCOMMON_H diff --git a/Source/Core/VideoCommon/Src/VideoConfig.cpp b/Source/Core/VideoCommon/Src/VideoConfig.cpp index a76514a10c..60677ceeeb 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.cpp +++ b/Source/Core/VideoCommon/Src/VideoConfig.cpp @@ -22,6 +22,7 @@ #include "VideoConfig.h" #include "VideoCommon.h" #include "FileUtil.h" +#include "Core.h" VideoConfig g_Config; VideoConfig g_ActiveConfig; @@ -51,7 +52,7 @@ void VideoConfig::Load(const char *ini_file) std::string temp; IniFile iniFile; iniFile.Load(ini_file); - + iniFile.Get("Hardware", "VSync", &bVSync, 0); // Hardware iniFile.Get("Settings", "wideScreenHack", &bWidescreenHack, false); iniFile.Get("Settings", "AspectRatio", &iAspectRatio, (int)ASPECT_AUTO); @@ -76,17 +77,18 @@ void VideoConfig::Load(const char *ini_file) iniFile.Get("Settings", "AnaglyphStereoSeparation", &iAnaglyphStereoSeparation, 200); iniFile.Get("Settings", "AnaglyphFocalAngle", &iAnaglyphFocalAngle, 0); iniFile.Get("Settings", "EnablePixelLighting", &bEnablePixelLighting, 0); - + iniFile.Get("Settings", "HackedBufferUpload", &bHackedBufferUpload, 0); + iniFile.Get("Settings", "MSAA", &iMultisampleMode, 0); iniFile.Get("Settings", "EFBScale", &iEFBScale, 2); // native - + iniFile.Get("Settings", "DstAlphaPass", &bDstAlphaPass, false); - + iniFile.Get("Settings", "TexFmtOverlayEnable", &bTexFmtOverlayEnable, 0); iniFile.Get("Settings", "TexFmtOverlayCenter", &bTexFmtOverlayCenter, 0); iniFile.Get("Settings", "WireFrame", &bWireFrame, 0); iniFile.Get("Settings", "DisableFog", &bDisableFog, 0); - + iniFile.Get("Settings", "EnableOpenCL", &bEnableOpenCL, false); iniFile.Get("Settings", "OMPDecoder", &bOMPDecoder, false); @@ -96,7 +98,7 @@ void VideoConfig::Load(const char *ini_file) iniFile.Get("Enhancements", "MaxAnisotropy", &iMaxAnisotropy, 0); // NOTE - this is x in (1 << x) iniFile.Get("Enhancements", "PostProcessingShader", &sPostProcessingShader, ""); iniFile.Get("Enhancements", "Enable3dVision", &b3DVision, false); - + iniFile.Get("Hacks", "EFBAccessEnable", &bEFBAccessEnable, true); iniFile.Get("Hacks", "DlistCachingEnable", &bDlistCachingEnable,false); iniFile.Get("Hacks", "EFBCopyEnable", &bEFBCopyEnable, true); @@ -134,6 +136,7 @@ void VideoConfig::GameIniLoad(const char *ini_file) iniFile.GetIfExists("Video_Settings", "AnaglyphStereoSeparation", &iAnaglyphStereoSeparation); iniFile.GetIfExists("Video_Settings", "AnaglyphFocalAngle", &iAnaglyphFocalAngle); iniFile.GetIfExists("Video_Settings", "EnablePixelLighting", &bEnablePixelLighting); + iniFile.GetIfExists("Video_Settings", "HackedBufferUpload", &bHackedBufferUpload); iniFile.GetIfExists("Video_Settings", "MSAA", &iMultisampleMode); iniFile.GetIfExists("Video_Settings", "EFBScale", &iEFBScale); // integral iniFile.GetIfExists("Video_Settings", "DstAlphaPass", &bDstAlphaPass); @@ -172,6 +175,7 @@ void VideoConfig::VerifyValidity() if (!backend_info.bSupports3DVision) b3DVision = false; if (!backend_info.bSupportsFormatReinterpretation) bEFBEmulateFormatChanges = false; if (!backend_info.bSupportsPixelLighting) bEnablePixelLighting = false; + if (backend_info.APIType != API_OPENGL) backend_info.bSupportsGLSLUBO = false; } void VideoConfig::Save(const char *ini_file) @@ -202,7 +206,7 @@ void VideoConfig::Save(const char *ini_file) iniFile.Set("Settings", "AnaglyphStereoSeparation", iAnaglyphStereoSeparation); iniFile.Set("Settings", "AnaglyphFocalAngle", iAnaglyphFocalAngle); iniFile.Set("Settings", "EnablePixelLighting", bEnablePixelLighting); - + iniFile.Set("Settings", "HackedBufferUpload", bHackedBufferUpload); iniFile.Set("Settings", "ShowEFBCopyRegions", bShowEFBCopyRegions); iniFile.Set("Settings", "MSAA", iMultisampleMode); @@ -215,14 +219,14 @@ void VideoConfig::Save(const char *ini_file) iniFile.Set("Settings", "EnableOpenCL", bEnableOpenCL); iniFile.Set("Settings", "OMPDecoder", bOMPDecoder); - + iniFile.Set("Settings", "EnableShaderDebugging", bEnableShaderDebugging); iniFile.Set("Enhancements", "ForceFiltering", bForceFiltering); iniFile.Set("Enhancements", "MaxAnisotropy", iMaxAnisotropy); iniFile.Set("Enhancements", "PostProcessingShader", sPostProcessingShader); iniFile.Set("Enhancements", "Enable3dVision", b3DVision); - + iniFile.Set("Hacks", "EFBAccessEnable", bEFBAccessEnable); iniFile.Set("Hacks", "DlistCachingEnable", bDlistCachingEnable); iniFile.Set("Hacks", "EFBCopyEnable", bEFBCopyEnable); @@ -233,7 +237,7 @@ void VideoConfig::Save(const char *ini_file) iniFile.Set("Hacks", "EFBEmulateFormatChanges", bEFBEmulateFormatChanges); iniFile.Set("Hardware", "Adapter", iAdapter); - + iniFile.Save(ini_file); } @@ -289,3 +293,8 @@ void VideoConfig::GameIniSave(const char* default_ini, const char* game_ini) iniFile.Save(game_ini); } + +bool VideoConfig::IsVSync() +{ + return Core::isTabPressed ? false : bVSync; +} diff --git a/Source/Core/VideoCommon/Src/VideoConfig.h b/Source/Core/VideoCommon/Src/VideoConfig.h index 183fcf784c..442e95f9bf 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.h +++ b/Source/Core/VideoCommon/Src/VideoConfig.h @@ -37,17 +37,6 @@ #define CONF_SAVETARGETS 8 #define CONF_SAVESHADERS 16 -enum MultisampleMode { - MULTISAMPLE_OFF, - MULTISAMPLE_2X, - MULTISAMPLE_4X, - MULTISAMPLE_8X, - MULTISAMPLE_CSAA_8X, - MULTISAMPLE_CSAA_8XQ, - MULTISAMPLE_CSAA_16X, - MULTISAMPLE_CSAA_16XQ, -}; - enum AspectMode { ASPECT_AUTO = 0, ASPECT_FORCE_16_9 = 1, @@ -67,6 +56,7 @@ struct VideoConfig void Save(const char *ini_file); void GameIniSave(const char* default_ini, const char* game_ini); void UpdateProjectionHack(); + bool IsVSync(); // General bool bVSync; @@ -98,12 +88,12 @@ struct VideoConfig bool bTexFmtOverlayCenter; bool bShowEFBCopyRegions; bool bLogFPSToFile; - + // Render bool bWireFrame; bool bDstAlphaPass; bool bDisableFog; - + // Utility bool bDumpTextures; bool bHiresTextures; @@ -115,7 +105,7 @@ struct VideoConfig int iAnaglyphStereoSeparation; int iAnaglyphFocalAngle; bool b3DVision; - + // Hacks bool bEFBAccessEnable; bool bDlistCachingEnable; @@ -133,6 +123,7 @@ struct VideoConfig bool bZTPSpeedHack; // The Legend of Zelda: Twilight Princess bool bUseBBox; bool bEnablePixelLighting; + bool bHackedBufferUpload; int iLog; // CONF_ bits int iSaveTargetId; // TODO: Should be dropped @@ -162,13 +153,15 @@ struct VideoConfig bool bSupportsDualSourceBlend; // only supported by D3D11 and OpenGL bool bSupportsFormatReinterpretation; bool bSupportsPixelLighting; + + bool bSupportsGLSLUBO; // needed by pixelShaderGen, so must stay in videoCommon } backend_info; - // Utility - bool RealXFBEnabled() const { return bUseXFB && bUseRealXFB; } - bool VirtualXFBEnabled() const { return bUseXFB && !bUseRealXFB; } - bool EFBCopiesToTextureEnabled() const { return bEFBCopyEnable && bCopyEFBToTexture; } - bool EFBCopiesToRamEnabled() const { return bEFBCopyEnable && !bCopyEFBToTexture; } + // Utility + bool RealXFBEnabled() const { return bUseXFB && bUseRealXFB; } + bool VirtualXFBEnabled() const { return bUseXFB && !bUseRealXFB; } + bool EFBCopiesToTextureEnabled() const { return bEFBCopyEnable && bCopyEFBToTexture; } + bool EFBCopiesToRamEnabled() const { return bEFBCopyEnable && !bCopyEFBToTexture; } }; extern VideoConfig g_Config; diff --git a/Source/Core/VideoCommon/Src/VideoState.cpp b/Source/Core/VideoCommon/Src/VideoState.cpp index ad5384cda9..0d99d0378f 100644 --- a/Source/Core/VideoCommon/Src/VideoState.cpp +++ b/Source/Core/VideoCommon/Src/VideoState.cpp @@ -30,33 +30,33 @@ static void DoState(PointerWrap &p) { - // BP Memory - p.Do(bpmem); + // BP Memory + p.Do(bpmem); p.DoMarker("BP Memory"); // CP Memory - p.DoArray(arraybases, 16); - p.DoArray(arraystrides, 16); - p.Do(MatrixIndexA); - p.Do(MatrixIndexB); - p.Do(g_VtxDesc.Hex); + p.DoArray(arraybases, 16); + p.DoArray(arraystrides, 16); + p.Do(MatrixIndexA); + p.Do(MatrixIndexB); + p.Do(g_VtxDesc.Hex); p.DoArray(g_VtxAttr, 8); p.DoMarker("CP Memory"); - // XF Memory - p.Do(xfregs); - p.DoArray(xfmem, XFMEM_SIZE); + // XF Memory + p.Do(xfregs); + p.DoArray(xfmem, XFMEM_SIZE); p.DoMarker("XF Memory"); // Texture decoder - p.DoArray(texMem, TMEM_SIZE); + p.DoArray(texMem, TMEM_SIZE); p.DoMarker("texMem"); - // FIFO - Fifo_DoState(p); + // FIFO + Fifo_DoState(p); p.DoMarker("Fifo"); - CommandProcessor::DoState(p); + CommandProcessor::DoState(p); p.DoMarker("CommandProcessor"); PixelEngine::DoState(p); @@ -77,7 +77,7 @@ static void DoState(PointerWrap &p) void VideoCommon_DoState(PointerWrap &p) { - DoState(p); + DoState(p); } void VideoCommon_RunLoop(bool enable) diff --git a/Source/Core/VideoCommon/Src/XFMemory.h b/Source/Core/VideoCommon/Src/XFMemory.h index fc199b8c32..2ef3e41eb5 100644 --- a/Source/Core/VideoCommon/Src/XFMemory.h +++ b/Source/Core/VideoCommon/Src/XFMemory.h @@ -110,70 +110,70 @@ union LitChannel { - struct - { - u32 matsource : 1; - u32 enablelighting : 1; - u32 lightMask0_3 : 4; - u32 ambsource : 1; - u32 diffusefunc : 2; // LIGHTDIF_X - u32 attnfunc : 2; // LIGHTATTN_X - u32 lightMask4_7 : 4; - }; - struct - { - u32 hex : 15; - u32 unused : 17; - }; - struct - { - u32 dummy0 : 7; - u32 lightparams : 4; - u32 dummy1 : 21; - }; - unsigned int GetFullLightMask() const - { - return enablelighting ? (lightMask0_3 | (lightMask4_7 << 4)) : 0; - } + struct + { + u32 matsource : 1; + u32 enablelighting : 1; + u32 lightMask0_3 : 4; + u32 ambsource : 1; + u32 diffusefunc : 2; // LIGHTDIF_X + u32 attnfunc : 2; // LIGHTATTN_X + u32 lightMask4_7 : 4; + }; + struct + { + u32 hex : 15; + u32 unused : 17; + }; + struct + { + u32 dummy0 : 7; + u32 lightparams : 4; + u32 dummy1 : 21; + }; + unsigned int GetFullLightMask() const + { + return enablelighting ? (lightMask0_3 | (lightMask4_7 << 4)) : 0; + } }; union INVTXSPEC { - struct - { - u32 numcolors : 2; - u32 numnormals : 2; // 0 - nothing, 1 - just normal, 2 - normals and binormals - u32 numtextures : 4; - u32 unused : 24; - }; - u32 hex; + struct + { + u32 numcolors : 2; + u32 numnormals : 2; // 0 - nothing, 1 - just normal, 2 - normals and binormals + u32 numtextures : 4; + u32 unused : 24; + }; + u32 hex; }; union TexMtxInfo { - struct - { - u32 unknown : 1; - u32 projection : 1; // XF_TEXPROJ_X - u32 inputform : 2; // XF_TEXINPUT_X - u32 texgentype : 3; // XF_TEXGEN_X - u32 sourcerow : 5; // XF_SRCGEOM_X - u32 embosssourceshift : 3; // what generated texcoord to use - u32 embosslightshift : 3; // light index that is used - }; - u32 hex; + struct + { + u32 unknown : 1; + u32 projection : 1; // XF_TEXPROJ_X + u32 inputform : 2; // XF_TEXINPUT_X + u32 texgentype : 3; // XF_TEXGEN_X + u32 sourcerow : 5; // XF_SRCGEOM_X + u32 embosssourceshift : 3; // what generated texcoord to use + u32 embosslightshift : 3; // light index that is used + }; + u32 hex; }; union PostMtxInfo { - struct - { - u32 index : 6; // base row of dual transform matrix - u32 unused : 2; - u32 normalize : 1; // normalize before send operation - }; - u32 hex; + struct + { + u32 index : 6; // base row of dual transform matrix + u32 unused : 2; + u32 normalize : 1; // normalize before send operation + }; + u32 hex; }; union NumColorChannel @@ -207,25 +207,25 @@ union DualTexInfo struct Light { - u32 useless[3]; - u32 color; //rgba - float a0; //attenuation - float a1; - float a2; - float k0; //k stuff - float k1; - float k2; - union - { - struct { + u32 useless[3]; + u32 color; //rgba + float a0; //attenuation + float a1; + float a2; + float k0; //k stuff + float k1; + float k2; + union + { + struct { float dpos[3]; - float ddir[3]; // specular lights only - }; - struct { - float sdir[3]; - float shalfangle[3]; // specular lights only - }; - }; + float ddir[3]; // specular lights only + }; + struct { + float sdir[3]; + float shalfangle[3]; // specular lights only + }; + }; }; struct Viewport @@ -246,35 +246,35 @@ struct Projection struct XFRegisters { - u32 error; // 0x1000 - u32 diag; // 0x1001 - u32 state0; // 0x1002 - u32 state1; // 0x1003 - u32 xfClock; // 0x1004 - u32 clipDisable; // 0x1005 - u32 perf0; // 0x1006 - u32 perf1; // 0x1007 - INVTXSPEC hostinfo; // 0x1008 number of textures,colors,normals from vertex input - NumColorChannel numChan; // 0x1009 - u32 ambColor[2]; // 0x100a, 0x100b - u32 matColor[2]; // 0x100c, 0x100d - LitChannel color[2]; // 0x100e, 0x100f - LitChannel alpha[2]; // 0x1010, 0x1011 - DualTexInfo dualTexTrans; // 0x1012 - u32 unk3; // 0x1013 - u32 unk4; // 0x1014 - u32 unk5; // 0x1015 - u32 unk6; // 0x1016 - u32 unk7; // 0x1017 - u32 MatrixIndexA; // 0x1018 - u32 MatrixIndexB; // 0x1019 - Viewport viewport; // 0x101a - 0x101f - Projection projection; // 0x1020 - 0x1026 - u32 unk8[24]; // 0x1027 - 0x103e - NumTexGen numTexGen; // 0x103f - TexMtxInfo texMtxInfo[8]; // 0x1040 - 0x1047 - u32 unk9[8]; // 0x1048 - 0x104f - PostMtxInfo postMtxInfo[8]; // 0x1050 - 0x1057 + u32 error; // 0x1000 + u32 diag; // 0x1001 + u32 state0; // 0x1002 + u32 state1; // 0x1003 + u32 xfClock; // 0x1004 + u32 clipDisable; // 0x1005 + u32 perf0; // 0x1006 + u32 perf1; // 0x1007 + INVTXSPEC hostinfo; // 0x1008 number of textures,colors,normals from vertex input + NumColorChannel numChan; // 0x1009 + u32 ambColor[2]; // 0x100a, 0x100b + u32 matColor[2]; // 0x100c, 0x100d + LitChannel color[2]; // 0x100e, 0x100f + LitChannel alpha[2]; // 0x1010, 0x1011 + DualTexInfo dualTexTrans; // 0x1012 + u32 unk3; // 0x1013 + u32 unk4; // 0x1014 + u32 unk5; // 0x1015 + u32 unk6; // 0x1016 + u32 unk7; // 0x1017 + u32 MatrixIndexA; // 0x1018 + u32 MatrixIndexB; // 0x1019 + Viewport viewport; // 0x101a - 0x101f + Projection projection; // 0x1020 - 0x1026 + u32 unk8[24]; // 0x1027 - 0x103e + NumTexGen numTexGen; // 0x103f + TexMtxInfo texMtxInfo[8]; // 0x1040 - 0x1047 + u32 unk9[8]; // 0x1048 - 0x104f + PostMtxInfo postMtxInfo[8]; // 0x1050 - 0x1057 }; diff --git a/Source/Core/VideoCommon/Src/XFStructs.cpp b/Source/Core/VideoCommon/Src/XFStructs.cpp index 9f395bfecf..df9624b6f0 100644 --- a/Source/Core/VideoCommon/Src/XFStructs.cpp +++ b/Source/Core/VideoCommon/Src/XFStructs.cpp @@ -36,37 +36,37 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData) u32 address = baseAddress; u32 dataIndex = 0; - while (transferSize > 0 && address < 0x1058) - { - u32 newValue = pData[dataIndex]; + while (transferSize > 0 && address < 0x1058) + { + u32 newValue = pData[dataIndex]; u32 nextAddress = address + 1; - switch (address) - { - case XFMEM_ERROR: - case XFMEM_DIAG: - case XFMEM_STATE0: // internal state 0 - case XFMEM_STATE1: // internal state 1 - case XFMEM_CLOCK: + switch (address) + { + case XFMEM_ERROR: + case XFMEM_DIAG: + case XFMEM_STATE0: // internal state 0 + case XFMEM_STATE1: // internal state 1 + case XFMEM_CLOCK: case XFMEM_SETGPMETRIC: nextAddress = 0x1007; - break; + break; - case XFMEM_CLIPDISABLE: + case XFMEM_CLIPDISABLE: //if (data & 1) {} // disable clipping detection //if (data & 2) {} // disable trivial rejection //if (data & 4) {} // disable cpoly clipping acceleration - break; + break; - case XFMEM_VTXSPECS: //__GXXfVtxSpecs, wrote 0004 - break; + case XFMEM_VTXSPECS: //__GXXfVtxSpecs, wrote 0004 + break; - case XFMEM_SETNUMCHAN: + case XFMEM_SETNUMCHAN: if (xfregs.numChan.numColorChans != (newValue & 3)) - VertexManager::Flush(); - break; + VertexManager::Flush(); + break; - case XFMEM_SETCHAN0_AMBCOLOR: // Channel Ambient Color + case XFMEM_SETCHAN0_AMBCOLOR: // Channel Ambient Color case XFMEM_SETCHAN1_AMBCOLOR: { u8 chan = address - XFMEM_SETCHAN0_AMBCOLOR; @@ -75,11 +75,11 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData) VertexManager::Flush(); VertexShaderManager::SetMaterialColorChanged(chan); PixelShaderManager::SetMaterialColorChanged(chan); - } + } break; } - case XFMEM_SETCHAN0_MATCOLOR: // Channel Material Color + case XFMEM_SETCHAN0_MATCOLOR: // Channel Material Color case XFMEM_SETCHAN1_MATCOLOR: { u8 chan = address - XFMEM_SETCHAN0_MATCOLOR; @@ -92,28 +92,28 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData) break; } - case XFMEM_SETCHAN0_COLOR: // Channel Color + case XFMEM_SETCHAN0_COLOR: // Channel Color case XFMEM_SETCHAN1_COLOR: case XFMEM_SETCHAN0_ALPHA: // Channel Alpha - case XFMEM_SETCHAN1_ALPHA: + case XFMEM_SETCHAN1_ALPHA: if (((u32*)&xfregs)[address - 0x1000] != (newValue & 0x7fff)) - VertexManager::Flush(); + VertexManager::Flush(); break; - case XFMEM_DUALTEX: + case XFMEM_DUALTEX: if (xfregs.dualTexTrans.enabled != (newValue & 1)) - VertexManager::Flush(); - break; + VertexManager::Flush(); + break; - case XFMEM_SETMATRIXINDA: - //_assert_msg_(GX_XF, 0, "XF matrixindex0"); + case XFMEM_SETMATRIXINDA: + //_assert_msg_(GX_XF, 0, "XF matrixindex0"); VertexShaderManager::SetTexMatrixChangedA(newValue); - break; - case XFMEM_SETMATRIXINDB: - //_assert_msg_(GX_XF, 0, "XF matrixindex1"); - VertexShaderManager::SetTexMatrixChangedB(newValue); - break; + break; + case XFMEM_SETMATRIXINDB: + //_assert_msg_(GX_XF, 0, "XF matrixindex1"); + VertexShaderManager::SetTexMatrixChangedB(newValue); + break; case XFMEM_SETVIEWPORT: case XFMEM_SETVIEWPORT+1: @@ -135,16 +135,16 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData) case XFMEM_SETPROJECTION+4: case XFMEM_SETPROJECTION+5: case XFMEM_SETPROJECTION+6: - VertexManager::Flush(); + VertexManager::Flush(); VertexShaderManager::SetProjectionChanged(); nextAddress = XFMEM_SETPROJECTION + 7; break; - case XFMEM_SETNUMTEXGENS: // GXSetNumTexGens + case XFMEM_SETNUMTEXGENS: // GXSetNumTexGens if (xfregs.numTexGen.numTexGens != (newValue & 15)) VertexManager::Flush(); - break; + break; case XFMEM_SETTEXMTXINFO: case XFMEM_SETTEXMTXINFO+1: @@ -178,47 +178,47 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData) // Maybe these are for Normals? case 0x1048: //xfregs.texcoords[0].nrmmtxinfo.hex = data; break; ?? - case 0x1049: - case 0x104a: - case 0x104b: - case 0x104c: - case 0x104d: - case 0x104e: - case 0x104f: + case 0x1049: + case 0x104a: + case 0x104b: + case 0x104c: + case 0x104d: + case 0x104e: + case 0x104f: DEBUG_LOG(VIDEO, "Possible Normal Mtx XF reg?: %x=%x\n", address, newValue); break; case 0x1013: - case 0x1014: - case 0x1015: - case 0x1016: - case 0x1017: + case 0x1014: + case 0x1015: + case 0x1016: + case 0x1017: - default: - WARN_LOG(VIDEO, "Unknown XF Reg: %x=%x\n", address, newValue); - break; - } + default: + WARN_LOG(VIDEO, "Unknown XF Reg: %x=%x\n", address, newValue); + break; + } int transferred = nextAddress - address; address = nextAddress; transferSize -= transferred; dataIndex += transferred; - } + } } void LoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData) { - // do not allow writes past registers - if (baseAddress + transferSize > 0x1058) - { - INFO_LOG(VIDEO, "xf load exceeds address space: %x %d bytes\n", baseAddress, transferSize); + // do not allow writes past registers + if (baseAddress + transferSize > 0x1058) + { + INFO_LOG(VIDEO, "xf load exceeds address space: %x %d bytes\n", baseAddress, transferSize); - if (baseAddress >= 0x1058) - transferSize = 0; - else - transferSize = 0x1058 - baseAddress; - } + if (baseAddress >= 0x1058) + transferSize = 0; + else + transferSize = 0x1058 - baseAddress; + } // write to XF mem if (baseAddress < 0x1000 && transferSize > 0) @@ -247,11 +247,11 @@ void LoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData) } // write to XF regs - if (transferSize > 0) + if (transferSize > 0) { XFRegWritten(transferSize, baseAddress, pData); memcpy_gc((u32*)(&xfregs) + (baseAddress - 0x1000), pData, transferSize * 4); - } + } } // TODO - verify that it is correct. Seems to work, though. diff --git a/Source/Core/VideoCommon/Src/memcpy_amd.cpp b/Source/Core/VideoCommon/Src/memcpy_amd.cpp index 4bc3012e81..bd393560d4 100644 --- a/Source/Core/VideoCommon/Src/memcpy_amd.cpp +++ b/Source/Core/VideoCommon/Src/memcpy_amd.cpp @@ -465,8 +465,8 @@ End: void * memcpy_amd(void *dest, const void *src, size_t n) { -memcpy(dest, src, n); -return dest; + memcpy(dest, src, n); + return dest; } diff --git a/Source/Core/VideoCommon/Src/DLCache.cpp b/Source/Core/VideoCommon/Src/x64DLCache.cpp index c828ea3a03..3e03271993 100644 --- a/Source/Core/VideoCommon/Src/DLCache.cpp +++ b/Source/Core/VideoCommon/Src/x64DLCache.cpp @@ -35,7 +35,7 @@ #include "VertexLoaderManager.h" #include "VertexManagerBase.h" #include "x64Emitter.h" -#include "ABI.h" +#include "x64ABI.h" #include "DLCache.h" #include "VideoConfig.h" @@ -111,17 +111,17 @@ struct CachedDisplayList u32 num_cp_reg; u32 num_bp_reg; u32 num_index_xf; - u32 num_draw_call; + u32 num_draw_call; u32 pass; u32 check; - int frame_count; + int frame_count; u32 BufferCount; void InsertRegion(ReferencedDataRegion* NewRegion) { if(LastRegion) { - LastRegion->NextRegion = NewRegion; + LastRegion->NextRegion = NewRegion; } LastRegion = NewRegion; if(!Regions) @@ -174,7 +174,7 @@ struct CachedDisplayList Current = Current->NextRegion; } return true; - } + } ReferencedDataRegion* FindOverlapingRegion(u8* RegionStart, u32 Regionsize) { @@ -182,7 +182,7 @@ struct CachedDisplayList while(Current) { if(!Current->IntersectsMemoryRange(RegionStart, Regionsize)) - return Current; + return Current; Current = Current->NextRegion; } return Current; @@ -330,7 +330,7 @@ u32 AnalyzeAndRunDisplayList(u32 address, u32 size, CachedDisplayList *dl) u32 addr = DataReadU32(); u32 count = DataReadU32(); ExecuteDisplayList(addr, count); - } + } break; case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that DEBUG_LOG(VIDEO, "GX 0x44: %08x", cmd_byte); @@ -392,7 +392,7 @@ u32 AnalyzeAndRunDisplayList(u32 address, u32 size, CachedDisplayList *dl) dl->num_draw_call = num_draw_call; dl->num_index_xf = num_index_xf; dl->num_xf_reg = num_xf_reg; - // reset to the old pointer + // reset to the old pointer g_pVideoData = old_pVideoData; return result; } @@ -458,7 +458,7 @@ void CompileAndRunDisplayList(u32 address, u32 size, CachedDisplayList *dl) NewRegion->MustClean = true; NewRegion->size = transfer_size * 4; NewRegion->start_address = (u8*) new u8[NewRegion->size+15+12]; // alignment and guaranteed space - NewRegion->hash = 0; + NewRegion->hash = 0; dl->InsertRegion(NewRegion); u32 *data_buffer = (u32*)(u8*)(((size_t)NewRegion->start_address+0xf)&~0xf); DataReadU32xFuncs[transfer_size-1](data_buffer); @@ -539,7 +539,6 @@ void CompileAndRunDisplayList(u32 address, u32 size, CachedDisplayList *dl) if (cmd_byte & 0x80) { // load vertices (use computed vertex size from FifoCommandRunnable above) - u16 numVertices = DataReadU16(); if(numVertices > 0) { @@ -550,8 +549,7 @@ void CompileAndRunDisplayList(u32 address, u32 size, CachedDisplayList *dl) cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7) (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, numVertices); - u8* EndAddress = VertexManager::s_pCurBufferPointer; - u32 Vdatasize = (u32)(EndAddress - StartAddress); + u32 Vdatasize = (u32)(VertexManager::s_pCurBufferPointer - StartAddress); if (Vdatasize > 0) { // Compile @@ -559,7 +557,7 @@ void CompileAndRunDisplayList(u32 address, u32 size, CachedDisplayList *dl) NewRegion->MustClean = true; NewRegion->size = Vdatasize; NewRegion->start_address = (u8*)new u8[Vdatasize]; - NewRegion->hash = 0; + NewRegion->hash = 0; dl->InsertRegion(NewRegion); memcpy(NewRegion->start_address, StartAddress, Vdatasize); emitter.ABI_CallFunctionCCCP((void *)&VertexLoaderManager::RunCompiledVertices, cmd_byte & GX_VAT_MASK, (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, numVertices, NewRegion->start_address); @@ -578,7 +576,6 @@ void CompileAndRunDisplayList(u32 address, u32 size, CachedDisplayList *dl) } } } - } else { @@ -627,7 +624,7 @@ void Clear() } dl_map.clear(); // Reset the cache pointers. - emitter.SetCodePtr(dlcode_cache); + emitter.SetCodePtr(dlcode_cache); } void ProgressiveCleanup() @@ -685,14 +682,14 @@ bool HandleDisplayList(u32 address, u32 size) { vhash = DLCache::CreateVMapId(Parentiter->second.VATUsed); iter = Parentiter->second.dl_map.find(vhash); - childexist = iter != Parentiter->second.dl_map.end(); + childexist = iter != Parentiter->second.dl_map.end(); } if (Parentiter != DLCache::dl_map.end() && childexist) { DLCache::CachedDisplayList &dl = iter->second; if (dl.uncachable) { - return false; + return false; } switch (dl.pass) @@ -701,7 +698,7 @@ bool HandleDisplayList(u32 address, u32 size) // First, check that the hash is the same as the last time. if (dl.dl_hash != GetHash64(Memory::GetPointer(address), size, 0)) { - dl.uncachable = true; + dl.uncachable = true; return false; } DLCache::CompileAndRunDisplayList(address, size, &dl); @@ -718,7 +715,7 @@ bool HandleDisplayList(u32 address, u32 size) if (DlistChanged) { dl.uncachable = true; - dl.ClearRegions(); + dl.ClearRegions(); return false; } dl.frame_count= frameCount; @@ -765,10 +762,9 @@ bool HandleDisplayList(u32 address, u32 size) vdl.VATUsed = dlvatused; vdl.count = 1; DLCache::dl_map[dl_id] = vdl; - } + return true; - } void IncrementCheckContextId() diff --git a/Source/Core/VideoCommon/Src/TextureDecoder.cpp b/Source/Core/VideoCommon/Src/x64TextureDecoder.cpp index 30df817902..f5612f34a4 100644 --- a/Source/Core/VideoCommon/Src/TextureDecoder.cpp +++ b/Source/Core/VideoCommon/Src/x64TextureDecoder.cpp @@ -517,7 +517,7 @@ inline void decodebytesARGB8_4ToRgba(u32 *dst, const u16 *src, const u16 * src2) { #if 0 for (int x = 0; x < 4; x++) { - dst[x] = ((src[x] & 0xFF) << 24) | ((src[x] & 0xFF00)>>8) | (src2[x] << 8); + dst[x] = ((src[x] & 0xFF) << 24) | ((src[x] & 0xFF00)>>8) | (src2[x] << 8); } #else dst[0] = ((src[0] & 0xFF) << 24) | ((src[0] & 0xFF00)>>8) | (src2[0] << 8); @@ -556,7 +556,7 @@ void decodeDXTBlock(u32 *dst, const DXTBlock *src, int pitch) { int blue3 = ((blue2 - blue1) >> 1) - ((blue2 - blue1) >> 3); int green3 = ((green2 - green1) >> 1) - ((green2 - green1) >> 3); - int red3 = ((red2 - red1) >> 1) - ((red2 - red1) >> 3); + int red3 = ((red2 - red1) >> 1) - ((red2 - red1) >> 3); colors[2] = makecol(red1 + red3, green1 + green3, blue1 + blue3, 255); colors[3] = makecol(red2 - red3, green2 - green3, blue2 - blue3, 255); } @@ -1119,20 +1119,6 @@ PC_TexFormat TexDecoder_Decode_RGBA(u32 * dst, const u8 * src, int width, int he _mm_storeu_si128( (__m128i*)( dst+(y + iy+1) * width + x + 4 ), o4 ); } } -#if 0 - // Reference C implementation: - for (int y = 0; y < height; y += 8) - for (int x = 0; x < width; x += 8) - for (int iy = 0; iy < 8; iy++, src += 4) - for (int ix = 0; ix < 4; ix++) - { - int val = src[ix]; - u8 i1 = Convert4To8(val >> 4); - u8 i2 = Convert4To8(val & 0xF); - memset(dst+(y + iy) * width + x + ix * 2 , i1,4); - memset(dst+(y + iy) * width + x + ix * 2 + 1 , i2,4); - } -#endif } break; case GX_TF_I8: // speed critical @@ -1248,26 +1234,6 @@ PC_TexFormat TexDecoder_Decode_RGBA(u32 * dst, const u8 * src, int width, int he } } -#if 0 - // Reference C implementation - for (int y = 0; y < height; y += 4) - for (int x = 0; x < width; x += 8) - for (int iy = 0; iy < 4; ++iy, src += 8) - { - u32 * newdst = dst + (y + iy)*width+x; - const u8 * newsrc = src; - u8 srcval; - - srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); - srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); - srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); - srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); - srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); - srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); - srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); - srcval = newsrc[0]; newdst[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); - } -#endif } break; case GX_TF_C8: @@ -1380,20 +1346,6 @@ PC_TexFormat TexDecoder_Decode_RGBA(u32 * dst, const u8 * src, int width, int he _mm_storeu_si128( (__m128i*)(dst + (y + iy) * width + x), r1 ); } } -#if 0 - // Reference C implementation: - for (int y = 0; y < height; y += 4) - for (int x = 0; x < width; x += 4) - for (int iy = 0; iy < 4; iy++, src += 8) - { - u32 *ptr = dst + (y + iy) * width + x; - u16 *s = (u16 *)src; - ptr[0] = decodeIA8Swapped(s[0]); - ptr[1] = decodeIA8Swapped(s[1]); - ptr[2] = decodeIA8Swapped(s[2]); - ptr[3] = decodeIA8Swapped(s[3]); - } -#endif } break; case GX_TF_C14X2: @@ -1493,18 +1445,6 @@ PC_TexFormat TexDecoder_Decode_RGBA(u32 * dst, const u8 * src, int width, int he __m128i *ptr = (__m128i *)(dst + (y + iy) * width + x); _mm_storeu_si128(ptr, abgr888x4); } -#if 0 - // Reference C implementation. - for (int y = 0; y < height; y += 4) - for (int x = 0; x < width; x += 4) - for (int iy = 0; iy < 4; iy++, src += 8) - { - u32 *ptr = dst + (y + iy) * width + x; - u16 *s = (u16 *)src; - for(int j = 0; j < 4; j++) - *ptr++ = decode565RGBA(Common::swap16(*s++)); - } -#endif } break; case GX_TF_RGB5A3: @@ -1718,13 +1658,6 @@ PC_TexFormat TexDecoder_Decode_RGBA(u32 * dst, const u8 * src, int width, int he } } } -#if 0 - // Reference C implementation: - for (int y = 0; y < height; y += 4) - for (int x = 0; x < width; x += 4) - for (int iy = 0; iy < 4; iy++, src += 8) - decodebytesRGB5A3rgba(dst+(y+iy)*width+x, (u16*)src); -#endif } break; case GX_TF_RGBA8: // speed critical @@ -1860,16 +1793,6 @@ PC_TexFormat TexDecoder_Decode_RGBA(u32 * dst, const u8 * src, int width, int he _mm_storeu_si128(dst128, rgba11); } } -#if 0 - // Reference C implementation. - for (int y = 0; y < height; y += 4) - for (int x = 0; x < width; x += 4) - { - for (int iy = 0; iy < 4; iy++) - decodebytesARGB8_4ToRgba(dst + (y+iy)*width + x, (u16*)src + 4 * iy, (u16*)src + 4 * iy + 16); - src += 64; - } -#endif } break; case GX_TF_CMPR: // speed critical @@ -2104,22 +2027,6 @@ PC_TexFormat TexDecoder_Decode_RGBA(u32 * dst, const u8 * src, int width, int he } } } -#if 0 - for (int y = 0; y < height; y += 8) - { - for (int x = 0; x < width; x += 8) - { - decodeDXTBlockRGBA((u32*)dst + y * width + x, (DXTBlock*)src, width); - src += sizeof(DXTBlock); - decodeDXTBlockRGBA((u32*)dst + y * width + x + 4, (DXTBlock*)src, width); - src += sizeof(DXTBlock); - decodeDXTBlockRGBA((u32*)dst + (y + 4) * width + x, (DXTBlock*)src, width); - src += sizeof(DXTBlock); - decodeDXTBlockRGBA((u32*)dst + (y + 4) * width + x + 4, (DXTBlock*)src, width); - src += sizeof(DXTBlock); - } - } -#endif break; } } @@ -2233,7 +2140,7 @@ void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth u32 base = (tBlk * widthBlks + sBlk) * blockWidth * blockHeight; u16 blkS = s & (blockWidth - 1); u16 blkT = t & (blockHeight - 1); - u32 blkOff = blkT * blockWidth + blkS; + u32 blkOff = blkT * blockWidth + blkS; */ switch (texformat) @@ -2247,9 +2154,9 @@ void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth u16 blkS = s & 7; u16 blkT = t & 7; u32 blkOff = (blkT << 3) + blkS; - + int rs = (blkOff & 1)?0:4; - u32 offset = base + (blkOff >> 1); + u32 offset = base + (blkOff >> 1); u8 val = (*(src + offset) >> rs) & 0xF; u16 *tlut = (u16*)(texMem + tlutaddr); @@ -2259,7 +2166,7 @@ void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth case 0: *((u32*)dst) = decodeIA8Swapped(tlut[val]); break; - case 1: + case 1: *((u32*)dst) = decode565RGBA(Common::swap16(tlut[val])); break; case 2: @@ -2277,9 +2184,9 @@ void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth u16 blkS = s & 7; u16 blkT = t & 7; u32 blkOff = (blkT << 3) + blkS; - + int rs = (blkOff & 1)?0:4; - u32 offset = base + (blkOff >> 1); + u32 offset = base + (blkOff >> 1); u8 val = (*(src + offset) >> rs) & 0xF; val = Convert4To8(val); @@ -2298,7 +2205,7 @@ void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth u16 blkS = s & 7; u16 blkT = t & 3; u32 blkOff = (blkT << 3) + blkS; - + u8 val = *(src + base + blkOff); dst[0] = val; dst[1] = val; @@ -2315,7 +2222,7 @@ void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth u16 blkS = s & 7; u16 blkT = t & 3; u32 blkOff = (blkT << 3) + blkS; - + u8 val = *(src + base + blkOff); u16 *tlut = (u16*)(texMem + tlutaddr); @@ -2324,7 +2231,7 @@ void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth case 0: *((u32*)dst) = decodeIA8Swapped(tlut[val]); break; - case 1: + case 1: *((u32*)dst) = decode565RGBA(Common::swap16(tlut[val])); break; case 2: @@ -2342,7 +2249,7 @@ void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth u16 blkS = s & 7; u16 blkT = t & 3; u32 blkOff = (blkT << 3) + blkS; - + u8 val = *(src + base + blkOff); const u8 a = Convert4To8(val>>4); const u8 l = Convert4To8(val&0xF); @@ -2361,7 +2268,7 @@ void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth u16 blkS = s & 3; u16 blkT = t & 3; u32 blkOff = (blkT << 2) + blkS; - + u32 offset = (base + blkOff) << 1; const u16* valAddr = (u16*)(src + offset); @@ -2377,7 +2284,7 @@ void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth u16 blkS = s & 3; u16 blkT = t & 3; u32 blkOff = (blkT << 2) + blkS; - + u32 offset = (base + blkOff) << 1; const u16* valAddr = (u16*)(src + offset); @@ -2389,7 +2296,7 @@ void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth case 0: *((u32*)dst) = decodeIA8Swapped(tlut[val]); break; - case 1: + case 1: *((u32*)dst) = decode565RGBA(Common::swap16(tlut[val])); break; case 2: @@ -2407,7 +2314,7 @@ void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth u16 blkS = s & 3; u16 blkT = t & 3; u32 blkOff = (blkT << 2) + blkS; - + u32 offset = (base + blkOff) << 1; const u16* valAddr = (u16*)(src + offset); @@ -2465,7 +2372,7 @@ void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth u32 offset = (base + blkOff) << 3; const DXTBlock* dxtBlock = (const DXTBlock*)(src + offset); - + u16 c1 = Common::swap16(dxtBlock->color1); u16 c2 = Common::swap16(dxtBlock->color2); int blue1 = Convert5To8(c1 & 0x1F); @@ -2484,7 +2391,7 @@ void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth colorSel |= c1 > c2?0:4; u32 color = 0; - + switch (colorSel) { case 0: |
