mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-29 04:08:55 +00:00
Merge pull request #20 from dolphin-emu/master
[pull] master from dolphin-emu:master
This commit is contained in:
commit
872ece4c2f
92 changed files with 18567 additions and 2615 deletions
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,307 @@
|
||||||
|
{
|
||||||
|
"meta":
|
||||||
|
{
|
||||||
|
"title": "Dragon Ball Z: Budokai Tenkaichi 3 Definitions",
|
||||||
|
"author": "Seedonator"
|
||||||
|
},
|
||||||
|
"groups":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Bloom",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"type": "efb",
|
||||||
|
"texture_filename": "efb1_n000014_128x128_4"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HUD",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "HUD Backdrop",
|
||||||
|
"texture_filename": "tex1_256x64_50e9493ab5ecd6e9_5efd0133152917bc_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Max Power Lightning",
|
||||||
|
"texture_filename": "tex1_256x128_76ee22f289405f4f_0a3363fc16e5200b_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Timer Backdrop",
|
||||||
|
"texture_filename": "tex1_64x64_1b0bd43920520089_894789000b300d35_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Teammate Backdrop",
|
||||||
|
"texture_filename": "tex1_64x64_76189a0850bac928_d5586441a9651de1_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "HUD Backdrop 2",
|
||||||
|
"texture_filename": "tex1_256x64_4751a5dd9b515483_6ef5db463bf9b5fe_9"
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Meters Colored",
|
||||||
|
"texture_filename": "tex1_256x64_974aae7fb39dd3fe_dc826162c7781cf3_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Meters Colored 2",
|
||||||
|
"texture_filename": "tex1_256x64_974aae7fb39dd3fe_c0adc9c4480c91c1_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Meters Red",
|
||||||
|
"texture_filename": "tex1_256x64_974aae7fb39dd3fe_65f3d25263258092_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Meters Overlay",
|
||||||
|
"texture_filename": "tex1_256x64_974aae7fb39dd3fe_37c76c0d16ef044d_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Meter Glow",
|
||||||
|
"texture_filename": "tex1_64x64_1c31b3c28a7aef47_1c42ae23afd2f40f_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Meter Teammate",
|
||||||
|
"texture_filename": "tex1_128x32_277ce02a6f60e609_30b338ab0d636ab2_9"
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Stat Bonus Ki Damage",
|
||||||
|
"texture_filename": "tex1_32x32_20bc4452577d1f49_85422f750ab42532_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Stat Bonus Charge Speed",
|
||||||
|
"texture_filename": "tex1_32x32_af9478cb6ebc0b7a_5ba8f3ea380bfdcf_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Stat Bonus Defense",
|
||||||
|
"texture_filename": "tex1_32x32_c7cf9020318a2959_5d41872b1fcd6199_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Stat Bonus Melee Damage",
|
||||||
|
"texture_filename": "tex1_32x32_e4c8e81a7318fa25_6e21f60b0c990c98_8"
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Blast Stock Number",
|
||||||
|
"texture_filename": "tex1_128x64_00ba91db7d176946_0ecdf6905c577ddb_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Blast Stock Number Glow",
|
||||||
|
"texture_filename": "tex1_128x64_53d69bea13e150ab_24a4df43c24b0515_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Timer Value",
|
||||||
|
"texture_filename": "tex1_128x128_6976151439efad50_501b3bc09a6958d7_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Hit Text",
|
||||||
|
"texture_filename": "tex1_128x64_9366938c3344b862_83be965a88f28a40_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Hit Counter",
|
||||||
|
"texture_filename": "tex1_128x128_273f16293f4d7a40_8a29b5887317abf8_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Damage Counter",
|
||||||
|
"texture_filename": "tex1_128x128_1588ef89e137fc24_1cce6b863d92c9a0_8"
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Announcer Max Power",
|
||||||
|
"texture_filename": "tex1_128x64_482f78c5dfc14eab_0e7513b77d82c9ae_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Announcer First Attack",
|
||||||
|
"texture_filename": "tex1_128x64_b92d24567ae12b3a_14d61fafa74e6334_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Announcer Counter",
|
||||||
|
"texture_filename": "tex1_128x64_bbdfacdc36d171ec_85047913fd8df9aa_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Announcer Lock On",
|
||||||
|
"texture_filename": "tex1_128x64_3ba4b1f803afd256_93ba5384bd764946_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Announcer Boost",
|
||||||
|
"texture_filename": "tex1_128x64_09d5b89f7dbf0590_2abc7134cbb2138b_9"
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Buttom Prompt Y",
|
||||||
|
"texture_filename": "tex1_32x32_15f350b2b7f46481_66860824280a89bf_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt Y Hold",
|
||||||
|
"texture_filename": "tex1_32x32_00d2fb316a25d017_a889bebad6535a02_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt Y Mash",
|
||||||
|
"texture_filename": "tex1_64x64_8934f812b54f87c4_66860824280a89bf_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Buttom Prompt B",
|
||||||
|
"texture_filename": "tex1_32x32_ce62786fc1170192_70b585e07941e91c_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt B Hold",
|
||||||
|
"texture_filename": "tex1_32x32_2841b917a7c23834_bdbd0425eb2f4b52_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt B Mash",
|
||||||
|
"texture_filename": "tex1_64x64_23b176984035b44c_8204be59ecb7c469_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Buttom Prompt X",
|
||||||
|
"texture_filename": "tex1_32x32_b52817e68be0e2d7_d1b283ce04ce1c7c_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt X Mash",
|
||||||
|
"texture_filename": "tex1_64x64_cb8aa5843b3cc31c_ccbcbdf9c811ed5d_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Buttom Prompt A",
|
||||||
|
"texture_filename": "tex1_32x32_630cfa888a9d005a_d95570935377e345_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt A Mash",
|
||||||
|
"texture_filename": "tex1_64x64_eef97dc696b0edd6_758bf7c8a0397add_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt Hold Hand",
|
||||||
|
"texture_filename": "tex1_32x32_80eec4ab54c12b14_2fbe88721f145bc3_8"
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt LStick Up",
|
||||||
|
"texture_filename": "tex1_32x32_56eb18736158692a_831cb2dcaee7d9c7_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt LStick Down",
|
||||||
|
"texture_filename": "tex1_32x32_4f6911885cbfd6b7_b01602f981cf7194_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt LStick Left",
|
||||||
|
"texture_filename": "tex1_32x32_de66fb7b17f39fb2_723568783ce8af39_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt LStick Right",
|
||||||
|
"texture_filename": "tex1_32x32_4a3ce686c4d7d216_d9a6c961c9883e00_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt LStick Clash N",
|
||||||
|
"texture_filename": "tex1_64x64_0e45133195ab2db7_8061698fc3e81ec4_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt LStick Clash NE",
|
||||||
|
"texture_filename": "tex1_64x64_23a7ebdcad6f294c_961413a3996f1955_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt LStick Clash E",
|
||||||
|
"texture_filename": "tex1_64x64_fc736187474b6d87_5db58dd7fedde1e4_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt LStick Clash SE",
|
||||||
|
"texture_filename": "tex1_64x64_847d2a027ba61a6d_da6f9db59fa7a52b_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt LStick Clash S",
|
||||||
|
"texture_filename": "tex1_64x64_2fd46476d6eeb2a5_8cf71f59f3f4f61d_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt LStick Clash Neutral",
|
||||||
|
"texture_filename": "tex1_64x64_e63e59943072d5ba_13e4b338982e9dbc_8"
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt Plus",
|
||||||
|
"texture_filename": "tex1_32x32_214dbb89f41af76c_ee10bcb01a356553_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Button Prompt Mash Backdrop",
|
||||||
|
"texture_filename": "tex1_64x64_c7be948af15370ea_104c0c86a865a442_9"
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Text Font Main",
|
||||||
|
"texture_filename": "tex1_512x128_b38c0db36dfc6ac3_71a440118950d6cd_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "draw_started",
|
||||||
|
"prettyname": "Text Font Special",
|
||||||
|
"texture_filename": "tex1_512x128_b38c0db36dfc6ac3_561056e6b4e21980_8"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
64
Data/Sys/Shaders/AutoHDR.glsl
Normal file
64
Data/Sys/Shaders/AutoHDR.glsl
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
// Based on https://github.com/Filoppi/PumboAutoHDR
|
||||||
|
|
||||||
|
/*
|
||||||
|
[configuration]
|
||||||
|
|
||||||
|
[OptionRangeFloat]
|
||||||
|
GUIName = HDR Display Max Nits
|
||||||
|
OptionName = HDR_DISPLAY_MAX_NITS
|
||||||
|
MinValue = 80
|
||||||
|
MaxValue = 2000
|
||||||
|
StepAmount = 1
|
||||||
|
DefaultValue = 400
|
||||||
|
|
||||||
|
[OptionRangeFloat]
|
||||||
|
GUIName = Shoulder Start Alpha
|
||||||
|
OptionName = AUTO_HDR_SHOULDER_START_ALPHA
|
||||||
|
MinValue = 0
|
||||||
|
MaxValue = 1
|
||||||
|
StepAmount = 0.01
|
||||||
|
DefaultValue = 0
|
||||||
|
|
||||||
|
[OptionRangeFloat]
|
||||||
|
GUIName = Shoulder Pow
|
||||||
|
OptionName = AUTO_HDR_SHOULDER_POW
|
||||||
|
MinValue = 1
|
||||||
|
MaxValue = 10
|
||||||
|
StepAmount = 0.05
|
||||||
|
DefaultValue = 2.5
|
||||||
|
|
||||||
|
[/configuration]
|
||||||
|
*/
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
float4 color = Sample();
|
||||||
|
|
||||||
|
// Nothing to do here, we are in SDR
|
||||||
|
if (!OptionEnabled(hdr_output) || !OptionEnabled(linear_space_output))
|
||||||
|
{
|
||||||
|
SetOutput(color);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float hdr_paper_white = hdr_paper_white_nits / hdr_sdr_white_nits;
|
||||||
|
|
||||||
|
// Restore the original SDR (0-1) brightness (we might or might not restore it later)
|
||||||
|
color.rgb /= hdr_paper_white;
|
||||||
|
|
||||||
|
// Find the color average
|
||||||
|
float sdr_ratio = (color.r + color.g + color.b) / 3.0;
|
||||||
|
|
||||||
|
const float auto_hdr_max_white = max(HDR_DISPLAY_MAX_NITS / (hdr_paper_white_nits / hdr_sdr_white_nits), hdr_sdr_white_nits) / hdr_sdr_white_nits;
|
||||||
|
if (sdr_ratio > AUTO_HDR_SHOULDER_START_ALPHA && AUTO_HDR_SHOULDER_START_ALPHA < 1.0)
|
||||||
|
{
|
||||||
|
const float auto_hdr_shoulder_ratio = 1.0 - (max(1.0 - sdr_ratio, 0.0) / (1.0 - AUTO_HDR_SHOULDER_START_ALPHA));
|
||||||
|
const float auto_hdr_extra_ratio = pow(auto_hdr_shoulder_ratio, AUTO_HDR_SHOULDER_POW) * (auto_hdr_max_white - 1.0);
|
||||||
|
const float auto_hdr_total_ratio = sdr_ratio + auto_hdr_extra_ratio;
|
||||||
|
color.rgb *= auto_hdr_total_ratio / sdr_ratio;
|
||||||
|
}
|
||||||
|
|
||||||
|
color.rgb *= hdr_paper_white;
|
||||||
|
|
||||||
|
SetOutput(color);
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
// References:
|
/***** COLOR CORRECTION *****/
|
||||||
|
|
||||||
|
// Color Space references:
|
||||||
// https://www.unravel.com.au/understanding-color-spaces
|
// https://www.unravel.com.au/understanding-color-spaces
|
||||||
|
|
||||||
// SMPTE 170M - BT.601 (NTSC-M) -> BT.709
|
// SMPTE 170M - BT.601 (NTSC-M) -> BT.709
|
||||||
|
@ -21,7 +23,7 @@ mat3 from_PAL = transpose(mat3(
|
||||||
|
|
||||||
float3 LinearTosRGBGamma(float3 color)
|
float3 LinearTosRGBGamma(float3 color)
|
||||||
{
|
{
|
||||||
float a = 0.055;
|
const float a = 0.055;
|
||||||
|
|
||||||
for (int i = 0; i < 3; ++i)
|
for (int i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
|
@ -36,17 +38,336 @@ float3 LinearTosRGBGamma(float3 color)
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***** COLOR SAMPLING *****/
|
||||||
|
|
||||||
|
// Non filtered gamma corrected sample (nearest neighbor)
|
||||||
|
float4 QuickSample(float3 uvw, float gamma)
|
||||||
|
{
|
||||||
|
#if 0 // Test sampling range
|
||||||
|
const float threshold = 0.00000001;
|
||||||
|
float2 xy = uvw.xy * GetResolution();
|
||||||
|
// Sampling outside the valid range, draw in yellow
|
||||||
|
if (xy.x < (0.0 - threshold) || xy.x > (GetResolution().x + threshold) || xy.y < (0.0 - threshold) || xy.y > (GetResolution().y + threshold))
|
||||||
|
return float4(1.0, 1.0, 0.0, 1);
|
||||||
|
// Sampling at the edges, draw in purple
|
||||||
|
if (xy.x < 1.0 || xy.x > (GetResolution().x - 1.0) || xy.y < 1.0 || xy.y > (GetResolution().y - 1.0))
|
||||||
|
return float4(0.5, 0, 0.5, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float4 color = texture(samp1, uvw);
|
||||||
|
color.rgb = pow(color.rgb, float3(gamma));
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
float4 QuickSample(float2 uv, float w, float gamma)
|
||||||
|
{
|
||||||
|
return QuickSample(float3(uv, w), gamma);
|
||||||
|
}
|
||||||
|
float4 QuickSampleByPixel(float2 xy, float w, float gamma)
|
||||||
|
{
|
||||||
|
float3 uvw = float3(xy * GetInvResolution(), w);
|
||||||
|
return QuickSample(uvw, gamma);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Bilinear Interpolation *****/
|
||||||
|
|
||||||
|
float4 BilinearSample(float3 uvw, float gamma)
|
||||||
|
{
|
||||||
|
// This emulates the (bi)linear filtering done directly from GPUs HW.
|
||||||
|
// Note that GPUs might natively filter red green and blue differently, but we don't do it.
|
||||||
|
// They might also use different filtering between upscaling and downscaling.
|
||||||
|
float2 source_size = GetResolution();
|
||||||
|
float2 pixel = (uvw.xy * source_size) - 0.5; // Try to find the matching pixel top left corner
|
||||||
|
|
||||||
|
// Find the integer and floating point parts
|
||||||
|
float2 int_pixel = floor(pixel);
|
||||||
|
float2 frac_pixel = fract(pixel);
|
||||||
|
|
||||||
|
// Take 4 samples around the original uvw
|
||||||
|
float4 c11 = QuickSampleByPixel(int_pixel + float2(0.5, 0.5), uvw.z, gamma);
|
||||||
|
float4 c21 = QuickSampleByPixel(int_pixel + float2(1.5, 0.5), uvw.z, gamma);
|
||||||
|
float4 c12 = QuickSampleByPixel(int_pixel + float2(0.5, 1.5), uvw.z, gamma);
|
||||||
|
float4 c22 = QuickSampleByPixel(int_pixel + float2(1.5, 1.5), uvw.z, gamma);
|
||||||
|
|
||||||
|
// Blend the 4 samples by their weight
|
||||||
|
return lerp(lerp(c11, c21, frac_pixel.x), lerp(c12, c22, frac_pixel.x), frac_pixel.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Bicubic Interpolation *****/
|
||||||
|
|
||||||
|
// Formula derived from:
|
||||||
|
// https://en.wikipedia.org/wiki/Mitchell%E2%80%93Netravali_filters#Definition
|
||||||
|
// Values from:
|
||||||
|
// https://guideencodemoe-mkdocs.readthedocs.io/encoding/resampling/#mitchell-netravali-bicubic
|
||||||
|
// Other references:
|
||||||
|
// https://www.codeproject.com/Articles/236394/Bi-Cubic-and-Bi-Linear-Interpolation-with-GLSL
|
||||||
|
// https://github.com/ValveSoftware/gamescope/pull/740
|
||||||
|
// https://stackoverflow.com/questions/13501081/efficient-bicubic-filtering-code-in-glsl
|
||||||
|
#define CUBIC_COEFF_GEN(B, C) \
|
||||||
|
(mat4(/* t^0 */ ((B) / 6.0), (-(B) / 3.0 + 1.0), ((B) / 6.0), (0.0), \
|
||||||
|
/* t^1 */ (-(B) / 2.0 - (C)), (0.0), ((B) / 2.0 + (C)), (0.0), \
|
||||||
|
/* t^2 */ ((B) / 2.0 + 2.0 * (C)), (2.0 * (B) + (C)-3.0), \
|
||||||
|
(-5.0 * (B) / 2.0 - 2.0 * (C) + 3.0), (-(C)), \
|
||||||
|
/* t^3 */ (-(B) / 6.0 - (C)), (-3.0 * (B) / 2.0 - (C) + 2.0), \
|
||||||
|
(3.0 * (B) / 2.0 + (C)-2.0), ((B) / 6.0 + (C))))
|
||||||
|
|
||||||
|
float4 CubicCoeffs(float t, mat4 coeffs)
|
||||||
|
{
|
||||||
|
return coeffs * float4(1.0, t, t * t, t * t * t);
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 CubicMix(float4 c0, float4 c1, float4 c2, float4 c3, float4 coeffs)
|
||||||
|
{
|
||||||
|
return c0 * coeffs[0] + c1 * coeffs[1] + c2 * coeffs[2] + c3 * coeffs[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
// By Sam Belliveau. Public Domain license.
|
||||||
|
// Simple 16 tap, gamma correct, implementation of bicubic filtering.
|
||||||
|
float4 BicubicSample(float3 uvw, float gamma, mat4 coeffs)
|
||||||
|
{
|
||||||
|
float2 pixel = (uvw.xy * GetResolution()) - 0.5;
|
||||||
|
float2 int_pixel = floor(pixel);
|
||||||
|
float2 frac_pixel = fract(pixel);
|
||||||
|
|
||||||
|
float4 c00 = QuickSampleByPixel(int_pixel + float2(-0.5, -0.5), uvw.z, gamma);
|
||||||
|
float4 c10 = QuickSampleByPixel(int_pixel + float2(+0.5, -0.5), uvw.z, gamma);
|
||||||
|
float4 c20 = QuickSampleByPixel(int_pixel + float2(+1.5, -0.5), uvw.z, gamma);
|
||||||
|
float4 c30 = QuickSampleByPixel(int_pixel + float2(+2.5, -0.5), uvw.z, gamma);
|
||||||
|
|
||||||
|
float4 c01 = QuickSampleByPixel(int_pixel + float2(-0.5, +0.5), uvw.z, gamma);
|
||||||
|
float4 c11 = QuickSampleByPixel(int_pixel + float2(+0.5, +0.5), uvw.z, gamma);
|
||||||
|
float4 c21 = QuickSampleByPixel(int_pixel + float2(+1.5, +0.5), uvw.z, gamma);
|
||||||
|
float4 c31 = QuickSampleByPixel(int_pixel + float2(+2.5, +0.5), uvw.z, gamma);
|
||||||
|
|
||||||
|
float4 c02 = QuickSampleByPixel(int_pixel + float2(-0.5, +1.5), uvw.z, gamma);
|
||||||
|
float4 c12 = QuickSampleByPixel(int_pixel + float2(+0.5, +1.5), uvw.z, gamma);
|
||||||
|
float4 c22 = QuickSampleByPixel(int_pixel + float2(+1.5, +1.5), uvw.z, gamma);
|
||||||
|
float4 c32 = QuickSampleByPixel(int_pixel + float2(+2.5, +1.5), uvw.z, gamma);
|
||||||
|
|
||||||
|
float4 c03 = QuickSampleByPixel(int_pixel + float2(-0.5, +2.5), uvw.z, gamma);
|
||||||
|
float4 c13 = QuickSampleByPixel(int_pixel + float2(+0.5, +2.5), uvw.z, gamma);
|
||||||
|
float4 c23 = QuickSampleByPixel(int_pixel + float2(+1.5, +2.5), uvw.z, gamma);
|
||||||
|
float4 c33 = QuickSampleByPixel(int_pixel + float2(+2.5, +2.5), uvw.z, gamma);
|
||||||
|
|
||||||
|
float4 cx = CubicCoeffs(frac_pixel.x, coeffs);
|
||||||
|
float4 cy = CubicCoeffs(frac_pixel.y, coeffs);
|
||||||
|
|
||||||
|
float4 x0 = CubicMix(c00, c10, c20, c30, cx);
|
||||||
|
float4 x1 = CubicMix(c01, c11, c21, c31, cx);
|
||||||
|
float4 x2 = CubicMix(c02, c12, c22, c32, cx);
|
||||||
|
float4 x3 = CubicMix(c03, c13, c23, c33, cx);
|
||||||
|
|
||||||
|
return CubicMix(x0, x1, x2, x3, cy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Sharp Bilinear Filtering *****/
|
||||||
|
|
||||||
|
// Based on https://github.com/libretro/slang-shaders/blob/master/interpolation/shaders/sharp-bilinear.slang
|
||||||
|
// by Themaister, Public Domain license
|
||||||
|
// Does a bilinear stretch, with a preapplied Nx nearest-neighbor scale,
|
||||||
|
// giving a sharper image than plain bilinear.
|
||||||
|
float4 SharpBilinearSample(float3 uvw, float gamma)
|
||||||
|
{
|
||||||
|
float2 source_size = GetResolution();
|
||||||
|
float2 inverted_source_size = GetInvResolution();
|
||||||
|
float2 target_size = GetWindowResolution();
|
||||||
|
float2 texel = uvw.xy * source_size;
|
||||||
|
float2 texel_floored = floor(texel);
|
||||||
|
float2 s = fract(texel);
|
||||||
|
float scale = ceil(max(target_size.x * inverted_source_size.x, target_size.y * inverted_source_size.y));
|
||||||
|
float region_range = 0.5 - (0.5 / scale);
|
||||||
|
|
||||||
|
// Figure out where in the texel to sample to get correct pre-scaled bilinear.
|
||||||
|
|
||||||
|
float2 center_dist = s - 0.5;
|
||||||
|
float2 f = ((center_dist - clamp(center_dist, -region_range, region_range)) * scale) + 0.5;
|
||||||
|
|
||||||
|
float2 mod_texel = texel_floored + f;
|
||||||
|
|
||||||
|
uvw.xy = mod_texel * inverted_source_size;
|
||||||
|
return BilinearSample(uvw, gamma);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Area Sampling *****/
|
||||||
|
|
||||||
|
// By Sam Belliveau and Filippo Tarpini. Public Domain license.
|
||||||
|
// Effectively a more accurate sharp bilinear filter when upscaling,
|
||||||
|
// that also works as a mathematically perfect downscale filter.
|
||||||
|
// https://entropymine.com/imageworsener/pixelmixing/
|
||||||
|
// https://github.com/obsproject/obs-studio/pull/1715
|
||||||
|
// https://legacy.imagemagick.org/Usage/filter/
|
||||||
|
float4 AreaSampling(float3 uvw, float gamma)
|
||||||
|
{
|
||||||
|
// Determine the sizes of the source and target images.
|
||||||
|
float2 source_size = GetResolution();
|
||||||
|
float2 inverted_target_size = GetInvWindowResolution();
|
||||||
|
|
||||||
|
// Determine the range of the source image that the target pixel will cover.
|
||||||
|
// Workaround: shift the resolution by 1/4 pixel to align the results with other sampling algorithms,
|
||||||
|
// otherwise the results would be offsetted, and we'd be sampling from coordinates outside the valid range.
|
||||||
|
float2 adjusted_source_size = source_size - 0.25;
|
||||||
|
float2 range = adjusted_source_size * inverted_target_size;
|
||||||
|
float2 beg = (uvw.xy * adjusted_source_size) - (range * 0.5);
|
||||||
|
float2 end = beg + range;
|
||||||
|
|
||||||
|
// Compute the top-left and bottom-right corners of the pixel box.
|
||||||
|
float2 f_beg = floor(beg);
|
||||||
|
float2 f_end = floor(end);
|
||||||
|
|
||||||
|
// Compute how much of the start and end pixels are covered horizontally & vertically.
|
||||||
|
float area_w = 1.0 - fract(beg.x);
|
||||||
|
float area_n = 1.0 - fract(beg.y);
|
||||||
|
float area_e = fract(end.x);
|
||||||
|
float area_s = fract(end.y);
|
||||||
|
|
||||||
|
// Compute the areas of the corner pixels in the pixel box.
|
||||||
|
float area_nw = area_n * area_w;
|
||||||
|
float area_ne = area_n * area_e;
|
||||||
|
float area_sw = area_s * area_w;
|
||||||
|
float area_se = area_s * area_e;
|
||||||
|
|
||||||
|
// Initialize the color accumulator.
|
||||||
|
float4 avg_color = float4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
// Prevents rounding errors due to the coordinates flooring above
|
||||||
|
const float2 offset = float2(0.5, 0.5);
|
||||||
|
|
||||||
|
// Accumulate corner pixels.
|
||||||
|
avg_color += area_nw * QuickSampleByPixel(float2(f_beg.x, f_beg.y) + offset, uvw.z, gamma);
|
||||||
|
avg_color += area_ne * QuickSampleByPixel(float2(f_end.x, f_beg.y) + offset, uvw.z, gamma);
|
||||||
|
avg_color += area_sw * QuickSampleByPixel(float2(f_beg.x, f_end.y) + offset, uvw.z, gamma);
|
||||||
|
avg_color += area_se * QuickSampleByPixel(float2(f_end.x, f_end.y) + offset, uvw.z, gamma);
|
||||||
|
|
||||||
|
// Determine the size of the pixel box.
|
||||||
|
int x_range = int(f_end.x - f_beg.x + 0.5);
|
||||||
|
int y_range = int(f_end.y - f_beg.y + 0.5);
|
||||||
|
|
||||||
|
// Workaround to compile the shader with DX11/12.
|
||||||
|
// If this isn't done, it will complain that the loop could have too many iterations.
|
||||||
|
// This number should be enough to guarantee downscaling from very high to very small resolutions.
|
||||||
|
// Note that this number might be referenced in the UI.
|
||||||
|
const int max_iterations = 16;
|
||||||
|
|
||||||
|
// Fix up the average calculations in case we reached the upper limit
|
||||||
|
x_range = min(x_range, max_iterations);
|
||||||
|
y_range = min(y_range, max_iterations);
|
||||||
|
|
||||||
|
// Accumulate top and bottom edge pixels.
|
||||||
|
for (int ix = 0; ix < max_iterations; ++ix)
|
||||||
|
{
|
||||||
|
if (ix < x_range)
|
||||||
|
{
|
||||||
|
float x = f_beg.x + 1.0 + float(ix);
|
||||||
|
avg_color += area_n * QuickSampleByPixel(float2(x, f_beg.y) + offset, uvw.z, gamma);
|
||||||
|
avg_color += area_s * QuickSampleByPixel(float2(x, f_end.y) + offset, uvw.z, gamma);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accumulate left and right edge pixels and all the pixels in between.
|
||||||
|
for (int iy = 0; iy < max_iterations; ++iy)
|
||||||
|
{
|
||||||
|
if (iy < y_range)
|
||||||
|
{
|
||||||
|
float y = f_beg.y + 1.0 + float(iy);
|
||||||
|
|
||||||
|
avg_color += area_w * QuickSampleByPixel(float2(f_beg.x, y) + offset, uvw.z, gamma);
|
||||||
|
avg_color += area_e * QuickSampleByPixel(float2(f_end.x, y) + offset, uvw.z, gamma);
|
||||||
|
|
||||||
|
for (int ix = 0; ix < max_iterations; ++ix)
|
||||||
|
{
|
||||||
|
if (ix < x_range)
|
||||||
|
{
|
||||||
|
float x = f_beg.x + 1.0 + float(ix);
|
||||||
|
avg_color += QuickSampleByPixel(float2(x, y) + offset, uvw.z, gamma);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the area of the pixel box that was sampled.
|
||||||
|
float area_corners = area_nw + area_ne + area_sw + area_se;
|
||||||
|
float area_edges = float(x_range) * (area_n + area_s) + float(y_range) * (area_w + area_e);
|
||||||
|
float area_center = float(x_range) * float(y_range);
|
||||||
|
|
||||||
|
// Return the normalized average color.
|
||||||
|
return avg_color / (area_corners + area_edges + area_center);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Main Functions *****/
|
||||||
|
|
||||||
|
// Returns an accurate (gamma corrected) sample of a gamma space space texture.
|
||||||
|
// Outputs in linear space for simplicity.
|
||||||
|
float4 LinearGammaCorrectedSample(float gamma)
|
||||||
|
{
|
||||||
|
float3 uvw = v_tex0;
|
||||||
|
float4 color = float4(0, 0, 0, 1);
|
||||||
|
|
||||||
|
if (resampling_method <= 1) // Bilinear
|
||||||
|
{
|
||||||
|
color = BilinearSample(uvw, gamma);
|
||||||
|
}
|
||||||
|
else if (resampling_method == 2) // Bicubic: B-Spline
|
||||||
|
{
|
||||||
|
color = BicubicSample(uvw, gamma, CUBIC_COEFF_GEN(1.0, 0.0));
|
||||||
|
}
|
||||||
|
else if (resampling_method == 3) // Bicubic: Mitchell-Netravali
|
||||||
|
{
|
||||||
|
color = BicubicSample(uvw, gamma, CUBIC_COEFF_GEN(1.0 / 3.0, 1.0 / 3.0));
|
||||||
|
}
|
||||||
|
else if (resampling_method == 4) // Bicubic: Catmull-Rom
|
||||||
|
{
|
||||||
|
color = BicubicSample(uvw, gamma, CUBIC_COEFF_GEN(0.0, 0.5));
|
||||||
|
}
|
||||||
|
else if (resampling_method == 5) // Sharp Bilinear
|
||||||
|
{
|
||||||
|
color = SharpBilinearSample(uvw, gamma);
|
||||||
|
}
|
||||||
|
else if (resampling_method == 6) // Area Sampling
|
||||||
|
{
|
||||||
|
color = AreaSampling(uvw, gamma);
|
||||||
|
}
|
||||||
|
else if (resampling_method == 7) // Nearest Neighbor
|
||||||
|
{
|
||||||
|
color = QuickSample(uvw, gamma);
|
||||||
|
}
|
||||||
|
else if (resampling_method == 8) // Bicubic: Hermite
|
||||||
|
{
|
||||||
|
color = BicubicSample(uvw, gamma, CUBIC_COEFF_GEN(0.0, 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
// Note: sampling in gamma space is "wrong" if the source
|
// This tries to fall back on GPU HW sampling if it can (it won't be gamma corrected).
|
||||||
// and target resolution don't match exactly.
|
bool raw_resampling = resampling_method <= 0;
|
||||||
// Fortunately at the moment here they always should but to do this correctly,
|
bool needs_rescaling = GetResolution() != GetWindowResolution();
|
||||||
// we'd need to sample from 4 pixels, de-apply the gamma from each of these,
|
|
||||||
// and then do linear sampling on their corrected value.
|
|
||||||
float4 color = Sample();
|
|
||||||
|
|
||||||
// Convert to linear space to do any other kind of operation
|
bool needs_resampling = needs_rescaling && (OptionEnabled(hdr_output) || OptionEnabled(correct_gamma) || !raw_resampling);
|
||||||
|
|
||||||
|
float4 color;
|
||||||
|
|
||||||
|
if (needs_resampling)
|
||||||
|
{
|
||||||
|
// Doing linear sampling in "gamma space" on linear texture formats isn't correct.
|
||||||
|
// If the source and target resolutions don't match, the GPU will return a color
|
||||||
|
// that is the average of 4 gamma space colors, but gamma space colors can't be blended together,
|
||||||
|
// gamma neeeds to be de-applied first. This makes a big difference if colors change
|
||||||
|
// drastically between two pixels.
|
||||||
|
|
||||||
|
color = LinearGammaCorrectedSample(game_gamma);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Default GPU HW sampling. Bilinear is identical to Nearest Neighbor if the input and output resolutions match.
|
||||||
|
if (needs_rescaling)
|
||||||
|
color = texture(samp0, v_tex0);
|
||||||
|
else
|
||||||
|
color = texture(samp1, v_tex0);
|
||||||
|
|
||||||
|
// Convert to linear before doing any other of follow up operations.
|
||||||
color.rgb = pow(color.rgb, float3(game_gamma));
|
color.rgb = pow(color.rgb, float3(game_gamma));
|
||||||
|
}
|
||||||
|
|
||||||
if (OptionEnabled(correct_color_space))
|
if (OptionEnabled(correct_color_space))
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
// Based on https://github.com/libretro/slang-shaders/blob/master/interpolation/shaders/sharp-bilinear.slang
|
|
||||||
// by Themaister, Public Domain license
|
|
||||||
// Does a bilinear stretch, with a preapplied Nx nearest-neighbor scale,
|
|
||||||
// giving a sharper image than plain bilinear.
|
|
||||||
|
|
||||||
/*
|
|
||||||
[configuration]
|
|
||||||
[OptionRangeFloat]
|
|
||||||
GUIName = Prescale Factor (set to 0 for automatic)
|
|
||||||
OptionName = PRESCALE_FACTOR
|
|
||||||
MinValue = 0.0
|
|
||||||
MaxValue = 16.0
|
|
||||||
StepAmount = 1.0
|
|
||||||
DefaultValue = 0.0
|
|
||||||
[/configuration]
|
|
||||||
*/
|
|
||||||
|
|
||||||
float CalculatePrescale(float config_scale) {
|
|
||||||
if (config_scale == 0.0) {
|
|
||||||
float2 source_size = GetResolution();
|
|
||||||
float2 window_size = GetWindowResolution();
|
|
||||||
return ceil(max(window_size.x / source_size.x, window_size.y / source_size.y));
|
|
||||||
} else {
|
|
||||||
return config_scale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
float2 source_size = GetResolution();
|
|
||||||
float2 texel = GetCoordinates() * source_size;
|
|
||||||
float2 texel_floored = floor(texel);
|
|
||||||
float2 s = fract(texel);
|
|
||||||
float config_scale = GetOption(PRESCALE_FACTOR);
|
|
||||||
float scale = CalculatePrescale(config_scale);
|
|
||||||
float region_range = 0.5 - 0.5 / scale;
|
|
||||||
|
|
||||||
// Figure out where in the texel to sample to get correct pre-scaled bilinear.
|
|
||||||
// Uses the hardware bilinear interpolator to avoid having to sample 4 times manually.
|
|
||||||
|
|
||||||
float2 center_dist = s - 0.5;
|
|
||||||
float2 f = (center_dist - clamp(center_dist, -region_range, region_range)) * scale + 0.5;
|
|
||||||
|
|
||||||
float2 mod_texel = texel_floored + f;
|
|
||||||
|
|
||||||
SetOutput(SampleLocation(mod_texel / source_size));
|
|
||||||
}
|
|
|
@ -1,12 +1,11 @@
|
||||||
TITLES = https://www.gametdb.com (type: Wii language: DE_unique version: 20191106234221)
|
TITLES = https://www.gametdb.com (type: Wii language: DE_unique version: 20230727194133)
|
||||||
R22J01 = FlingSmash
|
R22J01 = FlingSmash
|
||||||
R23P52 = Barbie und Die Drei Musketiere
|
R23P52 = Barbie und Die Drei Musketiere
|
||||||
R25PWR = LEGO Harry Potter: Die Jahre 1-4
|
R25PWR = LEGO Harry Potter: Die Jahre 1-4
|
||||||
R29P52 = Millennium Championship Paintball 2009
|
R29P52 = Millennium Championship Paintball 2009
|
||||||
R2AP7D = Ice Age 2 - Jetzt taut's
|
R2AP7D = Ice Age 2 - Jetzt taut's
|
||||||
R2AX7D = Ice Age 2 - Jetzt taut's
|
R2AX7D = Ice Age 2: Jetzt taut's
|
||||||
R2FP70 = Fritzi Fisch und der verschwundene Schatz
|
R2FP70 = Fritzi Fisch und der verschwundene Schatz
|
||||||
R2GP99 = Fragile Dreams - Farewell Ruins of the Moon
|
|
||||||
R2YP54 = Alles gute zum Geburtstag!
|
R2YP54 = Alles gute zum Geburtstag!
|
||||||
R3YP70 = Sam & Max: Season Two: All-Zeit Bereit
|
R3YP70 = Sam & Max: Season Two: All-Zeit Bereit
|
||||||
R42P69 = Die Sims 2: Gestrandet
|
R42P69 = Die Sims 2: Gestrandet
|
||||||
|
@ -19,6 +18,7 @@ R4LXUG = Schweine Party
|
||||||
R4PP69 = Die Sims 2: Haustiere
|
R4PP69 = Die Sims 2: Haustiere
|
||||||
R4ZJ01 = Fatal Frame 4: Mask of the Lunar Eclipse
|
R4ZJ01 = Fatal Frame 4: Mask of the Lunar Eclipse
|
||||||
R55P41 = Wer wird Millionär
|
R55P41 = Wer wird Millionär
|
||||||
|
R59D4Q = Club Penguin: Game Day!
|
||||||
R5AP8P = Der Goldene Kompass
|
R5AP8P = Der Goldene Kompass
|
||||||
R5AX8P = Der Goldene Kompass
|
R5AX8P = Der Goldene Kompass
|
||||||
R5FP41 = Academy of Champions: Fussball
|
R5FP41 = Academy of Champions: Fussball
|
||||||
|
@ -30,10 +30,11 @@ R5QPGT = Zirkus
|
||||||
R5UP41 = CSI: Tödliche Absichten
|
R5UP41 = CSI: Tödliche Absichten
|
||||||
R5VP41 = James Cameron's Avatar: Das Spiel
|
R5VP41 = James Cameron's Avatar: Das Spiel
|
||||||
R5VX41 = James Cameron's Avatar: Das Spiel
|
R5VX41 = James Cameron's Avatar: Das Spiel
|
||||||
|
R5XJ13 = MySims Agents
|
||||||
R6APPU = Mein Baby und ich
|
R6APPU = Mein Baby und ich
|
||||||
R6MPML = America´s Next Top Model
|
R6MPML = America´s Next Top Model
|
||||||
R6WP68 = AMF Bowling: World Lanes
|
R6WP68 = AMF Bowling: World Lanes
|
||||||
R6XP69 = Hasbro - Spiel Mal Wieder!
|
R6XP69 = Hasbro: Spiel mal wieder!
|
||||||
R7AP69 = SimAnimals Afrika
|
R7AP69 = SimAnimals Afrika
|
||||||
R7BP7J = Jelly Belly - Ballistic Beans
|
R7BP7J = Jelly Belly - Ballistic Beans
|
||||||
R7SP5G = Escape the Museum
|
R7SP5G = Escape the Museum
|
||||||
|
@ -55,7 +56,7 @@ R9EPNP = Brico Party: Werde Heimwerker-König
|
||||||
R9GPWR = Die Legende der Wächter
|
R9GPWR = Die Legende der Wächter
|
||||||
R9LP41 = Girls Life: Pyjama-Party
|
R9LP41 = Girls Life: Pyjama-Party
|
||||||
R9RPNG = Dance Party - Pop Hits
|
R9RPNG = Dance Party - Pop Hits
|
||||||
RB2PGT = Balloon Pop!
|
RAAE01 = Disco de Startup Wii
|
||||||
RB7P54 = Bully: Die Ehrenrunde
|
RB7P54 = Bully: Die Ehrenrunde
|
||||||
RBEP52 = Bee Movie: Das Game
|
RBEP52 = Bee Movie: Das Game
|
||||||
RBEX52 = Bee Movie: Das Game
|
RBEX52 = Bee Movie: Das Game
|
||||||
|
@ -73,7 +74,7 @@ RC3X41 = Petz: Katzenfreunde
|
||||||
RC8P7D = Crash: Herrscher Der Mutanten
|
RC8P7D = Crash: Herrscher Der Mutanten
|
||||||
RC9PGN = CID : The Dummy
|
RC9PGN = CID : The Dummy
|
||||||
RCCPGT = Cooking Mama 1
|
RCCPGT = Cooking Mama 1
|
||||||
RCGP54 = Carnival - Die Jahrmarkt-Party
|
RCGP54 = Carnival: Die Jahrmarkt-Party
|
||||||
RCIP41 = CSI: Eindeutige Beweise
|
RCIP41 = CSI: Eindeutige Beweise
|
||||||
RCKPGN = Klaus Gronewalds Sports Challenge
|
RCKPGN = Klaus Gronewalds Sports Challenge
|
||||||
RCLP4Q = Himmel und Huhn: Ace in Action
|
RCLP4Q = Himmel und Huhn: Ace in Action
|
||||||
|
@ -102,19 +103,18 @@ RG5PWR = Guinness World Records: Das Videospiel
|
||||||
RG6P69 = Boogie Superstar
|
RG6P69 = Boogie Superstar
|
||||||
RG8P41 = Petz Sports: Wilder Hunde-Spaß
|
RG8P41 = Petz Sports: Wilder Hunde-Spaß
|
||||||
RGAP8P = Planet 51: Das Spiel
|
RGAP8P = Planet 51: Das Spiel
|
||||||
RGFP69 = Der Pate: Blackhand Edition
|
|
||||||
RGHP52 = Guitar Hero III: Legends Of Rock
|
|
||||||
RGJP7U = George Der aus dem Dschungel kam
|
RGJP7U = George Der aus dem Dschungel kam
|
||||||
RGQE70 = Ghostbusters: Das Videospiel
|
RGQE70 = Ghostbusters: Das Videospiel
|
||||||
RGQP70 = Ghostbusters: Das Videospiel
|
RGQP70 = Ghostbusters: Das Videospiel
|
||||||
|
RGZP70 = Godzilla Unle고질라 봉인 해제ashed
|
||||||
RH5PKM = Horse Life: Freunde für immer
|
RH5PKM = Horse Life: Freunde für immer
|
||||||
RH6P69 = Harry Potter und der Halbblutprinz
|
RH6P69 = Harry Potter und der Halbblutprinz
|
||||||
RHKP18 = Job Island
|
RHKP18 = Job Island
|
||||||
RHNP70 = My Horse & Me - Mein Pferd und Ich
|
RHNP70 = My Horse & Me: Mein Pferd und ich
|
||||||
RHQP4Q = Hannah Montana: Welttournee im Rampenlicht
|
RHQP4Q = Hannah Montana: Welttournee im Rampenlicht
|
||||||
RHQX4Q = Hannah Montana: Welttournee im Rampenlicht
|
RHQX4Q = Hannah Montana: Welttournee im Rampenlicht
|
||||||
RHQY4Q = Hannah Montana: Welttournee im Rampenlicht
|
RHQY4Q = Hannah Montana: Welttournee im Rampenlicht
|
||||||
RHVPFR = Moorhuhn - Das verbotene Schloss
|
RHVPFR = Moorhuhn: Das verbotene Schloss
|
||||||
RHZP41 = Abenteuer auf dem Reiterhof: Die Pferdeflüsterin
|
RHZP41 = Abenteuer auf dem Reiterhof: Die Pferdeflüsterin
|
||||||
RI2P4Q = High School Musical: Sing It!
|
RI2P4Q = High School Musical: Sing It!
|
||||||
RI3P5D = Lucas der Ameisenschreck
|
RI3P5D = Lucas der Ameisenschreck
|
||||||
|
@ -123,9 +123,8 @@ RIBPKM = Igor: Das Spiel
|
||||||
RIHP8P = Der unglaubliche Hulk
|
RIHP8P = Der unglaubliche Hulk
|
||||||
RIJP69 = G.I. Joe: Geheimauftrag Cobra
|
RIJP69 = G.I. Joe: Geheimauftrag Cobra
|
||||||
RIOPSU = Schauderhafte Geschichten: Skrupellose Römer
|
RIOPSU = Schauderhafte Geschichten: Skrupellose Römer
|
||||||
RIPPAF = One Piece Unlimited Cruise 1 - Der Schatz unter den Wellen
|
|
||||||
RIRP8P = Iron Man: The Video Game
|
RIRP8P = Iron Man: The Video Game
|
||||||
RIUPAF = One Piece Unlimited Cruise 2: Das Erwachen eines Helden
|
RIUPAF = One Piece: Unlimited Cruise 2: Das Erwachen eines Helden
|
||||||
RJ2P52 = 007: Ein Quantum Trost
|
RJ2P52 = 007: Ein Quantum Trost
|
||||||
RJ8P64 = Indiana Jones und der Stab der Könige
|
RJ8P64 = Indiana Jones und der Stab der Könige
|
||||||
RJ9PFR = Think Logic Trainer - Training für Körper und Geist
|
RJ9PFR = Think Logic Trainer - Training für Körper und Geist
|
||||||
|
@ -144,21 +143,20 @@ RLADMR = Deal Or No Deal: Der Banker Schlägt Zurück
|
||||||
RLAPMR = Deal Or No Deal: Der Banker Schlägt Zurück
|
RLAPMR = Deal Or No Deal: Der Banker Schlägt Zurück
|
||||||
RLBPWR = LEGO Batman: Das Videospiel
|
RLBPWR = LEGO Batman: Das Videospiel
|
||||||
RLFP64 = Star Wars The Clone Wars: Lichtschwertduelle
|
RLFP64 = Star Wars The Clone Wars: Lichtschwertduelle
|
||||||
RLGP64 = LEGO Star Wars: Die Komplette Saga
|
RLGP64 = LEGO Star Wars: Die komplette Saga
|
||||||
RLIP64 = LEGO Indiana Jones: Die legendären Abenteuer
|
RLIP64 = LEGO Indiana Jones: Die legendären Abenteuer
|
||||||
RLLP70 = Go West!: Ein Abenteuer mit Lucky Luke
|
RLLP70 = Go West! Ein Abenteuer mit Lucky Luke
|
||||||
RLUX4Q = Bolt: Ein Hund für alle Fälle!
|
RLUX4Q = Bolt: Ein Hund für alle Fälle!
|
||||||
RLVP78 = Avatar - Der Herr der Elemente
|
RLVP78 = Avatar - Der Herr der Elemente
|
||||||
RM5P7D = Die Mumie: Das Grabmal des Drachenkaisers
|
RM5P7D = Die Mumie: Das Grabmal des Drachenkaisers
|
||||||
RM9PGM = Mushroom Men: Der Sporenkrieg
|
RM9PGM = Mushroom Men: Der Sporenkrieg
|
||||||
RMNDFR = Meine Tierpension
|
RMNDFR = Meine Tierpension
|
||||||
RMNPFR = Meine Tierpension
|
RMNPFR = Meine Tierpension
|
||||||
RMXP78 = MX vs ATV: Untamed
|
|
||||||
RN3P78 = SpongeBob und seine Freunde: Angriff der Spielzeugroboter
|
RN3P78 = SpongeBob und seine Freunde: Angriff der Spielzeugroboter
|
||||||
RN3X78 = SpongeBob und seine Freunde: Angriff der Spielzeugroboter
|
RN3X78 = SpongeBob und seine Freunde: Angriff der Spielzeugroboter
|
||||||
RN4P41 = ANNO: Erschaffe eine neue Welt
|
RN4P41 = ANNO: Erschaffe eine neue Welt
|
||||||
RNIPGT = Mind.Body.Soul: Ernährung ist Wichtig
|
RNIPGT = Mind.Body.Soul: Ernährung ist Wichtig
|
||||||
RNNP4Q = Die Chroniken Von Narnia: Prinz Kaspian Von Narnia
|
RNNP4Q = Die Chroniken von Narnia: Prinz Kaspian von Narnia
|
||||||
RNNX4Q = Die Chroniken von Narnia: Prinz Kaspian
|
RNNX4Q = Die Chroniken von Narnia: Prinz Kaspian
|
||||||
RNNY4Q = Die Chroniken von Narnia: Prinz Kaspian
|
RNNY4Q = Die Chroniken von Narnia: Prinz Kaspian
|
||||||
RNNZ4Q = Die Chroniken von Narnia: Prinz Kaspian
|
RNNZ4Q = Die Chroniken von Narnia: Prinz Kaspian
|
||||||
|
@ -169,11 +167,11 @@ ROJP52 = Rapala: Angel-Spaß
|
||||||
ROLP8P = Mario & Sonic bei den Olympischen Winterspielen
|
ROLP8P = Mario & Sonic bei den Olympischen Winterspielen
|
||||||
ROPP41 = Jagdfieber
|
ROPP41 = Jagdfieber
|
||||||
ROTP7J = Twin Strike: Operation Thunderstorm
|
ROTP7J = Twin Strike: Operation Thunderstorm
|
||||||
ROUPAF = One Piece Unlimited Cruise 1: Der Schatz unter den Wellen
|
ROUPAF = One Piece: Unlimited Cruise 1: Der Schatz unter den Wellen
|
||||||
ROVPHM = Playmobil Circus: Manege frei!
|
ROVPHM = Playmobil Circus: Manege frei!
|
||||||
ROYP41 = Wolkig Mit Aussicht Auf Fleischbällchen: Das Videospiel
|
ROYP41 = Wolkig Mit Aussicht Auf Fleischbällchen: Das Videospiel
|
||||||
ROYX41 = Wolkig mit Aussicht auf Fleischbällchen
|
ROYX41 = Wolkig mit Aussicht auf Fleischbällchen
|
||||||
RP2P69 = Smarty Pants - Das Besserwisserspiel
|
RP2P69 = Smarty Pants: Das Besserwisserspiel
|
||||||
RP6P41 = Petz: Die Affen sind los
|
RP6P41 = Petz: Die Affen sind los
|
||||||
RP7P52 = Piraten: Die Jagd nach Blackbeards Schatz
|
RP7P52 = Piraten: Die Jagd nach Blackbeards Schatz
|
||||||
RP9PRS = Space Chimps: Affen Im All
|
RP9PRS = Space Chimps: Affen Im All
|
||||||
|
@ -182,7 +180,7 @@ RPFP52 = Pitfall: Das große Abenteuer
|
||||||
RPSP4Q = Disney Prinzessinnen: Märchenhafte Reise
|
RPSP4Q = Disney Prinzessinnen: Märchenhafte Reise
|
||||||
RPTD52 = Tierbabys - Mein kleiner Welpe
|
RPTD52 = Tierbabys - Mein kleiner Welpe
|
||||||
RPVPKM = Mein erstes Katzenbaby
|
RPVPKM = Mein erstes Katzenbaby
|
||||||
RPWX41 = Prince of Persia: Die Vergessene Zeit
|
RPWX41 = Prince of Persia: Die vergessene Zeit
|
||||||
RPYP9B = Pangya! Golf with Style
|
RPYP9B = Pangya! Golf with Style
|
||||||
RQ4P78 = SpongeBob Schwammkopf: Die Kreatur aus der Krossen Krabbe
|
RQ4P78 = SpongeBob Schwammkopf: Die Kreatur aus der Krossen Krabbe
|
||||||
RQ8P08 = Moto GP
|
RQ8P08 = Moto GP
|
||||||
|
@ -192,7 +190,6 @@ RQKP41 = Kirmes Party
|
||||||
RQNPWR = Scooby-Doo! Geheimnisvolle Abenteuer
|
RQNPWR = Scooby-Doo! Geheimnisvolle Abenteuer
|
||||||
RQOP69 = Spore Helden
|
RQOP69 = Spore Helden
|
||||||
RQTP6V = Agatha Christie: Und dann gabs keines mehr
|
RQTP6V = Agatha Christie: Und dann gabs keines mehr
|
||||||
RQWPG9 = Puzzle Quest - Challenge of the Warlords
|
|
||||||
RQXP70 = Asterix bei den Olympischen Spielen
|
RQXP70 = Asterix bei den Olympischen Spielen
|
||||||
RRCP52 = Barbie Pferdeabenteuer: Im Reitercamp
|
RRCP52 = Barbie Pferdeabenteuer: Im Reitercamp
|
||||||
RRGP52 = Madagascar 2
|
RRGP52 = Madagascar 2
|
||||||
|
@ -214,7 +211,7 @@ RSND69 = Die Simpsons: Das Spiel
|
||||||
RSNP69 = Die Simpsons: Das Spiel
|
RSNP69 = Die Simpsons: Das Spiel
|
||||||
RSNX69 = Die Simpsons: Das Spiel
|
RSNX69 = Die Simpsons: Das Spiel
|
||||||
RSRP8P = Sonic und die Geheimen Ringe
|
RSRP8P = Sonic und die Geheimen Ringe
|
||||||
RT3P54 = Rockstar Games präsentiert Tischtennis
|
RT3P54 = Rockstar Games präsentiert: Tischtennis
|
||||||
RT6PKM = Das Zauberkarussell
|
RT6PKM = Das Zauberkarussell
|
||||||
RTEHMR = Tierliebe Groß Geschrieben
|
RTEHMR = Tierliebe Groß Geschrieben
|
||||||
RTEPFR = Meine Tierarztpraxis
|
RTEPFR = Meine Tierarztpraxis
|
||||||
|
@ -230,7 +227,7 @@ RU5X4Q = Küss den Frosch
|
||||||
RU7X5G = Nachts im Museum 2: Das Spiel
|
RU7X5G = Nachts im Museum 2: Das Spiel
|
||||||
RUBP7N = Die ultimative Brettspiele-Sammlung
|
RUBP7N = Die ultimative Brettspiele-Sammlung
|
||||||
RUCXRT = RTL Winter Sports 2008
|
RUCXRT = RTL Winter Sports 2008
|
||||||
RUEP4Q = G-Force - Agenten mit Biss
|
RUEP4Q = G-Force: Agenten mit Biss
|
||||||
RUEX4Q = G-Force: Agenten mit Biss
|
RUEX4Q = G-Force: Agenten mit Biss
|
||||||
RUEY4Q = G-Force: Agenten mit Biss
|
RUEY4Q = G-Force: Agenten mit Biss
|
||||||
RUFP99 = Rune Factory Frontier
|
RUFP99 = Rune Factory Frontier
|
||||||
|
@ -262,7 +259,7 @@ RWAZ78 = WALL•E: Der Letzte räumt die Erde auf
|
||||||
RWFH41 = Mein Wortschatz-Coach: Verbessere dein Ausdrucksvermögen
|
RWFH41 = Mein Wortschatz-Coach: Verbessere dein Ausdrucksvermögen
|
||||||
RWMP78 = Worms: Odyssee im Wurmraum
|
RWMP78 = Worms: Odyssee im Wurmraum
|
||||||
RWSP8P = Mario & Sonic bei den Olympischen Spielen
|
RWSP8P = Mario & Sonic bei den Olympischen Spielen
|
||||||
RX2P70 = My Horse & Me 2: Mein Pferd und Ich
|
RX2P70 = My Horse & Me 2: Mein Pferd und ich
|
||||||
RX4PMT = Casper's Schreckensschule: Der gruselige Sporttag
|
RX4PMT = Casper's Schreckensschule: Der gruselige Sporttag
|
||||||
RXDD4Q = Disney Th!nk - Das Schnelldenker-Quiz
|
RXDD4Q = Disney Th!nk - Das Schnelldenker-Quiz
|
||||||
RXDX4Q = Disney Th!nk: Schnelldenkerquiz
|
RXDX4Q = Disney Th!nk: Schnelldenkerquiz
|
||||||
|
@ -292,7 +289,7 @@ S2ZP52 = Zhu Zhu Pets: Lustige Waldtiere
|
||||||
S3EP78 = Barbie: Fashionista Inc.
|
S3EP78 = Barbie: Fashionista Inc.
|
||||||
S3MP69 = Die Sims 3
|
S3MP69 = Die Sims 3
|
||||||
S3PP4Q = Disney Princess: Mein Märchenhaftes Abenteuer
|
S3PP4Q = Disney Princess: Mein Märchenhaftes Abenteuer
|
||||||
S5BPKM = Zurück in die Zukunft - Das Spiel
|
S5BPKM = Zurück in die Zukunft: Das Spiel
|
||||||
S5MPVZ = Monster High: Aller Anfang ist schwer
|
S5MPVZ = Monster High: Aller Anfang ist schwer
|
||||||
S6BP4Q = Merida - Legende der Highlands
|
S6BP4Q = Merida - Legende der Highlands
|
||||||
S6IP78 = Disney Prinzessin: Bezaubernde Geschichten
|
S6IP78 = Disney Prinzessin: Bezaubernde Geschichten
|
||||||
|
@ -301,7 +298,8 @@ S7BP69 = Trivial Pursuit: Wetten & Gewinnen
|
||||||
S7FPGT = Zumba Kids: Die ultimate Zumba tanz-party
|
S7FPGT = Zumba Kids: Die ultimate Zumba tanz-party
|
||||||
S7SP41 = Die Schlümpfe Party Pack
|
S7SP41 = Die Schlümpfe Party Pack
|
||||||
SA3P5G = Alvin und Die Chipmunks 3: Chip Brunch
|
SA3P5G = Alvin und Die Chipmunks 3: Chip Brunch
|
||||||
SALP4Q = Alice Im Wunderland
|
SA3XGT = Alvin und Die Chipmunks 3: Chip Brunch
|
||||||
|
SALP4Q = Alice im Wunderland
|
||||||
SAOP78 = Monster High: Monsterkrasse Highschool-Klasse!
|
SAOP78 = Monster High: Monsterkrasse Highschool-Klasse!
|
||||||
SAOXVZ = Monster High: Monsterkrasse Highschool-Klasse!
|
SAOXVZ = Monster High: Monsterkrasse Highschool-Klasse!
|
||||||
SAVX5G = Alvin und die Chipmunks 2: Ohren zu und durch
|
SAVX5G = Alvin und die Chipmunks 2: Ohren zu und durch
|
||||||
|
@ -317,7 +315,7 @@ SBVP78 = SpongeBob Schwammkopf: Volle Kanne Vollgas
|
||||||
SCIP41 = CSI: Tödliche Verschwörung
|
SCIP41 = CSI: Tödliche Verschwörung
|
||||||
SCJP4Q = LEGO Pirates of the Caribbean: Das Videospiel
|
SCJP4Q = LEGO Pirates of the Caribbean: Das Videospiel
|
||||||
SCRPJH = Chicken Riot: Die wilde Hühnerjagd
|
SCRPJH = Chicken Riot: Die wilde Hühnerjagd
|
||||||
SCUPFR = Moorhuhn - Jahrmarkt-Party
|
SCUPFR = Moorhuhn: Jahrmarkt-Party
|
||||||
SCWP41 = Mein Fitness-Coach: Dance Workout
|
SCWP41 = Mein Fitness-Coach: Dance Workout
|
||||||
SCYP4Q = Cars 2: Das Videospiel
|
SCYP4Q = Cars 2: Das Videospiel
|
||||||
SCYY4Q = Cars 2: Das Videospiel
|
SCYY4Q = Cars 2: Das Videospiel
|
||||||
|
@ -327,7 +325,7 @@ SDFP4Q = Disney Sing It: Filmhits
|
||||||
SDGP4Q = Disney Channel: All Star Party Games
|
SDGP4Q = Disney Channel: All Star Party Games
|
||||||
SDIP4Q = Disney Sing It: Pop Party
|
SDIP4Q = Disney Sing It: Pop Party
|
||||||
SDLP78 = Doods großes Abenteuer
|
SDLP78 = Doods großes Abenteuer
|
||||||
SDMPAF = Ich - Einfach Unverbesserlich
|
SDMPAF = Ich - Einfach unverbesserlich
|
||||||
SDPP54 = Dora - Das große Geburtstagsabenteuer
|
SDPP54 = Dora - Das große Geburtstagsabenteuer
|
||||||
SDUP41 = Die Schlümpfe: Dance Party
|
SDUP41 = Die Schlümpfe: Dance Party
|
||||||
SDWP18 = Der Schattenläufer und die Rätsel des dunklen Turms
|
SDWP18 = Der Schattenläufer und die Rätsel des dunklen Turms
|
||||||
|
@ -342,6 +340,7 @@ SFIP01 = Mystery Case Files: Der Fall Malgrave
|
||||||
SFPPFR = Fussball Fan Party
|
SFPPFR = Fussball Fan Party
|
||||||
SFRDRV = Fit for Fun
|
SFRDRV = Fit for Fun
|
||||||
SFRPXT = Fit for Fun
|
SFRPXT = Fit for Fun
|
||||||
|
SFWP69 = FIFA Fußball-Weltmeisterschaft Südafrika 2010
|
||||||
SFWX69 = FIFA Fussball-Weltmeisterschaft Südafrika 2010
|
SFWX69 = FIFA Fussball-Weltmeisterschaft Südafrika 2010
|
||||||
SFXPKM = X Factor
|
SFXPKM = X Factor
|
||||||
SFYPAF = Family Party 90
|
SFYPAF = Family Party 90
|
||||||
|
@ -360,7 +359,7 @@ SHDP52 = Drachenzähmen leicht gemacht
|
||||||
SHHP69 = Harry Potter und die Heiligtümer des Todes - Teil 1
|
SHHP69 = Harry Potter und die Heiligtümer des Todes - Teil 1
|
||||||
SHMPLR = Henry der Schreckliche
|
SHMPLR = Henry der Schreckliche
|
||||||
SHOXKR = Hugo - Zauberei im Trollwald
|
SHOXKR = Hugo - Zauberei im Trollwald
|
||||||
SIAP52 = Ice Age 4: Voll Verschoben - Die Arktischen Spiele
|
SIAP52 = Ice Age 4: Voll verschoben - Die arktischen Spiele
|
||||||
SIIP8P = Mario & Sonic bei den Olympischen Spielen London 2012
|
SIIP8P = Mario & Sonic bei den Olympischen Spielen London 2012
|
||||||
SIJP52 = iCarly 2: Ab in die Klicke!
|
SIJP52 = iCarly 2: Ab in die Klicke!
|
||||||
SJ2PWR = Scooby-Doo! und der Spuk im Sumpf
|
SJ2PWR = Scooby-Doo! und der Spuk im Sumpf
|
||||||
|
@ -376,7 +375,7 @@ SMFP4Q = Phineas und Ferb: Quer durch die 2. Dimension
|
||||||
SMGP78 = Megamind: Das Bündnis von Team Mega
|
SMGP78 = Megamind: Das Bündnis von Team Mega
|
||||||
SMJP52 = Monster Jam: Pfad der Zerstörung
|
SMJP52 = Monster Jam: Pfad der Zerstörung
|
||||||
SNYPVZ = Monster High: 13 Wünsche
|
SNYPVZ = Monster High: 13 Wünsche
|
||||||
SOBD7K = Bibi Blocksberg - Das große Hexenbesen-Rennen 2
|
SOBD7K = Bibi Blocksberg: Das große Hexenbesen-Rennen 2
|
||||||
SONDMR = Meine ersten Mitsing-Lieder
|
SONDMR = Meine ersten Mitsing-Lieder
|
||||||
SONFMR = Meine ersten Mitsing-Lieder
|
SONFMR = Meine ersten Mitsing-Lieder
|
||||||
SOSPAF = Turbo: Die Super-Stunt-Gang
|
SOSPAF = Turbo: Die Super-Stunt-Gang
|
||||||
|
@ -385,9 +384,11 @@ SP8P78 = Die Pinguine aus Madagaskar: Dr. Seltsam kehrt zurück
|
||||||
SPBPGT = Richtig Buchstabieren Party
|
SPBPGT = Richtig Buchstabieren Party
|
||||||
SPDP52 = Spider-Man: Dimensions
|
SPDP52 = Spider-Man: Dimensions
|
||||||
SPXP41 = Prince of Persia: Die Vergessene Zeit
|
SPXP41 = Prince of Persia: Die Vergessene Zeit
|
||||||
|
SQFPGT = Phineas und Ferb: Suche nach Super-Sachen
|
||||||
SQQPVZ = Disney Planes 2: Immer im Einsatz
|
SQQPVZ = Disney Planes 2: Immer im Einsatz
|
||||||
SQTPML = Das Duell - Männer vs. Frauen: Partyspaß Total!
|
SQTPML = Das Duell - Männer vs. Frauen: Partyspaß Total!
|
||||||
SR4P41 = Raving Rabbids: Die verrückte Zeitreise
|
SR4P41 = Raving Rabbids: Die verrückte Zeitreise
|
||||||
|
SR5P41 = Raving Rabbids: Party Collection
|
||||||
SRPP4Q = Disney Rapunzel: Neu verföhnt
|
SRPP4Q = Disney Rapunzel: Neu verföhnt
|
||||||
SRXP52 = Generator Rex: Providence Agent
|
SRXP52 = Generator Rex: Providence Agent
|
||||||
SS8P78 = SpongeBob Schwammkopf: verflixt und zugemalt
|
SS8P78 = SpongeBob Schwammkopf: verflixt und zugemalt
|
||||||
|
@ -397,7 +398,6 @@ SSCFWR = Scene It? Ganz großes Kino!
|
||||||
SSCIWR = Scene It? Ganz großes Kino!
|
SSCIWR = Scene It? Ganz großes Kino!
|
||||||
SSCPWR = Scene It? Ganz großes Kino!
|
SSCPWR = Scene It? Ganz großes Kino!
|
||||||
SSCSWR = Scene It? Ganz großes Kino!
|
SSCSWR = Scene It? Ganz großes Kino!
|
||||||
SSEDNG = We Sing Vol. 2
|
|
||||||
SSEPNG = We Sing Vol. 2
|
SSEPNG = We Sing Vol. 2
|
||||||
SSHPHH = Sherlock Holmes: Das Geheimnis des silbernen Ohrrings
|
SSHPHH = Sherlock Holmes: Das Geheimnis des silbernen Ohrrings
|
||||||
ST5P52 = Transformers: Mission auf Cybertron
|
ST5P52 = Transformers: Mission auf Cybertron
|
||||||
|
@ -412,43 +412,159 @@ SU5PVZ = Monster High: Labyrinth-Skaten
|
||||||
SU7PAF = Die Hüter des Lichts
|
SU7PAF = Die Hüter des Lichts
|
||||||
SV3PAF = Madagascar 3: Flucht durch Europa
|
SV3PAF = Madagascar 3: Flucht durch Europa
|
||||||
SV7PVZ = Die Pinguine aus Madagascar
|
SV7PVZ = Die Pinguine aus Madagascar
|
||||||
SVDP52 = Spongebob Schwammkopf: Planktons Fiese Robo-Rache
|
SVDP52 = SpongeBob Schwammkopf: Planktons Fiese Robo-Rache
|
||||||
SVMP01 = Super Mario All-Stars: 25 Jahre Jubiläumsedition
|
SVMP01 = Super Mario All-Stars: 25 Jahre Jubiläumsedition
|
||||||
|
SVQEVZ = Barbie und ihre Schwestern: Die Rettung der Welpen
|
||||||
SVQPVZ = Barbie und ihre Schwestern: Die Rettung der Welpen
|
SVQPVZ = Barbie und ihre Schwestern: Die Rettung der Welpen
|
||||||
SVVPAF = Die Croods: Steinzeit Party!
|
SVVPAF = Die Croods: Steinzeit Party!
|
||||||
SW3PKM = Eurosport Winter Stars
|
SW3PKM = Eurosport Winter Stars
|
||||||
CS4P00 = SingItStar NRJ Music Tour
|
CS4P00 = SingItStar NRJ Music Tour
|
||||||
|
RMCPCA = Mario Kart Wii (Katalanische Übersetzung)
|
||||||
SDNP01 = New SUPER DODO BROS wii
|
SDNP01 = New SUPER DODO BROS wii
|
||||||
SIS1OH = SingItStar Custom: Volume 1
|
SIS1OH = SingItStar Custom: Volume 1
|
||||||
SISACD = SingItStar AC/DC
|
SISACD = SingItStar AC/DC
|
||||||
SISPOH = SingItStar Custom: Party
|
SISPOH = SingItStar Custom: Party
|
||||||
W2CP = Gehirntraining
|
W2CP = Gehirntraining
|
||||||
|
W2FP = Physiofun - Balance Training
|
||||||
|
W2GD = Phoenix Wright Ace Attorney: Justice for All (Deutsche Version)
|
||||||
|
W2GP = Phoenix Wright Ace Attorney: Justice for All
|
||||||
|
W2MP = Blaster Master: Overdrive
|
||||||
W2PP = Physiofun - Beckenboden Training
|
W2PP = Physiofun - Beckenboden Training
|
||||||
|
W3GD = Phoenix Wright Ace Attorney 3: Trials And Tribulations
|
||||||
|
W3KP = ThruSpace: High Velocity 3D Puzzle
|
||||||
W3MP = Die Drei Musketiere Einer für alle!
|
W3MP = Die Drei Musketiere Einer für alle!
|
||||||
|
W4AP = Arcade Sports: Air Hockey, Bowling, Pool, Snooker
|
||||||
|
W6BP = Eco-Shooter: Plant 530
|
||||||
|
W72P = Successfully Learning German Year 3
|
||||||
W73P = Lernerfolg Grundschule Deutsch Klasse 4
|
W73P = Lernerfolg Grundschule Deutsch Klasse 4
|
||||||
W74P = Lernerfolg Grundschule Deutsch Klasse 5
|
W74P = Lernerfolg Grundschule Deutsch Klasse 5
|
||||||
W7IP = Lernerfolg Grundschule Deutsch Klasse 2
|
W7IP = Lernerfolg Grundschule Deutsch Klasse 2
|
||||||
|
W8CP = Bit.Trip Core
|
||||||
W8WP = Happy Holidays Halloween
|
W8WP = Happy Holidays Halloween
|
||||||
|
W9BP = Big Town Shoot
|
||||||
W9RP = Happy Holidays Christmas
|
W9RP = Happy Holidays Christmas
|
||||||
|
WA4P = WarioWare: Do It Yourself - Showcase
|
||||||
|
WA7P = Toribash Violence Perfected
|
||||||
|
WA8P = Art Style: Penta Tentacles
|
||||||
|
WAEP = Around the world
|
||||||
|
WAFP = Airport Mania: First Flight
|
||||||
|
WAHP = Trenches: Generals
|
||||||
|
WALP = Art Style: light trax
|
||||||
|
WAOP = The Very Hungry Caterpillar´s ABC
|
||||||
|
WB2P = Strong Bad Episode 4: Dangeresque 3
|
||||||
|
WB3P = Strong Bad Episode 5: 8-bit is Enough
|
||||||
|
WBEP = Beer Pong: Frat Party Games
|
||||||
|
WBFP = Bit.Trip Fate
|
||||||
|
WBGP = Bang Attack
|
||||||
|
WBPP = PLÄTTCHEN - twist 'n' paint
|
||||||
|
WBRP = Pirates: The Key of Dreams
|
||||||
|
WBXP = Strong Bad Episode 1: Homestar Ruiner
|
||||||
|
WBYP = Strong Bad Episode 2: Strong Badia - The Free
|
||||||
|
WBZP = Strong Bad Episode 3: Baddest of the Bands
|
||||||
|
WCHP = Chess Challenge
|
||||||
|
WCJP = Cocoto: Platform Jumper
|
||||||
|
WCKP = chick chick BOOM
|
||||||
|
WCSP = CueSports: Snooker vs Billiards
|
||||||
|
WD9P = Castlevania: The Adventure ReBirth
|
||||||
|
WDEP = Magic Destiny Astrological Games
|
||||||
|
WDFP = Defend your Castle
|
||||||
|
WDHP = Art Style: ROTOHEX
|
||||||
WDMP = Dr. Mario & Bazillenjagd
|
WDMP = Dr. Mario & Bazillenjagd
|
||||||
|
WDPP = Dr. Mario & Germ Buster (Friend Battle Demo)
|
||||||
|
WEMP = Aha! I Got It! Escape Game
|
||||||
WETP = Bilderbuch-Spiele: Ein Abenteuer zum Aufklappen
|
WETP = Bilderbuch-Spiele: Ein Abenteuer zum Aufklappen
|
||||||
WF2P = FFCC: My Life as a Darklord
|
WF2P = FFCC: My Life as a Darklord
|
||||||
|
WF4P = Final Fantasy IV: The After Years
|
||||||
WFCP = FFCC: My Life as a King
|
WFCP = FFCC: My Life as a King
|
||||||
|
WFQP = Frogger: Hyper Arcade Edition
|
||||||
|
WFTP = Fish'em All!
|
||||||
|
WFVP = Football Up
|
||||||
|
WFWP = Flowerworks: Follie's Adventure
|
||||||
|
WFYP = Family Games Pen & Paper Edition
|
||||||
|
WGDP = Gradius Rebirth
|
||||||
WGFP = Girlfriends Forever Magic Skate
|
WGFP = Girlfriends Forever Magic Skate
|
||||||
|
WGGP = Gabrielle's Ghostly Groove: Monster Mix
|
||||||
WGPP = Zenquaria Virtuelles Aquarium
|
WGPP = Zenquaria Virtuelles Aquarium
|
||||||
|
WGSD = Phoenix Wright: Ace Attorney (Deutsche Version)
|
||||||
|
WGSF = Phoenix Wright: Ace Attorney (French Version)
|
||||||
|
WGSP = Phoenix Wright: Ace Attorney
|
||||||
|
WHEE = Heracles: Chariot Racing
|
||||||
|
WHEP = Heracles: Chariot Racing
|
||||||
|
WHFP = Heavy Fire: Special Operations
|
||||||
|
WHRP = Heron: Steam Machine
|
||||||
WHUP = Geisterhaus-Partyschreck
|
WHUP = Geisterhaus-Partyschreck
|
||||||
|
WHWP = HoopWorld: BasketBrawl
|
||||||
|
WICP = NyxQuest: Kindred Spirits
|
||||||
|
WIDP = Dracula: Undead Awakening
|
||||||
|
WIEP = Tales of Monkey Island Chapter 3: Lair of the Leviathan
|
||||||
|
WILP = Tales of Monkey Island Chapter 1: Launch of the Screaming Narwhal
|
||||||
WINP = Das Verrückte Labyrinth
|
WINP = Das Verrückte Labyrinth
|
||||||
|
WIRP = Tales of Monkey Island Chapter 5: Rise Of The Pirate God
|
||||||
|
WISP = Tales of Monkey Island Chapter 2: The Siege of Spinner Cay
|
||||||
|
WITP = Aha! I Found It! Hidden Object Game
|
||||||
|
WIYP = Tales of Monkey Island Chapter 4: The Trial and Execution of Guybrush Threepwood
|
||||||
|
WJKP = Jewel Keepers: Easter Island
|
||||||
|
WKBP = You, Me and the Cubes
|
||||||
WKFP = Kung Fu Funk - Everybody Is Kung Fu Fighting
|
WKFP = Kung Fu Funk - Everybody Is Kung Fu Fighting
|
||||||
|
WKKP = Pop-Up Pirates!
|
||||||
|
WKRP = Karate Phants: Gloves of Glory
|
||||||
|
WKWP = Adventure on LOST ISLAND: Hidden Object Game
|
||||||
WLEE = Lernen mit den PooYoos: Teil 1
|
WLEE = Lernen mit den PooYoos: Teil 1
|
||||||
WLEP = Lernen mit den PooYoos: Teil 1
|
WLEP = Lernen mit den PooYoos: Teil 1
|
||||||
WLNE = Lernen mit den PooYoos: Teil 2
|
WLNE = Lernen mit den PooYoos: Teil 2
|
||||||
WLNP = Lernen mit den PooYoos: Teil 2
|
WLNP = Lernen mit den PooYoos: Teil 2
|
||||||
|
WLOP = LostWinds: Winter of the Melodias
|
||||||
|
WLZP = lilt line
|
||||||
|
WM7P = Anima Ark of Sinners
|
||||||
WMBP = MaBoShi: Drei-Formen-Action
|
WMBP = MaBoShi: Drei-Formen-Action
|
||||||
WMCP = Monsteca Corral - Monsters Vs. Robots
|
WMCP = Monsteca Corral - Monsters Vs. Robots
|
||||||
WMJP = Dive - The Medes Islands Secret
|
WMSP = Enjoy your massage!
|
||||||
|
WN9E = Military Madness: Nectaris
|
||||||
|
WN9P = Military Madness: Nectaris
|
||||||
|
WNEE = Penguins & Friends Hey! That's My Fish!
|
||||||
|
WNEP = Penguins & Friends Hey! That’s my Fish!
|
||||||
|
WNVP = Neves Plus: Phantheon of Tangrams
|
||||||
|
WOBP = Art Style: ORBIENT
|
||||||
|
WOTP = Overturn: Mecha Wars
|
||||||
|
WP3P = Pearl Harbor Trilogy 1941: Red Sun Rising
|
||||||
|
WP4P = Learning with the PooYoos: Episode 3
|
||||||
WPJP = Pucca – Mission: Küsse
|
WPJP = Pucca – Mission: Küsse
|
||||||
WPVP = The Tales of Bearsworth Manor - Chaotic Conflicts
|
WPKP = Texas Hold'Em Poker
|
||||||
WZZP = The Tales of Bearsworth Manor - Puzzling Pages
|
WPQP = Protöthea
|
||||||
|
WPRP = Art Style: CUBELLO
|
||||||
|
WPVE = The Tales of Bearsworth Manor: Chaotic Conflicts
|
||||||
|
WREP = Racers Islands Crazy Arenas
|
||||||
|
WRIP = Rainbow Islands: Towering Adventure!
|
||||||
|
WRJP = Racers Islands - Crazy Racers
|
||||||
|
WRLP = FAST Racing League
|
||||||
|
WRRP = Robin Hood: The Return Of Richard
|
||||||
|
WRUP = Bit.Trip Runner
|
||||||
|
WSGP = Pop Them, Drop Them SAMEGAME
|
||||||
|
WSNP = Sonic The Hedgehog 4 Episode I
|
||||||
|
WSUP = Shootanto: Evolutionary Mayhem
|
||||||
|
WTEP = Tales of Elastic Boy Mission 1
|
||||||
|
WTFP = Bit.Trip Flux
|
||||||
|
WTMP = Adventure Island: The Beginning
|
||||||
|
WTRP = Bit.Trip Beat
|
||||||
|
WTWP = Fenimore Fillmore: The Westerner
|
||||||
|
WTXP = Texas Hold’em Tournament
|
||||||
|
WU2P = Successfully Learning Mathematics Year 3
|
||||||
|
WU3P = Successfully Learning Mathematics Year 4
|
||||||
|
WU4P = Successfully Learning Mathematics Year 5
|
||||||
|
WUIP = Successfully Learning Mathematics Year 2
|
||||||
|
WVBP = Bit.Trip Void
|
||||||
|
WVOP = Rock'n Roll Climber
|
||||||
|
WVSP = Gods Vs Humans
|
||||||
|
WVUP = Mr Bumblebee Racing Champion
|
||||||
|
WW2P = Where's Wally? Fantastic Journey 2
|
||||||
|
WW3P = Where's Wally? Fantastic Journey 3
|
||||||
|
WWIP = Where's Wally? Fantastic Journey 1
|
||||||
|
WWRP = Excitebike: World Challenge
|
||||||
|
WWXP = Paper Wars Cannon Fodder
|
||||||
|
WXBP = Ben 10: Alien Force - The Rise of Hex
|
||||||
|
WYIP = escapeVektor: Chapter 1
|
||||||
|
WYSP = Yard Sale Hidden Treasures Sunnyville
|
||||||
|
WZIP = Rubik's Puzzle Galaxy: RUSH
|
||||||
XIBP = Fish em All Demo
|
XIBP = Fish em All Demo
|
||||||
XICP = Gods vs Humans Demo
|
XICP = Gods vs Humans Demo
|
||||||
XIDP = Racers Islands Crazy Racers Demo
|
XIDP = Racers Islands Crazy Racers Demo
|
||||||
|
@ -464,8 +580,121 @@ XIUP = Soccer Bashi Demo
|
||||||
XIVP = Mix Superstar Demo
|
XIVP = Mix Superstar Demo
|
||||||
XIZP = 3D Pixel Racing Demo
|
XIZP = 3D Pixel Racing Demo
|
||||||
XJEP = Aya and the Cubes of Light Demo
|
XJEP = Aya and the Cubes of Light Demo
|
||||||
|
FA9P = Zelda II: The Adventure of Link
|
||||||
|
FB2L = Super Mario Bros.: The Lost Levels
|
||||||
|
FBKP = Teenage Mutant Ninja Turles
|
||||||
|
FC8P = Castlevania II: Simon's Quest
|
||||||
|
FCSP = Probotector II: Return of the Evil Forces
|
||||||
|
FDGP = Ghosts'n Goblins
|
||||||
|
FDRP = Skate or Die
|
||||||
|
FEML = Bio Miracle Bokutte UPA
|
||||||
|
FEQP = Castlevania III Dracula's Curse
|
||||||
|
FERM = Startropics II: Zoda's Revenge
|
||||||
|
FF5P = Double Dragon II: The Revenge
|
||||||
|
FFEP = A Boy and His Blob: Trouble on Blobolonia
|
||||||
|
FFPP = Ufouria: THE SAGA
|
||||||
|
FFUP = Adventure Island 2
|
||||||
|
FFVM = S.C.A.T.: Special Cybernetic Attack Team
|
||||||
|
JA4P = Super Ghouls'n Ghosts
|
||||||
|
JABL = Mario’s Super Picross
|
||||||
|
JADD = The Legend of Zelda: A Link to the Past
|
||||||
|
JADE = The Legend of Zelda: A Link to the Past
|
||||||
|
JADF = The Legend of Zelda: A Link to the Past
|
||||||
|
JAFD = SimCity
|
||||||
|
JAHP = R-TYPE III: The Third Lightning
|
||||||
|
JAJP = Street Fighter II: The World Warrior
|
||||||
|
JALP = Super Probotector: Alien Rebels
|
||||||
|
JAZD = The Legend of the Mystical Ninja
|
||||||
|
JBBP = Super Street Fighter II: The New Challengers
|
||||||
|
JBDD = Donkey Kong Country 2: Diddy's Kong-Quest
|
||||||
|
JBDE = Donkey Kong Country 2: Diddy's Kong Quest
|
||||||
|
JBIP = Street Fighter II Turbo: Hyper Fighting
|
||||||
|
JBPP = Donkey Kong Country 3: Dixie Kong’s Double Trouble
|
||||||
|
JCAL = DoReMi Fantasy - Milon’s DokiDoki Adventure
|
||||||
|
JCBM = Super Mario RPG: Legend of the Seven Stars
|
||||||
|
JCCP = Kirby’s Fun Pak
|
||||||
|
JCDM = Kirby’s Dream Land 3
|
||||||
|
JCJP = Super Punch Out!!
|
||||||
|
JCKP = Space Invaders -The Original Game-
|
||||||
|
JCTM = Ogre Battle: The March of the Black Queen
|
||||||
|
JD3P = SUPER E.D.F.: Earth Defense Force
|
||||||
|
JD8E = Super Adventure Island II
|
||||||
|
JDJP = Super Star Wars: The Empire Strikes Back
|
||||||
|
JDLP = Super Star Wars: Return of the Jedi
|
||||||
|
JDWP = Aero The Acrobat
|
||||||
|
JDZD = Mystic Quest Legend
|
||||||
|
NACE = The Legend of Zelda: Ocarina of Time
|
||||||
|
NACP = The Legend of Zelda: Ocarina of Time
|
||||||
NADE = Lylat wars
|
NADE = Lylat wars
|
||||||
|
NAJN = Sin and Punishment
|
||||||
|
NAKS = Pokémon Snap
|
||||||
|
NAME = Kirby 64: The Crystal Shards
|
||||||
|
NAMP = Kirby 64: The Crystal Shards
|
||||||
|
NAND = Pokémon Puzzle League
|
||||||
|
NAOE = 1080° Snowboarding
|
||||||
|
NAOP = 1080°: TenEighty Snowboarding
|
||||||
|
NARE = The Legend of Zelda: Majora's Mask
|
||||||
|
NARP = The Legend of Zelda: Majora's Mask
|
||||||
|
NAYE = Ogre Battle 64: Person of Lordly Caliber
|
||||||
|
NAYM = Ogre Battle 64: Person of Lordly Caliber
|
||||||
|
LALP = Fantasy Zone II
|
||||||
|
LANP = Alex Kidd: The Lost Stars
|
||||||
|
LAPP = Wonder Boy III: The Dragon's Trap
|
||||||
|
MA8P = Ecco: The Tides of Time
|
||||||
|
MAHP = Sonic the Hedgehog
|
||||||
|
MALP = Bonanza Bros.
|
||||||
|
MAOP = Bio-Hazard Battle
|
||||||
|
MAVP = Wonder Boy In Monster World
|
||||||
|
MAXP = Alex Kidd In The Enchanted Castle
|
||||||
|
MB6P = Shining Force II
|
||||||
|
MBBP = Sonic the Hedgehog 2
|
||||||
|
MBFP = Shinobi III: Return of the Ninja master
|
||||||
MBIP = Landstalker: Die Schätze von König Nolo
|
MBIP = Landstalker: Die Schätze von König Nolo
|
||||||
|
MBJP = Ghouls'n Ghosts
|
||||||
|
MBLP = ESWAT City Under Siege
|
||||||
|
MBMP = Sonic the Hedgehog 3
|
||||||
|
MBUP = Sonic 3D: Flickies' Island
|
||||||
|
MBWM = Columns III: Revenge of Columns
|
||||||
|
MC3P = Super Street Fighter II: The New Challengers
|
||||||
|
MCCP = Phantasy Star III: Generations of Doom
|
||||||
|
MCHM = MUSHA
|
||||||
|
MCLP = Street Fighter II’: Special Champion Edition
|
||||||
|
MCQP = Boogerman - A Pick and Flick Adventure
|
||||||
|
MCRP = Wolf of the Battlefield: MERCS
|
||||||
|
MCSP = Wonder Boy III: Monster Lair
|
||||||
|
MCVP = Pitfall: The Mayan Adventure
|
||||||
|
MCZP = Shanghai II Dragon's Eye
|
||||||
|
PAAP = Bomberman'93
|
||||||
|
PAGL = Bomberman'94
|
||||||
|
PARL = Detana Twin Bee
|
||||||
|
PAWP = Galaga'90
|
||||||
|
PBEP = Motoroader
|
||||||
|
PBIP = Bonk III: Bonk's Big Adventure
|
||||||
|
PBSP = Chew Man Fu
|
||||||
|
PBWP = Air 'Zonk'
|
||||||
|
PCSL = Digital Champ: Battle Boxing
|
||||||
|
PDJL = Street Fighter II': Champion Edition
|
||||||
|
QA3P = SimEarth: The Living Planet
|
||||||
|
QAAP = Super Air Zonk
|
||||||
|
QABP = Ys Book I & II
|
||||||
|
QADL = Gradius II: Gofer no Yabou
|
||||||
|
QAPL = Castlevania: Rondo of Blood
|
||||||
|
EA5P = Fatal Fury 3: Road To The Final Victory
|
||||||
|
EA7P = Samurai Shodown IV: Amakusa's Revenge
|
||||||
|
EA8M = Iron Clad
|
||||||
|
EAIP = Top Hunter
|
||||||
|
EBDP = Magical Drop 3
|
||||||
|
EBFP = Spin master
|
||||||
|
EBSP = The Path of the Warrior: Art of Fighting 3
|
||||||
|
ECAP = Real Bout Fatal Fury 2: The Newcomers
|
||||||
|
ECGP = Shock Troopers: 2nd Squad
|
||||||
|
E54P = GHOSTS'N GOBLINS
|
||||||
|
E55P = Commando
|
||||||
|
E57P = SonSon
|
||||||
|
E6PP = NINJA GAIDEN
|
||||||
|
C93P = The Last Ninja 2
|
||||||
|
C96P = Summer Games 2
|
||||||
|
C9IP = Cybernoid
|
||||||
HAAA = Fotokanal
|
HAAA = Fotokanal
|
||||||
HABA = Wii-Shop-Kanal
|
HABA = Wii-Shop-Kanal
|
||||||
HACA = Mii-Kanal
|
HACA = Mii-Kanal
|
||||||
|
@ -473,10 +702,25 @@ HACK = Mii-Kanal
|
||||||
HADE = Internet Kanal
|
HADE = Internet Kanal
|
||||||
HADP = Internet-Kanal
|
HADP = Internet-Kanal
|
||||||
HAFP = Wetterkanal
|
HAFP = Wetterkanal
|
||||||
|
HAGA = Nachrichtenkanal
|
||||||
HAGE = Nachrichtenkanal
|
HAGE = Nachrichtenkanal
|
||||||
|
HAGJ = Nachrichtenkanal
|
||||||
HAGP = Nachrichtenkanal
|
HAGP = Nachrichtenkanal
|
||||||
|
HAJP = Meinungskanal
|
||||||
HAPP = Mii-Wettbewerbskanal
|
HAPP = Mii-Wettbewerbskanal
|
||||||
|
HATP = Nintendo-Kanal
|
||||||
|
HAVP = Glückstagskanal
|
||||||
|
HAWP = Metroid Prime 3 Preview
|
||||||
HAYA = Fotokanal
|
HAYA = Fotokanal
|
||||||
|
HCAP = Jam with the Band Live
|
||||||
|
HCFE = Wii Speak-Kanal
|
||||||
|
HCFP = Wii Speak-Kanal
|
||||||
|
HCMP = Kirby TV-Kanal
|
||||||
|
HCRE = The Legend of Zelda: Skyward Sword - Speicherdaten-Update-Kanal für
|
||||||
|
HCRP = The Legend of Zelda: Skyward Sword - Speicherdaten-Update-Kanal für
|
||||||
|
RMCP = Mario Kart-Kanal
|
||||||
|
OHBC = Homebrew-Kanal
|
||||||
|
G2FD78 = Tak 2: Der Stab der Träume
|
||||||
G3AD69 = Der Herr der Ringe: Das dritte Zeitalter
|
G3AD69 = Der Herr der Ringe: Das dritte Zeitalter
|
||||||
G3DX6L = Carmen Sandiego: Das Geheimnis der gestohlenen Trommeln
|
G3DX6L = Carmen Sandiego: Das Geheimnis der gestohlenen Trommeln
|
||||||
G3MP41 = Der Anschlag
|
G3MP41 = Der Anschlag
|
||||||
|
@ -484,34 +728,35 @@ G4CP54 = Charlie und die Schokoladen-fabrik
|
||||||
G4MP69 = Die Sims: Brechen Aus
|
G4MP69 = Die Sims: Brechen Aus
|
||||||
G4OP69 = Die Sims 2: Haustiere
|
G4OP69 = Die Sims 2: Haustiere
|
||||||
G4ZP69 = Die Sims 2
|
G4ZP69 = Die Sims 2
|
||||||
G6FD69 = FIFA Fussball-Weltmeisterschaft 2006
|
G6FD69 = FIFA Fußball-Weltmeisterschaft Deutschland 2006
|
||||||
G8MP01 = Paper Mario: Die Legende Vom Äonentor
|
G8MP01 = Paper Mario: Die Legende vom Äonentor
|
||||||
G9TD52 = Grosse Haie: Kleine Fische
|
G9TD52 = Grosse Haie: Kleine Fische
|
||||||
GAZD69 = Harry Potter und der Gefangene von Askaban
|
GAZD69 = Harry Potter und der Gefangene von Askaban
|
||||||
GC3D78 = Scooby-Doo!: Fluch der Folianten
|
GC3D78 = Scooby-Doo! Fluch der Folianten
|
||||||
GCBP7D = Crash Bandicoot: Der Zorn Des Cortex
|
GCBP7D = Crash Bandicoot: Der Zorn des Cortex
|
||||||
GCGP41 = 3 Engel Für Charlie: Volle Power
|
GCGP41 = 3 Engel Für Charlie: Volle Power
|
||||||
GCIP69 = Die Sims
|
GCIP69 = Die Sims
|
||||||
GCQD7D = Buffy im Bann der Dämonen: Chaos Bleeds
|
GCQD7D = Buffy im Bann der Dämonen: Chaos Bleeds
|
||||||
GDKPA4 = Disney´s Sports Fußball
|
GDIX7D = Die Hard - Stirb Langsam: Vendetta
|
||||||
GDOP41 = Disney's Donald Duck Phantomias: Platyrhynchos Kineticus
|
GDKPA4 = Disney Sports: Fußball
|
||||||
GEND69 = James Bond 007: Alles Oder Nichts
|
GDOP41 = Disneys Donald Duck: Phantomias - Platyrhynchos Kineticus
|
||||||
|
GEND69 = James Bond 007: Alles oder Nichts
|
||||||
GENP69 = 007: Alles Oder Nichts
|
GENP69 = 007: Alles Oder Nichts
|
||||||
GF4D52 = Die Fantastischen Vier
|
GF4D52 = Die Fantastischen Vier
|
||||||
GFAD69 = FIFA Football 2003
|
GFHP6V = Böse Nachbarn
|
||||||
GFSD69 = FIFA Fussball Weltmeisterschaft 2002
|
GFSD69 = FIFA Fußball-Weltmeisterschaft 2002
|
||||||
GGVD78 = Der SpongBob Schwammkopf Film
|
GGVD78 = SpongBob Schwammkopf: Der Film
|
||||||
GH4D69 = Harry Potter und der Feuerkelch
|
GH4D69 = Harry Potter und der Feuerkelch
|
||||||
GH5D52 = Ab Durch Die Hecke
|
GH5D52 = Ab Durch Die Hecke
|
||||||
GHBP7D = Der Hobbit
|
GHBP7D = Der Hobbit
|
||||||
GHCD4Q = Himmel und Huhn
|
GHCD4Q = Himmel und Huhn
|
||||||
GHLY69 = Harry Potter und der Stein der Weisen
|
GHLY69 = Harry Potter und der Stein der Weisen
|
||||||
GHSY69 = Harry Potter Und Die Kammer Des Schreckens
|
GHSY69 = Harry Potter und die Kammer des Schreckens
|
||||||
GHVP08 = Disney's Tricky Micky
|
GHVP08 = Disney's Tricky Micky
|
||||||
GIAP7D = Ice Age 2 : Jetzt Taut's
|
GIAP7D = Ice Age 2: Jetzt Taut's
|
||||||
GICD78 = Die Unglaublichen
|
GICD78 = Die Unglaublichen
|
||||||
GIHD78 = Scooby-Doo! Nacht der 100 Schrecken
|
GIHD78 = Scooby-Doo! Nacht der 100 Schrecken
|
||||||
GIQY78 = Die Unglaublichen: Der Angriff Des Tunnelgräbers
|
GIQY78 = Die Unglaublichen: Der Angriff des Tunnelgräbers
|
||||||
GJND78 = Jimmy Neutron: Der mutige Erfinder
|
GJND78 = Jimmy Neutron: Der mutige Erfinder
|
||||||
GJUD78 = Tak und die Macht des Juju
|
GJUD78 = Tak und die Macht des Juju
|
||||||
GKBPAF = Baten Kaitos: Die Schwingen der Ewigkeit und der verlorene Ozean
|
GKBPAF = Baten Kaitos: Die Schwingen der Ewigkeit und der verlorene Ozean
|
||||||
|
@ -521,8 +766,9 @@ GL5X4F = Lego Star Wars : Das Videospiel
|
||||||
GL7P64 = LEGO Star Wars II: Die klassische Trilogie
|
GL7P64 = LEGO Star Wars II: Die klassische Trilogie
|
||||||
GLCD52 = Lemony Snicket: Rätselhafte Ereignisse
|
GLCD52 = Lemony Snicket: Rätselhafte Ereignisse
|
||||||
GLHPG9 = Flutsch und weg
|
GLHPG9 = Flutsch und weg
|
||||||
GLOD69 = Der Herr Der Ringe: Die Zwei Türme
|
GLOD69 = Der Herr der Ringe: Die zwei Türme
|
||||||
GLVD4Q = Die Chroniken von Narnia: Der König von Narnia
|
GLVD4Q = Die Chroniken von Narnia: Der König von Narnia
|
||||||
|
GLVP4Q = Die Chroniken von Narnia: Der König von Narnia
|
||||||
GLZD69 = 007: Liebesgrüsse aus Moskau
|
GLZD69 = 007: Liebesgrüsse aus Moskau
|
||||||
GMNP78 = Die Monster AG : Monster Ball
|
GMNP78 = Die Monster AG : Monster Ball
|
||||||
GNED78 = Findet Nemo
|
GNED78 = Findet Nemo
|
||||||
|
@ -533,8 +779,12 @@ GPHD52 = Pitfall: Die verlorene Expedition
|
||||||
GPLD9G = Disney's Ferkels Grosses Abenteuer - Spiel
|
GPLD9G = Disney's Ferkels Grosses Abenteuer - Spiel
|
||||||
GPQP6L = The Powerpuff Girls: Kampf den Gurkenschurken
|
GPQP6L = The Powerpuff Girls: Kampf den Gurkenschurken
|
||||||
GPXP01 = Pokémon Box: Rubin & Saphir
|
GPXP01 = Pokémon Box: Rubin & Saphir
|
||||||
GQ4D78 = SpongeBob Schwammkopf: Die Kreatur aus der krossen Krabbe
|
GQ4D78 = SpongeBob Schwammkopf: Die Kreatur aus der Krossen Krabbe
|
||||||
GQQD78 = Nickelodeon SpongeBob Schwammkopf: Film ab!
|
GQQD78 = SpongeBob Schwammkopf: Film ab!
|
||||||
|
GQQE78 = SpongeBob Schwammkopf: Film ab!
|
||||||
|
GQQF78 = SpongeBob Schwammkopf: Film ab!
|
||||||
|
GQQH78 = SpongeBob Schwammkopf: Film ab!
|
||||||
|
GQQP78 = SpongeBob Schwammkopf: Film ab!
|
||||||
GQWX69 = Harry Potter: Quidditch - Weltmeisterschaft
|
GQWX69 = Harry Potter: Quidditch - Weltmeisterschaft
|
||||||
GR9P6L = Die Herrschaft Des Feuers
|
GR9P6L = Die Herrschaft Des Feuers
|
||||||
GSKP7D = The Scorpion King : Aufstieg des Akkadiers
|
GSKP7D = The Scorpion King : Aufstieg des Akkadiers
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
||||||
TITLES = https://www.gametdb.com (type: Wii language: FR_unique version: 20191106234238)
|
TITLES = https://www.gametdb.com (type: Wii language: FR_unique version: 20230727194148)
|
||||||
R22J01 = FlingSmash
|
R22J01 = FlingSmash
|
||||||
R23P52 = Barbie et les Trois Mousquetaires
|
R23P52 = Barbie et les Trois Mousquetaires
|
||||||
R25PWR = LEGO Harry Potter : Années 1 à 4
|
R25PWR = LEGO Harry Potter : Années 1 à 4
|
||||||
|
@ -28,13 +28,11 @@ R3YP70 = Sam & Max : Saison 2 : Au-Delà du Temps et de l'Espace
|
||||||
R42P69 = Les Sims 2 : Naufragés
|
R42P69 = Les Sims 2 : Naufragés
|
||||||
R43P69 = EA Sports Active
|
R43P69 = EA Sports Active
|
||||||
R48P7D = Les Chroniques De Spiderwick
|
R48P7D = Les Chroniques De Spiderwick
|
||||||
R49P01 = Donkey Kong : Jungle Beat
|
|
||||||
R4BPGT = Baby Foot
|
R4BPGT = Baby Foot
|
||||||
R4EP01 = Endless Ocean 2 : Aventuriers des Fonds Marins
|
R4EP01 = Endless Ocean 2 : Aventuriers des Fonds Marins
|
||||||
R4PP69 = Les Sims 2 : Animaux & Cie
|
R4PP69 = Les Sims 2 : Animaux & Cie
|
||||||
R4ZJ01 = Project Zero 4 - Mask of the Lunar Eclipse
|
R4ZJ01 = Project Zero 4 - Mask of the Lunar Eclipse
|
||||||
R54FMR = Des Chiffres & des Lettres
|
R54FMR = Des Chiffres & des Lettres
|
||||||
R55F41 = Qui Veut Gagner Des Millions : 1ère Edition
|
|
||||||
R55P41 = Qui Veut Gagner Des Millions : 1ère Edition
|
R55P41 = Qui Veut Gagner Des Millions : 1ère Edition
|
||||||
R57FMR = Questions pour un champion : Le jeu officiel
|
R57FMR = Questions pour un champion : Le jeu officiel
|
||||||
R5AP8P = À la Croisée des Mondes : La Boussole d'Or
|
R5AP8P = À la Croisée des Mondes : La Boussole d'Or
|
||||||
|
@ -48,6 +46,7 @@ R5TP69 = Grand Chelem Tennis
|
||||||
R5UP41 = Les Experts: Préméditation
|
R5UP41 = Les Experts: Préméditation
|
||||||
R5VP41 = James Cameron's Avatar : The Game
|
R5VP41 = James Cameron's Avatar : The Game
|
||||||
R5VX41 = James Cameron's Avatar : The Game
|
R5VX41 = James Cameron's Avatar : The Game
|
||||||
|
R5XJ13 = MySims Agents
|
||||||
R5YD78 = All Star Pom Pom Girl 2
|
R5YD78 = All Star Pom Pom Girl 2
|
||||||
R5YP78 = All Star Pom Pom Girl 2
|
R5YP78 = All Star Pom Pom Girl 2
|
||||||
R62P4Q = Disney Sing It : Pop Hits
|
R62P4Q = Disney Sing It : Pop Hits
|
||||||
|
@ -81,7 +80,6 @@ R8RP41 = Arthur et la Vengeance de Maltazard
|
||||||
R8SP41 = Vacances Sports Party
|
R8SP41 = Vacances Sports Party
|
||||||
R8UXMR = Adibou et les saisons magiques
|
R8UXMR = Adibou et les saisons magiques
|
||||||
R8VP41 = Planète Nature : Au Secours des Animaux Sauvages
|
R8VP41 = Planète Nature : Au Secours des Animaux Sauvages
|
||||||
R92P01 = Nouvelle Façon de Jouer ! Pikmin 2
|
|
||||||
R94PMR = Total Dérapage
|
R94PMR = Total Dérapage
|
||||||
R94XMR = Total Dérapage : Prêts pour le Grand Frisson ?
|
R94XMR = Total Dérapage : Prêts pour le Grand Frisson ?
|
||||||
R9BPMT = Bob le bricoleur : On s'amuse comme des fous
|
R9BPMT = Bob le bricoleur : On s'amuse comme des fous
|
||||||
|
@ -93,6 +91,7 @@ R9IP01 = Nouvelle Façon de Jouer ! Pikmin
|
||||||
R9JP69 = The Beatles : Rock Band
|
R9JP69 = The Beatles : Rock Band
|
||||||
R9LP41 = Girls Life: Pyjama Party
|
R9LP41 = Girls Life: Pyjama Party
|
||||||
R9SPPL = Sudoku Ball : Detective
|
R9SPPL = Sudoku Ball : Detective
|
||||||
|
RAAE01 = Disque Startup du Wii
|
||||||
RB4P08 = Resident Evil 4 : Wii Edition
|
RB4P08 = Resident Evil 4 : Wii Edition
|
||||||
RB4X08 = Resident Evil 4 : Wii Edition
|
RB4X08 = Resident Evil 4 : Wii Edition
|
||||||
RB5P41 = Brothers in Arms : Earned in Blood
|
RB5P41 = Brothers in Arms : Earned in Blood
|
||||||
|
@ -199,7 +198,6 @@ RH3P4Q = High School Musical 3 Dance! Nos Années Lycée
|
||||||
RH5PKM = Horse Life : Amis pour la vie
|
RH5PKM = Horse Life : Amis pour la vie
|
||||||
RH6P69 = Harry Potter et le Prince de Sang-Mêlé
|
RH6P69 = Harry Potter et le Prince de Sang-Mêlé
|
||||||
RH8P4F = Tomb Raider : Underworld
|
RH8P4F = Tomb Raider : Underworld
|
||||||
RH8X4F = Tomb Raider : Underworld
|
|
||||||
RHCP52 = The History Channel : Battle for the Pacific
|
RHCP52 = The History Channel : Battle for the Pacific
|
||||||
RHGP6Z = Agent Hugo : Lemoon Twist
|
RHGP6Z = Agent Hugo : Lemoon Twist
|
||||||
RHKP18 = Job Island
|
RHKP18 = Job Island
|
||||||
|
@ -226,9 +224,8 @@ RIHP8P = L'Incroyable Hulk
|
||||||
RIJP69 = G.I. JOE : Le réveil du Cobra
|
RIJP69 = G.I. JOE : Le réveil du Cobra
|
||||||
RINP08 = Dead Rising : Chop Till You Drop
|
RINP08 = Dead Rising : Chop Till You Drop
|
||||||
RIOPSU = Horribles Histoires : les Redoutables Romains
|
RIOPSU = Horribles Histoires : les Redoutables Romains
|
||||||
RIPPAF = One Piece Unlimited Cruise 1 : Le Trésor sous les Flots
|
|
||||||
RITFMR = Intervilles : Le Jeu Officiel
|
RITFMR = Intervilles : Le Jeu Officiel
|
||||||
RIUPAF = One Piece - Unlimited Cruise 2 : L'Eveil d'un Héros
|
RIUPAF = One Piece: Unlimited Cruise 2: L'Eveil d'un Héros
|
||||||
RJ2P52 = 007 : Quantum of Solace
|
RJ2P52 = 007 : Quantum of Solace
|
||||||
RJ4PRM = Naissance de Rome : Sur les Traces de César
|
RJ4PRM = Naissance de Rome : Sur les Traces de César
|
||||||
RJ7FWP = Télé 7 Jeux : Mots Fléchés
|
RJ7FWP = Télé 7 Jeux : Mots Fléchés
|
||||||
|
@ -270,7 +267,6 @@ RLNFMR = Koh-Lanta
|
||||||
RLNHMR = Koh-Lanta
|
RLNHMR = Koh-Lanta
|
||||||
RLNIMR = Koh-Lanta
|
RLNIMR = Koh-Lanta
|
||||||
RLRP4F = Tomb Raider : Anniversary
|
RLRP4F = Tomb Raider : Anniversary
|
||||||
RLTPNR = London Taxi : Rush Hour
|
|
||||||
RLTXUG = London Taxi : Rush Hour
|
RLTXUG = London Taxi : Rush Hour
|
||||||
RLUP4Q = Volt : Star Malgré Lui
|
RLUP4Q = Volt : Star Malgré Lui
|
||||||
RLUX4Q = Volt : Star Malgré Lui
|
RLUX4Q = Volt : Star Malgré Lui
|
||||||
|
@ -306,7 +302,6 @@ RNPP69 = Need for Speed : ProStreet
|
||||||
RNPX69 = Need for Speed : ProStreet
|
RNPX69 = Need for Speed : ProStreet
|
||||||
RNSF69 = Need for Speed : Carbon
|
RNSF69 = Need for Speed : Carbon
|
||||||
RNSP69 = Need for Speed : Carbon
|
RNSP69 = Need for Speed : Carbon
|
||||||
RNSX69 = Need for Speed : Carbon
|
|
||||||
RNXPDA = Naruto : Clash of Ninja Revolution European Version
|
RNXPDA = Naruto : Clash of Ninja Revolution European Version
|
||||||
RO7P7D = The Legend of Spyro : The Eternal Night
|
RO7P7D = The Legend of Spyro : The Eternal Night
|
||||||
RO8P7D = La Légende de Spyro : La Naissance d'un Dragon
|
RO8P7D = La Légende de Spyro : La Naissance d'un Dragon
|
||||||
|
@ -319,7 +314,7 @@ ROLP8P = Mario & Sonic aux Jeux Olympiques d'Hiver
|
||||||
RONPG9 = Onechanbara : Bikini Zombie Slayers
|
RONPG9 = Onechanbara : Bikini Zombie Slayers
|
||||||
ROPP41 = Les Rebelles de la Fôret
|
ROPP41 = Les Rebelles de la Fôret
|
||||||
ROTP7J = Twin Strike : Operation Thunder
|
ROTP7J = Twin Strike : Operation Thunder
|
||||||
ROUPAF = One Piece - Unlimited Cruise 1 : Le Trésor sous les Flots
|
ROUPAF = One Piece: Unlimited Cruise 1: Le Trésor sous les Flots
|
||||||
ROVE6U = Playmobil Circus : Tous en Piste
|
ROVE6U = Playmobil Circus : Tous en Piste
|
||||||
ROVPHM = Playmobil Circus: Tous en Piste
|
ROVPHM = Playmobil Circus: Tous en Piste
|
||||||
ROYP41 = Tempête de boulettes géantes : Le Jeu Vidéo
|
ROYP41 = Tempête de boulettes géantes : Le Jeu Vidéo
|
||||||
|
@ -410,7 +405,7 @@ RTNP41 = Tenchu : Shadow Assassins
|
||||||
RTUFKM = Secret Files : Tunguska
|
RTUFKM = Secret Files : Tunguska
|
||||||
RTUPKM = Secret Files : Tunguska
|
RTUPKM = Secret Files : Tunguska
|
||||||
RTVP64 = Thrillville : Le parc en folie
|
RTVP64 = Thrillville : Le parc en folie
|
||||||
RTYP01 = Wii Echecs
|
RTYP01 = Wii Échecs
|
||||||
RTZE08 = Zack & Wiki : Le Trésor de Barbaros
|
RTZE08 = Zack & Wiki : Le Trésor de Barbaros
|
||||||
RTZJ08 = Zack & Wiki : Le Trésor de Barbaros
|
RTZJ08 = Zack & Wiki : Le Trésor de Barbaros
|
||||||
RTZP08 = Zack & Wiki : Le Trésor de Barbaros
|
RTZP08 = Zack & Wiki : Le Trésor de Barbaros
|
||||||
|
@ -501,7 +496,6 @@ RY2P41 = Rayman Contre les Lapins Encore plus Crétins
|
||||||
RY3P41 = Rayman Prod' présente : The Lapins Crétins Show
|
RY3P41 = Rayman Prod' présente : The Lapins Crétins Show
|
||||||
RYBP69 = Boom Blox : Smash Party
|
RYBP69 = Boom Blox : Smash Party
|
||||||
RYDP6V = Pet Pals: Vétérinaire
|
RYDP6V = Pet Pals: Vétérinaire
|
||||||
RYGP99 = Rygar : The Battle of Argus
|
|
||||||
RYJPTV = Princesse Lillifee : La fée magique
|
RYJPTV = Princesse Lillifee : La fée magique
|
||||||
RYKEAF = Family Ski & Snowboard
|
RYKEAF = Family Ski & Snowboard
|
||||||
RYWP01 = Cérébrale Académie
|
RYWP01 = Cérébrale Académie
|
||||||
|
@ -534,12 +528,14 @@ S6BP4Q = Rebelle
|
||||||
S6BX4Q = Rebelle
|
S6BX4Q = Rebelle
|
||||||
S6IP78 = Disney Princesse: Livres Enchantés
|
S6IP78 = Disney Princesse: Livres Enchantés
|
||||||
S6RP52 = Les Mondes de Ralph
|
S6RP52 = Les Mondes de Ralph
|
||||||
|
S72J01 = Hoshi no Kirby: 20th Anniversary Edition
|
||||||
S7APWR = LEGO Batman 2 : DC Super Heroes
|
S7APWR = LEGO Batman 2 : DC Super Heroes
|
||||||
S7BP69 = Trivial Pursuit Casual
|
S7BP69 = Trivial Pursuit Casual
|
||||||
S7EP52 = Transformers : Édition Ultime Combat
|
S7EP52 = Transformers : Édition Ultime Combat
|
||||||
S7FPGT = Zumba Kids : La fête ultime pour les enfants
|
S7FPGT = Zumba Kids : La fête ultime pour les enfants
|
||||||
S7SP41 = Les schtroumpfs Party Pack
|
S7SP41 = Les schtroumpfs Party Pack
|
||||||
SA3P5G = Alvin et Les Chipmunks 3
|
SA3P5G = Alvin et Les Chipmunks 3
|
||||||
|
SA3XGT = Alvin et Les Chipmunks 3
|
||||||
SALE4Q = Alice au Pays des Merveilles
|
SALE4Q = Alice au Pays des Merveilles
|
||||||
SALP4Q = Alice au Pays des Merveilles
|
SALP4Q = Alice au Pays des Merveilles
|
||||||
SAOP78 = Monster High: Lycée d'Enfer
|
SAOP78 = Monster High: Lycée d'Enfer
|
||||||
|
@ -580,6 +576,7 @@ SF5P41 = Mon Coach Personnel : Club Fitness
|
||||||
SFGP69 = Hasbro : Best of des Jeux en Famille Vol. 4
|
SFGP69 = Hasbro : Best of des Jeux en Famille Vol. 4
|
||||||
SFIP01 = Mystery Case Files : L'Affaire Malgrave
|
SFIP01 = Mystery Case Files : L'Affaire Malgrave
|
||||||
SFQP8P = Captain America : Super Soldier
|
SFQP8P = Captain America : Super Soldier
|
||||||
|
SFWP69 = Coupe du Monde de la FIFA, Afrique du Sud 2010
|
||||||
SFWX69 = Coupe du Monde de la FIFA, Afrique du Sud 2010
|
SFWX69 = Coupe du Monde de la FIFA, Afrique du Sud 2010
|
||||||
SFWY69 = Coupe du Monde de la FIFA
|
SFWY69 = Coupe du Monde de la FIFA
|
||||||
SG8PAF = Yogi l'Ours: Le Jeu Vidéo
|
SG8PAF = Yogi l'Ours: Le Jeu Vidéo
|
||||||
|
@ -596,6 +593,7 @@ SHMPLR = Lucas la Cata
|
||||||
SHVP78 = Hot Wheels
|
SHVP78 = Hot Wheels
|
||||||
SIAP52 = L'Âge de glace 4 : La dérive des continents - Jeux de l'Arctique
|
SIAP52 = L'Âge de glace 4 : La dérive des continents - Jeux de l'Arctique
|
||||||
SIIP8P = Mario & Sonic aux Jeux Olympiques de Londres 2012
|
SIIP8P = Mario & Sonic aux Jeux Olympiques de Londres 2012
|
||||||
|
SILP78 = Worms : Battle Islands
|
||||||
SINPNG = We Sing : Robbie Williams
|
SINPNG = We Sing : Robbie Williams
|
||||||
SJ2PWR = Scooby-Doo! Panique dans la Marmite
|
SJ2PWR = Scooby-Doo! Panique dans la Marmite
|
||||||
SJ9P41 = Just Dance 2 : Extra Songs
|
SJ9P41 = Just Dance 2 : Extra Songs
|
||||||
|
@ -624,7 +622,6 @@ SNBP41 = NCIS: Adapté de la série TV
|
||||||
SNHP69 = Need for Speed
|
SNHP69 = Need for Speed
|
||||||
SNUPJW = Happy Neuron Academy - Testez Votre Q.I.
|
SNUPJW = Happy Neuron Academy - Testez Votre Q.I.
|
||||||
SNYPVZ = Monster High : 13 souhaits
|
SNYPVZ = Monster High : 13 souhaits
|
||||||
SOMP01 = Beat the Beat : Rhythm Paradise
|
|
||||||
SONFMR = Mon Premier Karaoké
|
SONFMR = Mon Premier Karaoké
|
||||||
SOSPAF = Turbo : Équipe de Cascadeurs
|
SOSPAF = Turbo : Équipe de Cascadeurs
|
||||||
SOUP01 = The Legend of Zelda : Skyward Sword
|
SOUP01 = The Legend of Zelda : Skyward Sword
|
||||||
|
@ -676,6 +673,7 @@ SVDP52 = Bob l'éponge : La vengeance robotique de Plankton
|
||||||
SVHP69 = FIFA 14 - Édition Essentielle
|
SVHP69 = FIFA 14 - Édition Essentielle
|
||||||
SVHX69 = FIFA 14 - Édition Essentielle
|
SVHX69 = FIFA 14 - Édition Essentielle
|
||||||
SVMP01 = Super Mario All-Stars
|
SVMP01 = Super Mario All-Stars
|
||||||
|
SVQEVZ = Barbie et ses soeurs : La grande aventure des chiots
|
||||||
SVQPVZ = Barbie et ses soeurs : La grande aventure des chiots
|
SVQPVZ = Barbie et ses soeurs : La grande aventure des chiots
|
||||||
SVVPAF = Les Croods : Fête Préhistorique !
|
SVVPAF = Les Croods : Fête Préhistorique !
|
||||||
SXAP52 = Guitar Hero : World Tour
|
SXAP52 = Guitar Hero : World Tour
|
||||||
|
@ -683,56 +681,105 @@ SXBP52 = Guitar Hero : Metallica
|
||||||
SXCP52 = Guitar Hero : Greatest Hits
|
SXCP52 = Guitar Hero : Greatest Hits
|
||||||
SXDP52 = Guitar Hero : Van Halen
|
SXDP52 = Guitar Hero : Van Halen
|
||||||
SXIP52 = Guitar Hero : Warriors of Rock
|
SXIP52 = Guitar Hero : Warriors of Rock
|
||||||
|
GMSE02 = Super Mario Sunshine Multijoueur
|
||||||
R4ZP01 = Project Zero 4 - Mask of the Lunar Eclipse
|
R4ZP01 = Project Zero 4 - Mask of the Lunar Eclipse
|
||||||
|
RMCE88 = Le Mario Kare Deluxa por jatras
|
||||||
|
RMCJ91 = Wiimms Mario Kart Fun 2021-09 Reservé
|
||||||
|
RMCK91 = Wiimms Mario Kart Fun 2021-09 Reservé
|
||||||
|
RMCP91 = Wiimms Mario Kart Fun 2021-09 Réservé
|
||||||
|
RMCPCA = Mario Kart Wii (traduction en catalan)
|
||||||
SBOD3Q = StarSing : Chansons Magiques de Disney v1.1
|
SBOD3Q = StarSing : Chansons Magiques de Disney v1.1
|
||||||
SILP4Q = SingItStar Latino
|
SILP4Q = SingItStar Latino
|
||||||
|
SNBE66 = Nouveau Super Mario Bros. Wii Apocalypse
|
||||||
W2CP = Cérébral Challenge
|
W2CP = Cérébral Challenge
|
||||||
W2FP = Entrainement d'équilibre Physiofun
|
W2FP = Entrainement d'équilibre Physiofun
|
||||||
|
W2GD = Phoenix Wright Ace Attorney: Justice for All (Deutsche Version)
|
||||||
|
W2GF = Phoenix Wright: Ace Attorney: Justice for All
|
||||||
W2GP = Phoenix Wright Ace Attorney : Justice for All
|
W2GP = Phoenix Wright Ace Attorney : Justice for All
|
||||||
W2MP = Blaster Master Overdrive
|
W2MP = Blaster Master Overdrive
|
||||||
W2PP = Programme de rééducation du périnée Physiofun
|
W2PP = Programme de rééducation du périnée Physiofun
|
||||||
|
W3GD = Phoenix Wright Ace Attorney 3: Trials And Tribulations
|
||||||
|
W3GF = Phoenix Wright: Ace Attorney: Trials and Tribulations
|
||||||
W3GP = Phoenix Wright Ace Attorney : Trials and Tribulations
|
W3GP = Phoenix Wright Ace Attorney : Trials and Tribulations
|
||||||
W3KE = Thruspace
|
W3KE = Thruspace
|
||||||
W3KP = Thruspace
|
W3KP = Thruspace
|
||||||
W3MP = Les Trois Mousquetaires : Tous pour un!
|
W3MP = Les Trois Mousquetaires : Tous pour un!
|
||||||
W44P = Stop Stress : A Day of Fury
|
W44P = Stop Stress : A Day of Fury
|
||||||
W4AP = Arcade Sports : Air Hockey, Bowling, Pool, Snooker
|
W4AP = Arcade Sports : Air Hockey, Bowling, Pool, Snooker
|
||||||
|
W6BP = Eco-Shooter: Plant 530
|
||||||
|
W72P = Successfully Learning German Year 3
|
||||||
|
W73P = Successfully Learning German Year 4
|
||||||
|
W74P = Successfully Learning German Year 5
|
||||||
|
W7IP = Successfully Learning German Year 2
|
||||||
|
W8CP = Bit.Trip Core
|
||||||
W8WP = Happy Holidays Halloween
|
W8WP = Happy Holidays Halloween
|
||||||
|
W9BP = Big Town Shoot
|
||||||
W9RP = Happy Holidays Christmas
|
W9RP = Happy Holidays Christmas
|
||||||
WA4P = WarioWare : Do It Yourself - Showcase
|
WA4P = WarioWare : Do It Yourself - Showcase
|
||||||
WA7P = Toribash - La violence perfectionnée
|
WA7P = Toribash - La violence perfectionnée
|
||||||
WA8P = ArtStyle: Penta Tentacles
|
WA8P = ArtStyle: Penta Tentacles
|
||||||
|
WAEP = Around the world
|
||||||
|
WAFP = Airport Mania: First Flight
|
||||||
|
WAHP = Trenches: Generals
|
||||||
WALP = Art Style : light trax
|
WALP = Art Style : light trax
|
||||||
|
WAOP = The Very Hungry Caterpillar´s ABC
|
||||||
WB2P = Strong Bad Episode 4 : Dangeresque 3
|
WB2P = Strong Bad Episode 4 : Dangeresque 3
|
||||||
WB3P = Strong Bad Episode 5 : 8-bit is Enough
|
WB3P = Strong Bad Episode 5 : 8-bit is Enough
|
||||||
WBEP = Beer Pong : Frat Party Games
|
WBEP = Beer Pong : Frat Party Games
|
||||||
|
WBFP = Bit.Trip Fate
|
||||||
|
WBGP = Bang Attack
|
||||||
|
WBPP = PLÄTTCHEN - twist 'n' paint
|
||||||
WBRP = Pirates : The Key of Dreams
|
WBRP = Pirates : The Key of Dreams
|
||||||
|
WBXP = Strong Bad Episode 1: Homestar Ruiner
|
||||||
WBYP = Strong Bad Episode 2 : Strong Badia - The Free
|
WBYP = Strong Bad Episode 2 : Strong Badia - The Free
|
||||||
WBZP = Strong Bad Episode 3 : Baddest of the Bands
|
WBZP = Strong Bad Episode 3 : Baddest of the Bands
|
||||||
|
WCHP = Chess Challenge
|
||||||
WCJP = Cocoto : Platform Jumper
|
WCJP = Cocoto : Platform Jumper
|
||||||
|
WCKP = chick chick BOOM
|
||||||
WCSP = CueSports : Snooker vs Billiards
|
WCSP = CueSports : Snooker vs Billiards
|
||||||
WD9P = Castlevania : The Adventure ReBirth
|
WD9P = Castlevania : The Adventure ReBirth
|
||||||
|
WDEP = Magic Destiny Astrological Games
|
||||||
|
WDFP = Defend your Castle
|
||||||
WDHP = ArtStyle : ROTOHEX
|
WDHP = ArtStyle : ROTOHEX
|
||||||
WDMP = Dr. Mario & Bactericide
|
WDMP = Dr. Mario & Bactericide
|
||||||
|
WDPP = Dr. Mario & Germ Buster (Friend Battle Demo)
|
||||||
|
WEMP = Aha! I Got It! Escape Game
|
||||||
WETP = Jeux de plateau en images : La chasse au trésor
|
WETP = Jeux de plateau en images : La chasse au trésor
|
||||||
WF2P = Final Fantasy Crystal Chronicles : My Life as a Darklord
|
WF2P = Final Fantasy Crystal Chronicles : My Life as a Darklord
|
||||||
|
WF3E = Family Games - Pen & Paper Edition
|
||||||
WF4P = Final Fantasy IV : Les Années Suivantes
|
WF4P = Final Fantasy IV : Les Années Suivantes
|
||||||
WFCP = Final Fantasy Crystal Chronicles : My Life as a King
|
WFCP = Final Fantasy Crystal Chronicles : My Life as a King
|
||||||
|
WFQP = Frogger: Hyper Arcade Edition
|
||||||
|
WFTP = Fish'em All!
|
||||||
|
WFVP = Football Up
|
||||||
WFWP = Flowerworks : Follie's Adventure
|
WFWP = Flowerworks : Follie's Adventure
|
||||||
WFXP = Feu de Bois Chaleureux
|
WFXP = Feu de Bois Chaleureux
|
||||||
|
WFYP = Family Games Pen & Paper Edition
|
||||||
|
WGDP = Gradius Rebirth
|
||||||
WGFP = Girlfriends Forever Magic Skate
|
WGFP = Girlfriends Forever Magic Skate
|
||||||
|
WGGP = Gabrielle's Ghostly Groove: Monster Mix
|
||||||
WGPP = Zenquaria L'aquarium Virtuel
|
WGPP = Zenquaria L'aquarium Virtuel
|
||||||
|
WGSE = Phoenix Wright: Ace Attorney
|
||||||
|
WGSF = Phoenix Wright: Ace Attorney (French Version)
|
||||||
|
WGSP = Phoenix Wright: Ace Attorney
|
||||||
WHEE = Heracles : Chariot Racing
|
WHEE = Heracles : Chariot Racing
|
||||||
WHEP = Heracles : Chariot Racing
|
WHEP = Heracles : Chariot Racing
|
||||||
|
WHFP = Heavy Fire: Special Operations
|
||||||
WHRP = Heron : Steam Machine
|
WHRP = Heron : Steam Machine
|
||||||
WHUP = Ghost Party
|
WHUP = Ghost Party
|
||||||
WHWP = HoopWorld : BasketBrawl
|
WHWP = HoopWorld : BasketBrawl
|
||||||
WICP = NyxQuest : Kindred Spirits
|
WICP = NyxQuest : Kindred Spirits
|
||||||
WIDP = Dracula : Undead Awakening
|
WIDP = Dracula : Undead Awakening
|
||||||
WIEP = Tales of Monkey Island Chapter 3 : Lair of the Leviathan
|
WIEP = Tales of Monkey Island Chapter 3 : Lair of the Leviathan
|
||||||
|
WILP = Tales of Monkey Island Chapter 1: Launch of the Screaming Narwhal
|
||||||
|
WIRP = Tales of Monkey Island Chapter 5: Rise Of The Pirate God
|
||||||
WISP = Tales of Monkey Island Chapter 2 : The Siege of Spinner Cay
|
WISP = Tales of Monkey Island Chapter 2 : The Siege of Spinner Cay
|
||||||
|
WITP = Aha! I Found It! Hidden Object Game
|
||||||
WIYP = Tales of Monkey Island Chapter 4 : The Trial and Execution of Guybrush Threepwood
|
WIYP = Tales of Monkey Island Chapter 4 : The Trial and Execution of Guybrush Threepwood
|
||||||
WJKP = Les Gardiens du Joyau : l'Île de l'Est
|
WJKP = Les Gardiens du Joyau : l'Île de l'Est
|
||||||
|
WKBP = You, Me and the Cubes
|
||||||
|
WKFP = Kung Fu Funk: Everybody Is Kung Fu Fighting
|
||||||
|
WKKP = Pop-Up Pirates!
|
||||||
WKRP = Karate Phants : Gloves of Glory
|
WKRP = Karate Phants : Gloves of Glory
|
||||||
WKWP = Les aventures de l'ile perdue jeu d'objets cachés
|
WKWP = Les aventures de l'ile perdue jeu d'objets cachés
|
||||||
WLEE = Apprends avec les PooYoos: Episode 1
|
WLEE = Apprends avec les PooYoos: Episode 1
|
||||||
|
@ -740,38 +787,76 @@ WLEP = Apprends avec les PooYoos: Episode 1
|
||||||
WLNE = Apprends avec les PooYoos: Episode 2
|
WLNE = Apprends avec les PooYoos: Episode 2
|
||||||
WLNP = Apprends avec les PooYoos: Episode 2
|
WLNP = Apprends avec les PooYoos: Episode 2
|
||||||
WLOP = LostWinds : Winter of the Melodias
|
WLOP = LostWinds : Winter of the Melodias
|
||||||
|
WLZP = lilt line
|
||||||
|
WM7E = Anima Ark of Sinners
|
||||||
|
WM7P = Anima Ark of Sinners
|
||||||
WMBP = MaBoShi : l'arcade des trois formes
|
WMBP = MaBoShi : l'arcade des trois formes
|
||||||
|
WMCP = Monsteca Corral: Monsters Vs. Robots
|
||||||
|
WMJP = Dive: The Medes Islands Secret
|
||||||
|
WMSP = Enjoy your massage!
|
||||||
WMWP = Le monde de Miffy
|
WMWP = Le monde de Miffy
|
||||||
WMWX = Le monde de Miffy
|
WMWX = Le monde de Miffy
|
||||||
|
WN9E = Military Madness: Nectaris
|
||||||
WN9P = Military Madness : Nectaris
|
WN9P = Military Madness : Nectaris
|
||||||
|
WNEE = Penguins & Friends Hey! That's My Fish!
|
||||||
|
WNEP = Penguins & Friends Hey! That’s my Fish!
|
||||||
WNVP = Neves Plus
|
WNVP = Neves Plus
|
||||||
|
WOBE = Art Style: ORBIENT
|
||||||
WOBP = Art Style : ORBIENT
|
WOBP = Art Style : ORBIENT
|
||||||
WOTP = Overturn : Mecha Wars
|
WOTP = Overturn : Mecha Wars
|
||||||
|
WP3P = Pearl Harbor Trilogy 1941: Red Sun Rising
|
||||||
WP4E = Apprends avec les Pooyoos Episode 3
|
WP4E = Apprends avec les Pooyoos Episode 3
|
||||||
WP4P = Apprends avec les Pooyoos Episode 3
|
WP4P = Apprends avec les Pooyoos Episode 3
|
||||||
WPJP = Pucca Mission Bisous
|
WPJP = Pucca Mission Bisous
|
||||||
|
WPKP = Texas Hold'Em Poker
|
||||||
|
WPQP = Protöthea
|
||||||
|
WPRE = Art Style: Cubello
|
||||||
WPRP = Art Style : CUBELLO
|
WPRP = Art Style : CUBELLO
|
||||||
WPVP = The Tales of Bearsworth Manor - Chaotic Conflicts
|
WPVE = The Tales of Bearsworth Manor: Chaotic Conflicts
|
||||||
WR2E = Labo Lapins Crétins
|
WR2E = Labo Lapins Crétins
|
||||||
WR2P = Labo Lapins Crétins
|
WR2P = Labo Lapins Crétins
|
||||||
WR9P = Megaman 9
|
WR9P = Megaman 9
|
||||||
WRDP = Mot Cache
|
WRDP = Mot Cache
|
||||||
|
WREP = Racers Islands Crazy Arenas
|
||||||
WRFE = Reel Fishing Challenge 2
|
WRFE = Reel Fishing Challenge 2
|
||||||
WRFP = Reel Fishing Challenge 2
|
WRFP = Reel Fishing Challenge 2
|
||||||
WRIP = Rainbow Islands : Towering Adventure!
|
WRIP = Rainbow Islands : Towering Adventure!
|
||||||
|
WRJP = Racers Islands - Crazy Racers
|
||||||
|
WRLP = FAST Racing League
|
||||||
WRRP = Robin Hood : Le Retour de Richard
|
WRRP = Robin Hood : Le Retour de Richard
|
||||||
|
WRUP = Bit.Trip Runner
|
||||||
WRXP = Megaman 10
|
WRXP = Megaman 10
|
||||||
|
WSGP = Pop Them, Drop Them SAMEGAME
|
||||||
WSJP = Trouvez les Differences!
|
WSJP = Trouvez les Differences!
|
||||||
|
WSNP = Sonic The Hedgehog 4 Episode I
|
||||||
|
WSUE = Shootanto: Evolutionary Mayhem
|
||||||
WSUP = Shootanto : Evolutionary Mayhem
|
WSUP = Shootanto : Evolutionary Mayhem
|
||||||
|
WTEP = Tales of Elastic Boy Mission 1
|
||||||
|
WTFP = Bit.Trip Flux
|
||||||
WTMP = Adventure Island The Beginning
|
WTMP = Adventure Island The Beginning
|
||||||
|
WTRE = Bit.Trip Beat
|
||||||
WTRP = Bit.Trip : Beat
|
WTRP = Bit.Trip : Beat
|
||||||
WTWP = Fenimore Fillmore The Westerner
|
WTWP = Fenimore Fillmore The Westerner
|
||||||
|
WTXP = Texas Hold’em Tournament
|
||||||
|
WU2P = Successfully Learning Mathematics Year 3
|
||||||
|
WU3P = Successfully Learning Mathematics Year 4
|
||||||
|
WU4P = Successfully Learning Mathematics Year 5
|
||||||
WUIP = Succès au primaire : Power maths
|
WUIP = Succès au primaire : Power maths
|
||||||
|
WVBP = Bit.Trip Void
|
||||||
|
WVOP = Rock'n Roll Climber
|
||||||
|
WVSP = Gods Vs Humans
|
||||||
|
WVUP = Mr Bumblebee Racing Champion
|
||||||
|
WW2P = Where's Wally? Fantastic Journey 2
|
||||||
|
WW3P = Where's Wally? Fantastic Journey 3
|
||||||
WWIP = Où est Charlie ? Voyage Fantastique 1
|
WWIP = Où est Charlie ? Voyage Fantastique 1
|
||||||
|
WWRP = Excitebike: World Challenge
|
||||||
|
WWXP = Paper Wars Cannon Fodder
|
||||||
WXBE = Ben 10 Alien Force The Rise of Hex
|
WXBE = Ben 10 Alien Force The Rise of Hex
|
||||||
WXBP = Ben 10 Alien Force The Rise of Hex
|
WXBP = Ben 10 Alien Force The Rise of Hex
|
||||||
|
WYIP = escapeVektor: Chapter 1
|
||||||
|
WYSP = Yard Sale Hidden Treasures Sunnyville
|
||||||
WZIP = Rubik's Puzzle Galaxy : RUSH
|
WZIP = Rubik's Puzzle Galaxy : RUSH
|
||||||
WZZP = The Tales of Bearsworth Manor - Puzzling Pages
|
WZZE = The Tales of Bearsworth Manor: Puzzling Pages
|
||||||
XIBP = Fish em All Demo
|
XIBP = Fish em All Demo
|
||||||
XICP = Gods vs Humans Demo
|
XICP = Gods vs Humans Demo
|
||||||
XIDP = Racers Islands Crazy Racers Demo
|
XIDP = Racers Islands Crazy Racers Demo
|
||||||
|
@ -790,60 +875,163 @@ XIZP = 3D Pixel Racing Demo
|
||||||
XJEP = Aya and the Cubes of Light Demo
|
XJEP = Aya and the Cubes of Light Demo
|
||||||
FA9P = Zelda II : The Adventure of Link
|
FA9P = Zelda II : The Adventure of Link
|
||||||
FB2L = Super Mario Bros. : The Lost Levels
|
FB2L = Super Mario Bros. : The Lost Levels
|
||||||
|
FBKP = Teenage Mutant Ninja Turles
|
||||||
FC8P = Castlevania II : Simon's Quest
|
FC8P = Castlevania II : Simon's Quest
|
||||||
FCSP = Probotector II : Return of the Evil Forces
|
FCSP = Probotector II : Return of the Evil Forces
|
||||||
|
FCYP = Yoshi’s Cookie
|
||||||
|
FDGP = Ghosts'n Goblins
|
||||||
|
FDRP = Skate or Die
|
||||||
|
FEML = Bio Miracle Bokutte UPA
|
||||||
|
FEQP = Castlevania III Dracula's Curse
|
||||||
|
FERM = Startropics II: Zoda's Revenge
|
||||||
|
FF5E = Double Dragon II: The Revenge
|
||||||
|
FF5P = Double Dragon II: The Revenge
|
||||||
|
FFEE = A Boy and His Blob: Trouble on Blobolonia
|
||||||
FFEP = A Boy and His Blob : Trouble on Blobolonia
|
FFEP = A Boy and His Blob : Trouble on Blobolonia
|
||||||
|
FFPB = Ufouria: The Saga
|
||||||
|
FFPP = Ufouria: THE SAGA
|
||||||
|
FFUP = Adventure Island 2
|
||||||
|
FFVM = S.C.A.T.: Special Cybernetic Attack Team
|
||||||
|
JA4P = Super Ghouls'n Ghosts
|
||||||
|
JABL = Mario’s Super Picross
|
||||||
JADD = The Legend of Zelda : A Link to the Past
|
JADD = The Legend of Zelda : A Link to the Past
|
||||||
JADE = The Legend of Zelda : A Link to the Past
|
JADE = The Legend of Zelda : A Link to the Past
|
||||||
JADF = The Legend of Zelda : A Link to the Past
|
JADF = The Legend of Zelda : A Link to the Past
|
||||||
JADP = The Legend of Zelda : A Link to the Past
|
JADP = The Legend of Zelda : A Link to the Past
|
||||||
|
JAFF = SimCity
|
||||||
|
JAFP = SimCity
|
||||||
JAHP = R-TYPE III : The Third Lightning
|
JAHP = R-TYPE III : The Third Lightning
|
||||||
JAJP = Street Fighter II : The World Warrior
|
JAJP = Street Fighter II : The World Warrior
|
||||||
JALP = Super Probotector : Alien Rebels
|
JALP = Super Probotector : Alien Rebels
|
||||||
|
JAZP = The Legend of the Mystical Ninja
|
||||||
JBBP = Super Street Fighter II : The New Challengers
|
JBBP = Super Street Fighter II : The New Challengers
|
||||||
JBDP = Donkey Kong Country 2 : Diddy's Kong-Quest
|
JBDP = Donkey Kong Country 2 : Diddy's Kong-Quest
|
||||||
JBIP = Street Fighter II Turbo : Hyper Fighting
|
JBIP = Street Fighter II Turbo : Hyper Fighting
|
||||||
JBPP = Donkey Kong Country 3 : Dixie Kong’s Double Trouble
|
JBPP = Donkey Kong Country 3 : Dixie Kong’s Double Trouble
|
||||||
|
JCAL = DoReMi Fantasy - Milon’s DokiDoki Adventure
|
||||||
JCBM = Super Mario RPG : Legend of the Seven Stars
|
JCBM = Super Mario RPG : Legend of the Seven Stars
|
||||||
|
JCCP = Kirby’s Fun Pak
|
||||||
|
JCDM = Kirby’s Dream Land 3
|
||||||
|
JCJP = Super Punch Out!!
|
||||||
|
JCKP = Space Invaders -The Original Game-
|
||||||
JCTM = Ogre Battle : The March of the Black Queen
|
JCTM = Ogre Battle : The March of the Black Queen
|
||||||
JD3P = SUPER E.D.F. : Earth Defense Force
|
JD3P = SUPER E.D.F. : Earth Defense Force
|
||||||
JDJP = Super Star Wars : The Empire Strikes Back
|
JDJP = Super Star Wars : The Empire Strikes Back
|
||||||
JDLP = Super Star Wars : Return of the Jedi
|
JDLP = Super Star Wars : Return of the Jedi
|
||||||
|
JDWE = Aero the Acrobat
|
||||||
|
JDWP = Aero The Acrobat
|
||||||
|
JDZF = Mystic Quest Legend
|
||||||
NACP = The Legend of Zelda : Ocarina of Time
|
NACP = The Legend of Zelda : Ocarina of Time
|
||||||
|
NAJN = Sin and Punishment
|
||||||
|
NAKS = Pokémon Snap
|
||||||
NAME = Kirby 64 : The Crystal Shards
|
NAME = Kirby 64 : The Crystal Shards
|
||||||
NAMP = Kirby 64 : The Crystal Shards
|
NAMP = Kirby 64 : The Crystal Shards
|
||||||
|
NAND = Pokémon Puzzle League
|
||||||
|
NAOP = 1080°: TenEighty Snowboarding
|
||||||
NARP = The Legend of Zelda : Majora's Mask
|
NARP = The Legend of Zelda : Majora's Mask
|
||||||
|
NAYE = Ogre Battle 64: Person of Lordly Caliber
|
||||||
|
NAYM = Ogre Battle 64: Person of Lordly Caliber
|
||||||
|
LALP = Fantasy Zone II
|
||||||
|
LANP = Alex Kidd: The Lost Stars
|
||||||
|
LAPP = Wonder Boy III: The Dragon's Trap
|
||||||
|
MA8P = Ecco: The Tides of Time
|
||||||
|
MAHE = Sonic the Hedgehog
|
||||||
|
MAHP = Sonic the Hedgehog
|
||||||
MAKP = Shadow Dancer : The Secret of Shinobi
|
MAKP = Shadow Dancer : The Secret of Shinobi
|
||||||
|
MALP = Bonanza Bros.
|
||||||
|
MAOP = Bio-Hazard Battle
|
||||||
MARP = La Légende de Thor
|
MARP = La Légende de Thor
|
||||||
MB6P = Shining Force II
|
MAVP = Wonder Boy In Monster World
|
||||||
|
MAXP = Alex Kidd In The Enchanted Castle
|
||||||
|
MBBP = Sonic the Hedgehog 2
|
||||||
|
MBFP = Shinobi III: Return of the Ninja master
|
||||||
MBIP = Landstalker : Le Trésor du Roi Nole
|
MBIP = Landstalker : Le Trésor du Roi Nole
|
||||||
|
MBJE = Ghouls'n Ghosts
|
||||||
|
MBJP = Ghouls'n Ghosts
|
||||||
|
MBLP = ESWAT City Under Siege
|
||||||
|
MBMP = Sonic the Hedgehog 3
|
||||||
|
MBUP = Sonic 3D: Flickies' Island
|
||||||
|
MBWM = Columns III: Revenge of Columns
|
||||||
|
MC3P = Super Street Fighter II: The New Challengers
|
||||||
|
MCCP = Phantasy Star III: Generations of Doom
|
||||||
MCHM = MUSHA : Metallic Uniframe Super Hybrid Armor
|
MCHM = MUSHA : Metallic Uniframe Super Hybrid Armor
|
||||||
|
MCLP = Street Fighter II’: Special Champion Edition
|
||||||
|
MCQP = Boogerman - A Pick and Flick Adventure
|
||||||
|
MCRP = Wolf of the Battlefield: MERCS
|
||||||
|
MCSP = Wonder Boy III: Monster Lair
|
||||||
|
MCVP = Pitfall: The Mayan Adventure
|
||||||
|
MCZP = Shanghai II Dragon's Eye
|
||||||
|
PAAP = Bomberman'93
|
||||||
|
PAGL = Bomberman'94
|
||||||
|
PARL = Detana Twin Bee
|
||||||
PAWP = Galaga'88
|
PAWP = Galaga'88
|
||||||
PB3P = Devil Crash
|
PB3P = Devil Crash
|
||||||
|
PBEP = Motoroader
|
||||||
PBIP = Bonk III : Bonk's Big Adventure
|
PBIP = Bonk III : Bonk's Big Adventure
|
||||||
|
PBSP = Chew Man Fu
|
||||||
|
PBWP = Air 'Zonk'
|
||||||
PC2P = Taito Chase H.Q.
|
PC2P = Taito Chase H.Q.
|
||||||
PCSL = Digital Champ : Battle Boxing
|
PCSL = Digital Champ : Battle Boxing
|
||||||
|
PDJL = Street Fighter II': Champion Edition
|
||||||
QA3P = SimEarth : The Living Planet
|
QA3P = SimEarth : The Living Planet
|
||||||
|
QAAP = Super Air Zonk
|
||||||
|
QABP = Ys Book I & II
|
||||||
QADL = Gradius II : Gofer no Yabou
|
QADL = Gradius II : Gofer no Yabou
|
||||||
|
QAPL = Castlevania: Rondo of Blood
|
||||||
|
QAPN = Castlevania Rondo of Blood
|
||||||
QAPP = Castlevania : Rondo of Blood
|
QAPP = Castlevania : Rondo of Blood
|
||||||
|
EA5E = Fatal Fury 3: Road to the Final Victory
|
||||||
EA5P = Fatal Fury 3 : Road To The Final Victory
|
EA5P = Fatal Fury 3 : Road To The Final Victory
|
||||||
|
EA7P = Samurai Shodown IV: Amakusa's Revenge
|
||||||
|
EA8M = Iron Clad
|
||||||
|
EAIE = Top Hunter
|
||||||
|
EAIP = Top Hunter
|
||||||
|
EASE = Samurai Shodown 2
|
||||||
|
EBDP = Magical Drop 3
|
||||||
|
EBFP = Spin master
|
||||||
|
EBSP = The Path of the Warrior: Art of Fighting 3
|
||||||
|
ECAP = Real Bout Fatal Fury 2: The Newcomers
|
||||||
|
ECGP = Shock Troopers: 2nd Squad
|
||||||
|
E54P = GHOSTS'N GOBLINS
|
||||||
|
E55P = Commando
|
||||||
|
E57P = SonSon
|
||||||
|
E6PP = NINJA GAIDEN
|
||||||
|
C93P = The Last Ninja 2
|
||||||
|
C96P = Summer Games 2
|
||||||
|
C9IP = Cybernoid
|
||||||
HAAA = Chaîne Photos
|
HAAA = Chaîne Photos
|
||||||
HABA = Chaîne Boutique
|
HABA = Chaîne boutique Wii
|
||||||
HACA = Chaîne Mii
|
HACA = Chaîne Mii
|
||||||
HACK = Chaîne Mii
|
HACK = Chaîne Mii
|
||||||
HADE = Chaîne Internet
|
HADE = Chaîne Internet
|
||||||
HADP = Chaîne Internet
|
HADP = Chaîne Internet
|
||||||
HAFP = Chaîne Météo
|
HAFA = Chaîne météo
|
||||||
|
HAFP = Chaîne météo
|
||||||
|
HAGA = Chaîne infos
|
||||||
HAGE = Chaîne infos
|
HAGE = Chaîne infos
|
||||||
HAGP = Chaîne Infos
|
HAGJ = Chaîne infos
|
||||||
HAJP = Chaîne Votes
|
HAGP = Chaîne infos
|
||||||
HAPP = Chaîne Concours Mii
|
HAJP = Chaîne votes
|
||||||
|
HAPE = Chaîne Regardez-Mii
|
||||||
|
HAPP = Chaîne concours Mii
|
||||||
HATP = Chaîne Nintendo
|
HATP = Chaîne Nintendo
|
||||||
HAYA = Chaîne Photos
|
HAVP = Chaîne jour de chance
|
||||||
|
HAWP = Metroid Prime 3 Preview
|
||||||
|
HAYA = Chaîne photos
|
||||||
|
HAYK = Chaîne Photo
|
||||||
|
HCAP = Jam with the Band Live
|
||||||
|
HCFE = Chaîne Wii Speak
|
||||||
HCFP = Chaîne Wii Speak
|
HCFP = Chaîne Wii Speak
|
||||||
HCMP = Chaîne Kirby TV
|
HCMP = Chaîne Kirby TV
|
||||||
|
HCRE = The Legend of Zelda: Skyward Sword - Chaîne mise à jour des données
|
||||||
|
HCRP = The Legend of Zelda: Skyward Sword - Chaîne mise à jour des données
|
||||||
|
RMCE = Chaîne Mario Kart
|
||||||
|
RMCP = Chaîne Mario Kart
|
||||||
|
DNUA = Donut Wii
|
||||||
|
OHBC = Chaîne Homebrew
|
||||||
|
RMCX = Chaîne Mario Kart Wii CTGP Revolution
|
||||||
G2FF78 = Tak 2: Le Sceptre des Rêves
|
G2FF78 = Tak 2: Le Sceptre des Rêves
|
||||||
G3AF69 = Le Seigneur des Anneaux : Le Tiers Âge
|
G3AF69 = Le Seigneur des Anneaux: Le Tiers Âge
|
||||||
G3DP6L = Carmen Sandiego : Le Secret des Tam-Tams Volés
|
G3DP6L = Carmen Sandiego : Le Secret des Tam-Tams Volés
|
||||||
G3MP41 = La Somme de toutes les Peurs
|
G3MP41 = La Somme de toutes les Peurs
|
||||||
G3XP52 = X-Men: Le Jeu Officiel
|
G3XP52 = X-Men: Le Jeu Officiel
|
||||||
|
@ -854,19 +1042,21 @@ G4ZP69 = Les Sims 2
|
||||||
G5DP78 = Scooby-Doo! : Démasqué
|
G5DP78 = Scooby-Doo! : Démasqué
|
||||||
G6FF69 = Coupe du Monde de la FIFA 2006
|
G6FF69 = Coupe du Monde de la FIFA 2006
|
||||||
G8MP01 = Paper Mario: La Porte Millénaire
|
G8MP01 = Paper Mario: La Porte Millénaire
|
||||||
|
G9TF52 = Gang de Requins
|
||||||
GAVY78 = Avatar : Le Dernier Maître de l'Air
|
GAVY78 = Avatar : Le Dernier Maître de l'Air
|
||||||
GAZF69 = Harry Potter et le Prisonnier d'Azkaban
|
GAZF69 = Harry Potter et le Prisonnier d'Azkaban
|
||||||
GC3F78 = Scooby-Doo! : Le Livre des Ténèbres
|
GC3F78 = Scooby-Doo! Le Livre des Ténèbres
|
||||||
GCBP7D = Crash Bandicoot : La Vengeance de Cortex
|
GCBP7D = Crash Bandicoot: La Vengeance de Cortex
|
||||||
GCGP41 = Charlie's Angels: Les Anges se Déchaînent
|
GCGP41 = Charlie's Angels: Les Anges se Déchaînent
|
||||||
GCIP69 = Les Sims
|
GCIP69 = Les Sims
|
||||||
GCOF52 = Call of Duty : Le Jour De Gloire
|
GCOF52 = Call of Duty : Le Jour De Gloire
|
||||||
GCQF7D = Buffy contre les Vampires : Chaos Bleeds
|
GCQF7D = Buffy contre les Vampires : Chaos Bleeds
|
||||||
GDDP41 = Donald Cou@k Att@k?*!
|
GDDP41 = Donald Cou@k Att@k?*!
|
||||||
GDOP41 = Disney's Donald Qui est PK ?
|
GDOP41 = Disney's Donald Qui est PK?
|
||||||
GENF69 = James Bond 007: Quitte ou Double
|
GENF69 = James Bond 007: Quitte ou Double
|
||||||
GF4F52 = Les 4 Fantastiques
|
GF4F52 = Les 4 Fantastiques
|
||||||
GFAF69 = FIFA Football 2003
|
GFHP6V = Un Voisin d'Enfer!
|
||||||
|
GFSF69 = Coupe du Monde FIFA 2002
|
||||||
GGVX78 = Bob l'Eponge : Le Film
|
GGVX78 = Bob l'Eponge : Le Film
|
||||||
GH2P69 = Need for Speed : Poursuite Infernale 2
|
GH2P69 = Need for Speed : Poursuite Infernale 2
|
||||||
GH4F69 = Harry Potter et la Coupe de Feu
|
GH4F69 = Harry Potter et la Coupe de Feu
|
||||||
|
@ -877,27 +1067,28 @@ GHSY69 = Harry Potter et la Chambre des Secrets
|
||||||
GHVP08 = Disney Cache-Cache Furtif
|
GHVP08 = Disney Cache-Cache Furtif
|
||||||
GIAP7D = L'Age de Glace 2
|
GIAP7D = L'Age de Glace 2
|
||||||
GICF78 = Les Indestructibles
|
GICF78 = Les Indestructibles
|
||||||
|
GIHF78 = Scooby-Doo! La Nuit des 100 Frissons
|
||||||
GIHP78 = Scooby-Doo! : La Nuit des 100 Frissons
|
GIHP78 = Scooby-Doo! : La Nuit des 100 Frissons
|
||||||
GIQX78 = Les Indestructibles: La Terrible Attaque du Démolisseur
|
GIQX78 = Les Indestructibles: La Terrible Attaque du Démolisseur
|
||||||
GJUF78 = Tak et le Pouvoir de Juju
|
GJUF78 = Tak & Le Pouvoir de Juju
|
||||||
GKBPAF = Baten Kaitos : Les Ailes éternelles et l'Océan perdu
|
GKBPAF = Baten Kaitos : Les Ailes éternelles et l'Océan perdu
|
||||||
GKJF78 = Cars: Quatre Roues
|
GKJF78 = Cars: Quatre Roues
|
||||||
GKLF69 = Le Seigneur des Anneaux : Le Retour du Roi
|
GKLF69 = Le Seigneur des Anneaux: Le Retour du Roi
|
||||||
GKMP41 = Prince of Persia: Les Deux Royaumes
|
GKMP41 = Prince of Persia: Les Deux Royaumes
|
||||||
GL5X4F = Lego Star Wars : Le Jeu Vidéo
|
GL5X4F = Lego Star Wars : Le Jeu Vidéo
|
||||||
GL7P64 = Lego Star Wars II: La Trilogie Originale
|
GL7P64 = Lego Star Wars II: La Trilogie Originale
|
||||||
GLCF52 = Les Desastreuses Aventures des Orphelins Baudelaire
|
GLCF52 = Les Désastreuses Aventures des Orphelins Baudelaire: D'Apres Lemony Snicket
|
||||||
GLGP41 = Largo Winch : Aller Simple pour les Balkans
|
GLGP41 = Largo Winch : Aller Simple pour les Balkans
|
||||||
GLHPG9 = Souris City
|
GLHPG9 = Souris City
|
||||||
GLNP69 = Les Looney Tunes Passent à l'Action
|
GLNP69 = Les Looney Tunes Passent à l'Action
|
||||||
GLOF69 = Le Seigneur des Anneaux : Les Deux Tours
|
GLOF69 = Le Seigneur des Anneaux: Les Deux Tours
|
||||||
GLVF4Q = Le Monde de Narnia: Le Lion, la Sorcière et l'Armoire Magique
|
GLVF4Q = Le Monde de Narnia: Le Lion, la Sorcière et l'Armoire Magique
|
||||||
GLZF69 = 007 : Bons Baisers de Russie
|
GLZF69 = 007 : Bons Baisers de Russie
|
||||||
GMFF69 = Medal of Honor : En Première Ligne
|
GMFF69 = Medal of Honor : En Première Ligne
|
||||||
GMNP78 = Monstres & Cie : Crazy Balls
|
GMNP78 = Monstres & Cie : Crazy Balls
|
||||||
GMWF52 = Minority Report: Le futur vous rattrape
|
GMWF52 = Minority Report: Le Futur vous Rattrape
|
||||||
GNEF78 = Le Monde De Némo
|
GNEF78 = Le Monde de Némo
|
||||||
GONF69 = Medal of Honor : Les Faucons de Guerre
|
GONF69 = Medal of Honor: Les Faucons de Guerre
|
||||||
GOSP41 = Les Rebelles de la Forêt
|
GOSP41 = Les Rebelles de la Forêt
|
||||||
GOYF69 = GoldenEye : Au service du Mal
|
GOYF69 = GoldenEye : Au service du Mal
|
||||||
GP3P78 = Le Pole Express
|
GP3P78 = Le Pole Express
|
||||||
|
@ -909,20 +1100,25 @@ GQ4F78 = Bob L'éponge: La Créature du Crabe Croustillant
|
||||||
GQFFFK = Franklin: Un anniversaire surprise
|
GQFFFK = Franklin: Un anniversaire surprise
|
||||||
GQLP54 = Dora l'Exploratrice: Voyage sur la Planète Violette
|
GQLP54 = Dora l'Exploratrice: Voyage sur la Planète Violette
|
||||||
GQPP78 = Bob l'Eponge: Bataille pour Bikini Bottom
|
GQPP78 = Bob l'Eponge: Bataille pour Bikini Bottom
|
||||||
GQQF78 = Bob L'éponge : Silence on tourne!
|
GQQD78 = Bob L'éponge: Silence on tourne!
|
||||||
|
GQQE78 = Bob L'éponge: Silence on tourne!
|
||||||
|
GQQF78 = Bob L'éponge: Silence on tourne!
|
||||||
|
GQQH78 = Bob L'éponge: Silence on tourne!
|
||||||
|
GQQP78 = Bob L'éponge: Silence on tourne!
|
||||||
GQWX69 = Harry Potter: Coupe du Monde de Quidditch
|
GQWX69 = Harry Potter: Coupe du Monde de Quidditch
|
||||||
GR2P52 = Les Royaumes Perdus II
|
GR2P52 = Les Royaumes Perdus II
|
||||||
GR8F69 = Medal of Honor : Soleil Levant
|
GR8F69 = Medal of Honor: Soleil Levant
|
||||||
GR9P6L = Le Règne Du Feu
|
GR9P6L = Le Règne Du Feu
|
||||||
GRNP52 = Les Royaumes Perdus
|
GRNP52 = Les Royaumes Perdus
|
||||||
GRUF78 = Power Rangers : Dino Tonnerre
|
GRRF78 = Les Razmoket: La Rançon Royale
|
||||||
|
GRUF78 = Power Rangers: Dino Tonnerre
|
||||||
GSKP7D = Le Roi Scorpion : L'Ascension de l'Akkadien
|
GSKP7D = Le Roi Scorpion : L'Ascension de l'Akkadien
|
||||||
GTYP69 = Ty: Le Tigre de Tasmanie
|
GTYP69 = Ty: Le Tigre de Tasmanie
|
||||||
GU2F78 = 2 Games in 1: Les Indestructibles / Le Monde de Nemo
|
GU2F78 = 2 Games in 1: Les Indestructibles / Le Monde de Nemo
|
||||||
GU3X78 = 2 Games in 1: Bob L'éponge le Film / Tak 2 Le Sceptre des Rêves
|
GU3X78 = 2 Games in 1: Bob L'éponge le Film / Tak 2 Le Sceptre des Rêves
|
||||||
GUBP69 = Les Urbz: Les Sims in the City
|
GUBP69 = Les Urbz: Les Sims in the City
|
||||||
GVLF69 = Marvel Nemesis : L'Avenement des Imparfaits
|
GVLF69 = Marvel Nemesis: L'Avenement des Imparfaits
|
||||||
GW7F69 = James bond 007 dans Espion pour Cible
|
GW7F69 = James Bond 007 dans Espion pour Cible
|
||||||
GWHP41 = Winnie l'Ourson: à la Recherche des Souvenirs Oubliés
|
GWHP41 = Winnie l'Ourson: à la Recherche des Souvenirs Oubliés
|
||||||
GWLX6L = Wallace & Gromit dans Le Project Zoo
|
GWLX6L = Wallace & Gromit dans Le Project Zoo
|
||||||
GWVX52 = X-Men 2 : La Vengeance de Wolverine
|
GWVX52 = X-Men 2 : La Vengeance de Wolverine
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
TITLES = https://www.gametdb.com (type: Wii language: IT_unique version: 20191106234245)
|
TITLES = https://www.gametdb.com (type: Wii language: IT_unique version: 20230727194156)
|
||||||
R23P52 = Barbie e le Tre Moschettiere
|
R23P52 = Barbie e le Tre Moschettiere
|
||||||
R25PWR = LEGO Harry Potter: Anni 1-4
|
R25PWR = LEGO Harry Potter: Anni 1-4
|
||||||
R2AP7D = L'Era Glaciale 2: Il Disgelo
|
R2AP7D = L'Era Glaciale 2: Il Disgelo
|
||||||
|
@ -91,8 +91,7 @@ RIHP8P = L'Incredibile Hulk
|
||||||
RIJP69 = G.I. Joe: La nascita dei Cobra
|
RIJP69 = G.I. Joe: La nascita dei Cobra
|
||||||
RINP08 = Dead Rising: Salme di Fine Stagione
|
RINP08 = Dead Rising: Salme di Fine Stagione
|
||||||
RIOPSU = Brutte Storie: I Rivoltanti Romani
|
RIOPSU = Brutte Storie: I Rivoltanti Romani
|
||||||
RIPPAF = One Piece Unlimited Cruise 1 - The Treasure Beneath the Waves
|
RIUPAF = One Piece: Unlimited Cruise 2: Il Risveglio di un Eroe
|
||||||
RIUPAF = One Piece Unlimited Cruise 2: Il Risveglio di un Eroe
|
|
||||||
RJ8E64 = Indiana Jones e il Bastone dei Re
|
RJ8E64 = Indiana Jones e il Bastone dei Re
|
||||||
RJ8P64 = Indiana Jones e il Bastone dei Re
|
RJ8P64 = Indiana Jones e il Bastone dei Re
|
||||||
RJAX52 = Call of Duty: Modern Warfare - Edizione Reflex
|
RJAX52 = Call of Duty: Modern Warfare - Edizione Reflex
|
||||||
|
@ -107,7 +106,7 @@ RLBPWR = LEGO Batman: Il Videogioco
|
||||||
RLFP64 = Star Wars The Clone Wars: L'era dei duelli
|
RLFP64 = Star Wars The Clone Wars: L'era dei duelli
|
||||||
RLGP64 = LEGO Star Wars: La Saga Completa
|
RLGP64 = LEGO Star Wars: La Saga Completa
|
||||||
RLIP64 = LEGO Indiana Jones: Le Avventure Originali
|
RLIP64 = LEGO Indiana Jones: Le Avventure Originali
|
||||||
RLLP70 = Go West!: Un'Avventura di Lucky Luke
|
RLLP70 = Go West! Un'Avventura di Lucky Luke
|
||||||
RLNFMR = L'Isola dei Famosi
|
RLNFMR = L'Isola dei Famosi
|
||||||
RLNHMR = L'Isola dei Famosi
|
RLNHMR = L'Isola dei Famosi
|
||||||
RLNIMR = L'Isola dei Famosi
|
RLNIMR = L'Isola dei Famosi
|
||||||
|
@ -133,7 +132,7 @@ RO8X7D = The Legend of Spyro: L'Alba del Drago
|
||||||
ROEPGT = Hotel Bau
|
ROEPGT = Hotel Bau
|
||||||
ROLP8P = Mario & Sonic ai Giochi Olimpici Invernali
|
ROLP8P = Mario & Sonic ai Giochi Olimpici Invernali
|
||||||
ROPP41 = Boog & Elliot a Caccia Di Amici
|
ROPP41 = Boog & Elliot a Caccia Di Amici
|
||||||
ROUPAF = One Piece Unlimited Cruise 1: Il Tesoro Sommerso
|
ROUPAF = One Piece: Unlimited Cruise 1: Il Tesoro Sommerso
|
||||||
ROYP41 = Piovono Polpette: Il Videogioco
|
ROYP41 = Piovono Polpette: Il Videogioco
|
||||||
ROYX41 = Piovono Polpette
|
ROYX41 = Piovono Polpette
|
||||||
RP2P69 = Le So Tutte!
|
RP2P69 = Le So Tutte!
|
||||||
|
@ -253,6 +252,7 @@ S75P69 = Monopoly
|
||||||
S7FPGT = Zumba Kids: Che la festa abbia inizio, con Zumba!
|
S7FPGT = Zumba Kids: Che la festa abbia inizio, con Zumba!
|
||||||
S7SP41 = I Puffi Party Pack
|
S7SP41 = I Puffi Party Pack
|
||||||
SA3P5G = Alvin Superstar 3: Si Salvi Chi Può
|
SA3P5G = Alvin Superstar 3: Si Salvi Chi Può
|
||||||
|
SA3XGT = Alvin Superstar 3: Si Salvi Chi Può
|
||||||
SALP4Q = Alice nel Paese delle Meraviglie
|
SALP4Q = Alice nel Paese delle Meraviglie
|
||||||
SAOP78 = Monster High: Scuola da Paura
|
SAOP78 = Monster High: Scuola da Paura
|
||||||
SAOXVZ = Monster High: Scuola da Paura
|
SAOXVZ = Monster High: Scuola da Paura
|
||||||
|
@ -342,8 +342,9 @@ SU7PAF = Le 5 Leggende
|
||||||
SUUP78 = uDraw Studio: E sei subito artista!
|
SUUP78 = uDraw Studio: E sei subito artista!
|
||||||
SV3PAF = Madagascar 3: Ricercati in Europa
|
SV3PAF = Madagascar 3: Ricercati in Europa
|
||||||
SV7PVZ = I Pinguini di Madagascar
|
SV7PVZ = I Pinguini di Madagascar
|
||||||
SVDP52 = SpongeBob: La Vendetta Robotica de Plankton
|
SVDP52 = SpongeBob: La Vendetta Robotica di Plankton
|
||||||
SVMP01 = Super Mario All-Stars: Edizione per il 25° anniversario
|
SVMP01 = Super Mario All-Stars: Edizione per il 25° anniversario
|
||||||
|
SVQEVZ = Barbie e le sue sorelle: Salvataggio Cuccioli
|
||||||
SVQPVZ = Barbie e le sue sorelle: Salvataggio Cuccioli
|
SVQPVZ = Barbie e le sue sorelle: Salvataggio Cuccioli
|
||||||
SVVPAF = I Croods: Festa Preistorica!
|
SVVPAF = I Croods: Festa Preistorica!
|
||||||
SXAP52 = Guitar Hero 4: World Tour
|
SXAP52 = Guitar Hero 4: World Tour
|
||||||
|
@ -351,29 +352,155 @@ SXIP52 = Guitar Hero 6: Warriors of Rock
|
||||||
CGIE52 = Guitar Hero III Custom: Iron Maiden
|
CGIE52 = Guitar Hero III Custom: Iron Maiden
|
||||||
CLAPSI = SingItStar Clásicos
|
CLAPSI = SingItStar Clásicos
|
||||||
DMSP4Q = Sing It Star e la Magia Disney
|
DMSP4Q = Sing It Star e la Magia Disney
|
||||||
|
G01E01 = Super Smash Bros. Melee: Remix SD
|
||||||
MILPSI = SingItStar Miliki
|
MILPSI = SingItStar Miliki
|
||||||
R15POH = SingItStar Radio 105
|
R15POH = SingItStar Radio 105
|
||||||
RGGE52 = Guitar Hero III Custom: Rock The Games
|
RGGE52 = Guitar Hero III Custom: Rock The Games
|
||||||
|
RMCPCA = Mario Kart Wii (traduzione in catalano)
|
||||||
RSJESD = Guitar Hero III Custom: System Of A Down
|
RSJESD = Guitar Hero III Custom: System Of A Down
|
||||||
S02PES = SingItStar 90's
|
S02PES = SingItStar 90's
|
||||||
SILP4Q = Sing It: Latino
|
SILP4Q = Sing It: Latino
|
||||||
SP9P4Q = SingItStar POP 2009
|
SP9P4Q = SingItStar POP 2009
|
||||||
WFFF4I = Fatal Frame 4: La Maschera dell'eclissi lunare
|
WFFF4I = Fatal Frame 4: La Maschera dell'eclissi lunare
|
||||||
W2CP = Brain Challenge L'Allena-Mente
|
W2CP = Brain Challenge L'Allena-Mente
|
||||||
|
W2FP = Physiofun - Balance Training
|
||||||
|
W2GD = Phoenix Wright Ace Attorney: Justice for All (Deutsche Version)
|
||||||
|
W2GI = Phoenix Wright: Ace Attorney: Justice for All
|
||||||
|
W2GP = Phoenix Wright Ace Attorney: Justice for All
|
||||||
|
W2MP = Blaster Master: Overdrive
|
||||||
|
W2PP = Physiofun: Pelvic Floor Training
|
||||||
|
W3GI = Phoenix Wright: Ace Attorney: Trials and Tribulations
|
||||||
|
W3KP = ThruSpace: High Velocity 3D Puzzle
|
||||||
W3MP = I Tre Moschettieri Uno per tutti!
|
W3MP = I Tre Moschettieri Uno per tutti!
|
||||||
|
W44P = Stop Stress: A Day of Fury
|
||||||
|
W4AP = Arcade Sports: Air Hockey, Bowling, Pool, Snooker
|
||||||
W6BP = 530 ECO SHOOTER
|
W6BP = 530 ECO SHOOTER
|
||||||
|
W72P = Successfully Learning German Year 3
|
||||||
|
W73P = Successfully Learning German Year 4
|
||||||
|
W74P = Successfully Learning German Year 5
|
||||||
|
W7IP = Successfully Learning German Year 2
|
||||||
|
W8CP = Bit.Trip Core
|
||||||
W8WP = Happy Holidays Halloween
|
W8WP = Happy Holidays Halloween
|
||||||
|
W9BP = Big Town Shoot
|
||||||
W9RP = Happy Holidays Christmas
|
W9RP = Happy Holidays Christmas
|
||||||
|
WA4P = WarioWare: Do It Yourself - Showcase
|
||||||
|
WA7P = Toribash Violence Perfected
|
||||||
|
WA8P = Art Style: Penta Tentacles
|
||||||
|
WAEP = Around the world
|
||||||
|
WAFP = Airport Mania: First Flight
|
||||||
|
WAHP = Trenches: Generals
|
||||||
|
WALP = Art Style: light trax
|
||||||
|
WAOP = The Very Hungry Caterpillar´s ABC
|
||||||
|
WB2P = Strong Bad Episode 4: Dangeresque 3
|
||||||
|
WB3P = Strong Bad Episode 5: 8-bit is Enough
|
||||||
|
WBEP = Beer Pong: Frat Party Games
|
||||||
|
WBFP = Bit.Trip Fate
|
||||||
|
WBGP = Bang Attack
|
||||||
|
WBPP = PLÄTTCHEN - twist 'n' paint
|
||||||
|
WBRP = Pirates: The Key of Dreams
|
||||||
|
WBXP = Strong Bad Episode 1: Homestar Ruiner
|
||||||
|
WBYP = Strong Bad Episode 2: Strong Badia - The Free
|
||||||
|
WBZP = Strong Bad Episode 3: Baddest of the Bands
|
||||||
|
WCHP = Chess Challenge
|
||||||
|
WCJP = Cocoto: Platform Jumper
|
||||||
|
WCKP = chick chick BOOM
|
||||||
|
WCSP = CueSports: Snooker vs Billiards
|
||||||
|
WDEP = Magic Destiny Astrological Games
|
||||||
|
WDFP = Defend your Castle
|
||||||
|
WDHP = Art Style: ROTOHEX
|
||||||
WDMP = Dr. Mario & Sterminavirus
|
WDMP = Dr. Mario & Sterminavirus
|
||||||
|
WDPP = Dr. Mario & Germ Buster (Friend Battle Demo)
|
||||||
|
WEMP = Aha! I Got It! Escape Game
|
||||||
WETP = Giochi da tavolo animati: Un'avventura pop-up!
|
WETP = Giochi da tavolo animati: Un'avventura pop-up!
|
||||||
|
WF2P = Final Fantasy Crystal Chronicles: My Life as a Darklord
|
||||||
|
WF4P = Final Fantasy IV: The After Years
|
||||||
|
WFCP = Final Fantasy Crystal Chronicles: My Life as a King
|
||||||
|
WFQP = Frogger: Hyper Arcade Edition
|
||||||
|
WFTP = Fish'em All!
|
||||||
|
WFVP = Football Up
|
||||||
|
WFWP = Flowerworks: Follie's Adventure
|
||||||
|
WGFP = Girlfriends Forever: Magic Skate
|
||||||
|
WGGP = Gabrielle's Ghostly Groove: Monster Mix
|
||||||
WGPP = Zenquaria™: Acquario virtuale
|
WGPP = Zenquaria™: Acquario virtuale
|
||||||
|
WGSF = Phoenix Wright: Ace Attorney (French Version)
|
||||||
|
WGSI = Phoenix Wright: Ace Attorney
|
||||||
|
WGSP = Phoenix Wright: Ace Attorney
|
||||||
|
WHEP = Heracles: Chariot Racing
|
||||||
|
WHFP = Heavy Fire: Special Operations
|
||||||
|
WHRP = Heron: Steam Machine
|
||||||
WHUP = Fantasma Party
|
WHUP = Fantasma Party
|
||||||
|
WHWP = HoopWorld: BasketBrawl
|
||||||
|
WICP = NyxQuest: Kindred Spirits
|
||||||
|
WIDP = Dracula: Undead Awakening
|
||||||
|
WIEP = Tales of Monkey Island Chapter 3: Lair of the Leviathan
|
||||||
|
WILP = Tales of Monkey Island Chapter 1: Launch of the Screaming Narwhal
|
||||||
|
WIRP = Tales of Monkey Island Chapter 5: Rise Of The Pirate God
|
||||||
|
WISP = Tales of Monkey Island Chapter 2: The Siege of Spinner Cay
|
||||||
|
WITP = Aha! I Found It! Hidden Object Game
|
||||||
|
WIYP = Tales of Monkey Island Chapter 4: The Trial and Execution of Guybrush Threepwood
|
||||||
|
WJKP = Jewel Keepers: Easter Island
|
||||||
|
WKBP = You, Me and the Cubes
|
||||||
|
WKFP = Kung Fu Funk: Everybody Is Kung Fu Fighting
|
||||||
|
WKKP = Pop-Up Pirates!
|
||||||
|
WKRP = Karate Phants: Gloves of Glory
|
||||||
|
WKWP = Adventure on LOST ISLAND: Hidden Object Game
|
||||||
WLEE = Impara con i PooYoo: Episodio 1
|
WLEE = Impara con i PooYoo: Episodio 1
|
||||||
WLEP = Impara con i PooYoo: Episodio 1
|
WLEP = Impara con i PooYoo: Episodio 1
|
||||||
WLNE = Impara con i PooYoo: Episodio 2
|
WLNE = Impara con i PooYoo: Episodio 2
|
||||||
WLNP = Impara con i PooYoo: Episodio 2
|
WLNP = Impara con i PooYoo: Episodio 2
|
||||||
|
WLOP = LostWinds: Winter of the Melodias
|
||||||
|
WLZP = lilt line
|
||||||
|
WM7P = Anima Ark of Sinners
|
||||||
WMBP = MaBoShi: L'arcade delle tre forme
|
WMBP = MaBoShi: L'arcade delle tre forme
|
||||||
|
WMCP = Monsteca Corral: Monsters Vs. Robots
|
||||||
|
WMJP = Dive: The Medes Islands Secret
|
||||||
|
WMSP = Enjoy your massage!
|
||||||
|
WN9E = Military Madness: Nectaris
|
||||||
|
WN9P = Military Madness: Nectaris
|
||||||
|
WNEE = Penguins & Friends Hey! That's My Fish!
|
||||||
|
WNEP = Penguins & Friends Hey! That’s my Fish!
|
||||||
|
WNVP = Neves Plus: Phantheon of Tangrams
|
||||||
|
WOBP = Art Style: ORBIENT
|
||||||
|
WOTP = Overturn: Mecha Wars
|
||||||
|
WP3P = Pearl Harbor Trilogy 1941: Red Sun Rising
|
||||||
|
WP4P = Learning with the PooYoos: Episode 3
|
||||||
|
WPKP = Texas Hold'Em Poker
|
||||||
|
WPQP = Protöthea
|
||||||
|
WPRP = Art Style: CUBELLO
|
||||||
|
WPVP = The Tales of Bearsworth Manor: Chaotic Conflicts
|
||||||
|
WREP = Racers Islands Crazy Arenas
|
||||||
|
WRIP = Rainbow Islands: Towering Adventure!
|
||||||
|
WRJP = Racers Islands - Crazy Racers
|
||||||
|
WRLP = FAST Racing League
|
||||||
|
WRRP = Robin Hood: The Return Of Richard
|
||||||
|
WRUP = Bit.Trip Runner
|
||||||
|
WSGP = Pop Them, Drop Them SAMEGAME
|
||||||
|
WSNP = Sonic The Hedgehog 4 Episode I
|
||||||
|
WSUP = Shootanto: Evolutionary Mayhem
|
||||||
|
WTEP = Tales of Elastic Boy Mission 1
|
||||||
|
WTFP = Bit.Trip Flux
|
||||||
WTMP = ADVENTURE ISLAND The Beginning
|
WTMP = ADVENTURE ISLAND The Beginning
|
||||||
|
WTRP = Bit.Trip Beat
|
||||||
|
WTWP = Fenimore Fillmore: The Westerner
|
||||||
|
WTXP = Texas Hold’em Tournament
|
||||||
|
WU2P = Successfully Learning Mathematics Year 3
|
||||||
|
WU3P = Successfully Learning Mathematics Year 4
|
||||||
|
WU4P = Successfully Learning Mathematics Year 5
|
||||||
|
WUIP = Successfully Learning Mathematics Year 2
|
||||||
|
WVBP = Bit.Trip Void
|
||||||
|
WVOP = Rock'n Roll Climber
|
||||||
|
WVSP = Gods Vs Humans
|
||||||
|
WVUP = Mr Bumblebee Racing Champion
|
||||||
|
WW2P = Where's Wally? Fantastic Journey 2
|
||||||
|
WW3P = Where's Wally? Fantastic Journey 3
|
||||||
|
WWIP = Where's Wally? Fantastic Journey 1
|
||||||
|
WWRP = Excitebike: World Challenge
|
||||||
|
WWXP = Paper Wars Cannon Fodder
|
||||||
|
WXBP = Ben 10: Alien Force - The Rise of Hex
|
||||||
|
WYIP = escapeVektor: Chapter 1
|
||||||
|
WYSP = Yard Sale Hidden Treasures Sunnyville
|
||||||
|
WZIP = Rubik's Puzzle Galaxy: RUSH
|
||||||
|
WZZP = The Tales of Bearsworth Manor: Puzzling Pages
|
||||||
XIBP = Fish em All Demo
|
XIBP = Fish em All Demo
|
||||||
XICP = Gods vs Humans Demo
|
XICP = Gods vs Humans Demo
|
||||||
XIDP = Racers Islands Crazy Racers Demo
|
XIDP = Racers Islands Crazy Racers Demo
|
||||||
|
@ -390,35 +517,147 @@ XIUP = Soccer Bashi Demo
|
||||||
XIVP = Mix Superstar Demo
|
XIVP = Mix Superstar Demo
|
||||||
XIZP = 3D Pixel Racing Demo
|
XIZP = 3D Pixel Racing Demo
|
||||||
XJEP = Aya and the Cubes of Light Demo
|
XJEP = Aya and the Cubes of Light Demo
|
||||||
|
FA9P = Zelda II: The Adventure of Link
|
||||||
|
FB2L = Super Mario Bros.: The Lost Levels
|
||||||
|
FBKP = Teenage Mutant Ninja Turles
|
||||||
|
FC8P = Castlevania II: Simon's Quest
|
||||||
|
FCSP = Probotector II: Return of the Evil Forces
|
||||||
|
FDGP = Ghosts'n Goblins
|
||||||
|
FDRP = Skate or Die
|
||||||
|
FEML = Bio Miracle Bokutte UPA
|
||||||
|
FEQP = Castlevania III Dracula's Curse
|
||||||
FERM = Zoda's Revenge: StarTropics II
|
FERM = Zoda's Revenge: StarTropics II
|
||||||
FFVM = S.C.A.T.
|
FF5P = Double Dragon II: The Revenge
|
||||||
|
FFEP = A Boy and His Blob: Trouble on Blobolonia
|
||||||
|
FFPP = Ufouria: THE SAGA
|
||||||
|
FFUP = Adventure Island 2
|
||||||
FFWP = Donkey Kong: Edizione Originale
|
FFWP = Donkey Kong: Edizione Originale
|
||||||
FFXP = Super Mario Brothers: Edizione Esclusiva per il 25° Anniversario
|
FFXP = Super Mario Brothers: Edizione Esclusiva per il 25° Anniversario
|
||||||
JCCP = Kirby's Fun Pak
|
JA4P = Super Ghouls'n Ghosts
|
||||||
|
JABL = Mario’s Super Picross
|
||||||
|
JADP = The Legend of Zelda: A Link to the Past
|
||||||
|
JAFP = SimCity
|
||||||
|
JAHP = R-TYPE III: The Third Lightning
|
||||||
|
JAJP = Street Fighter II: The World Warrior
|
||||||
|
JALP = Super Probotector: Alien Rebels
|
||||||
|
JAZP = The Legend of the Mystical Ninja
|
||||||
|
JBBP = Super Street Fighter II: The New Challengers
|
||||||
|
JBDP = Donkey Kong Country 2: Diddy's Kong-Quest
|
||||||
|
JBIP = Street Fighter II Turbo: Hyper Fighting
|
||||||
|
JBPP = Donkey Kong Country 3: Dixie Kong’s Double Trouble
|
||||||
|
JCAL = DoReMi Fantasy - Milon’s DokiDoki Adventure
|
||||||
|
JCBM = Super Mario RPG: Legend of the Seven Stars
|
||||||
|
JCDM = Kirby’s Dream Land 3
|
||||||
|
JCJP = Super Punch Out!!
|
||||||
|
JCKP = Space Invaders -The Original Game-
|
||||||
|
JCTM = Ogre Battle: The March of the Black Queen
|
||||||
|
JD3P = SUPER E.D.F.: Earth Defense Force
|
||||||
|
JDJP = Super Star Wars: The Empire Strikes Back
|
||||||
|
JDLP = Super Star Wars: Return of the Jedi
|
||||||
|
JDWP = Aero The Acrobat
|
||||||
|
JDZP = Mystic Quest Legend
|
||||||
JECM = CHRONO TRIGGER
|
JECM = CHRONO TRIGGER
|
||||||
|
NACP = The Legend of Zelda: Ocarina of Time
|
||||||
|
NAKS = Pokémon Snap
|
||||||
|
NAMP = Kirby 64: The Crystal Shards
|
||||||
|
NAOP = 1080°: TenEighty Snowboarding
|
||||||
|
NARP = The Legend of Zelda: Majora's Mask
|
||||||
|
NAYM = Ogre Battle 64: Person of Lordly Caliber
|
||||||
|
LALP = Fantasy Zone II
|
||||||
|
LANP = Alex Kidd: The Lost Stars
|
||||||
|
LAPP = Wonder Boy III: The Dragon's Trap
|
||||||
|
MA8P = Ecco: The Tides of Time
|
||||||
|
MAHP = Sonic the Hedgehog
|
||||||
|
MAKP = Shadow Dancer: The Secret of Shinobi
|
||||||
|
MALP = Bonanza Bros.
|
||||||
|
MAOP = Bio-Hazard Battle
|
||||||
|
MAVP = Wonder Boy In Monster World
|
||||||
|
MAXP = Alex Kidd In The Enchanted Castle
|
||||||
|
MB6P = Shining Force II
|
||||||
|
MBBP = Sonic the Hedgehog 2
|
||||||
|
MBFP = Shinobi III: Return of the Ninja master
|
||||||
|
MBIP = Landstalker: The Treasures of King Nole
|
||||||
|
MBJP = Ghouls'n Ghosts
|
||||||
|
MBLP = ESWAT City Under Siege
|
||||||
|
MBMP = Sonic the Hedgehog 3
|
||||||
|
MBUP = Sonic 3D: Flickies' Island
|
||||||
|
MBWM = Columns III: Revenge of Columns
|
||||||
|
MC3P = Super Street Fighter II: The New Challengers
|
||||||
|
MCCP = Phantasy Star III: Generations of Doom
|
||||||
|
MCHM = MUSHA
|
||||||
|
MCLP = Street Fighter II’: Special Champion Edition
|
||||||
|
MCQP = Boogerman - A Pick and Flick Adventure
|
||||||
|
MCRP = Wolf of the Battlefield: MERCS
|
||||||
|
MCSP = Wonder Boy III: Monster Lair
|
||||||
|
MCVP = Pitfall: The Mayan Adventure
|
||||||
|
MCZP = Shanghai II Dragon's Eye
|
||||||
|
PAAP = Bomberman'93
|
||||||
|
PAGL = Bomberman'94
|
||||||
|
PARL = Detana Twin Bee
|
||||||
|
PAWP = Galaga'90
|
||||||
|
PBEP = Motoroader
|
||||||
|
PBIP = Bonk III: Bonk's Big Adventure
|
||||||
|
PBSP = Chew Man Fu
|
||||||
|
PBWP = Air 'Zonk'
|
||||||
PCSL = DIGITAL CHAMP Battle Boxing
|
PCSL = DIGITAL CHAMP Battle Boxing
|
||||||
|
PDJL = Street Fighter II': Champion Edition
|
||||||
|
QA3P = SimEarth: The Living Planet
|
||||||
|
QAAP = Super Air Zonk
|
||||||
|
QABP = Ys Book I & II
|
||||||
|
QADL = Gradius II: Gofer no Yabou
|
||||||
QAPL = CASTLEVANIA RONDO OF BLOOD
|
QAPL = CASTLEVANIA RONDO OF BLOOD
|
||||||
QAPP = CASTLEVANIA RONDO OF BLOOD
|
QAPP = CASTLEVANIA RONDO OF BLOOD
|
||||||
SP4V = CASTLEVANIA RONDO OF BLOOD
|
SP4V = CASTLEVANIA RONDO OF BLOOD
|
||||||
|
EA5P = Fatal Fury 3: Road To The Final Victory
|
||||||
|
EA7P = Samurai Shodown IV: Amakusa's Revenge
|
||||||
|
EA8M = Iron Clad
|
||||||
|
EAIP = Top Hunter
|
||||||
|
EBDP = Magical Drop 3
|
||||||
|
EBFP = Spin master
|
||||||
|
EBSP = The Path of the Warrior: Art of Fighting 3
|
||||||
|
ECAP = Real Bout Fatal Fury 2: The Newcomers
|
||||||
|
ECGP = Shock Troopers: 2nd Squad
|
||||||
|
E54P = GHOSTS'N GOBLINS
|
||||||
E55P = Wolf of the Battlefield: Commando
|
E55P = Wolf of the Battlefield: Commando
|
||||||
|
E57P = SonSon
|
||||||
|
E6PP = NINJA GAIDEN
|
||||||
|
C93P = The Last Ninja 2
|
||||||
|
C96P = Summer Games 2
|
||||||
|
C9IP = Cybernoid
|
||||||
HAAA = Canale Foto
|
HAAA = Canale Foto
|
||||||
|
HABA = Canale Wii Shop
|
||||||
|
HACA = Canale Mii
|
||||||
|
HADE = Canale Internet
|
||||||
HADP = Canale Internet
|
HADP = Canale Internet
|
||||||
HAFP = Canale Meteo
|
HAFP = Canale Meteo
|
||||||
|
HAGA = Canale Notizie
|
||||||
HAGE = Canale Notizie
|
HAGE = Canale Notizie
|
||||||
|
HAGJ = Canale Notizie
|
||||||
HAGP = Canale Notizie
|
HAGP = Canale Notizie
|
||||||
|
HAJP = Canale Vota Anche Tu
|
||||||
|
HAPP = Canale Concorsi Mii
|
||||||
|
HATP = Canale Nintendo
|
||||||
|
HAVP = Canal La fortuna ti sorride
|
||||||
|
HAWP = Metroid Prime 3 Preview
|
||||||
HAYA = Canale Foto
|
HAYA = Canale Foto
|
||||||
|
HCFE = Canale Wii Speak
|
||||||
|
HCFP = Canale Wii Speak
|
||||||
|
HCMP = Canale TV Kirby
|
||||||
|
HCRE = The Legend of Zelda: Skyward Sword - Canale Aggrioornamento dati di
|
||||||
|
HCRP = The Legend of Zelda: Skyward Sword - Canale Aggrioornamento dati di
|
||||||
|
RMCP = Canale Mario Kart
|
||||||
JODI = Canale Homebrew
|
JODI = Canale Homebrew
|
||||||
LULZ = Canale Homebrew
|
LULZ = Canale Homebrew
|
||||||
OHBC = Canale Homebrew
|
OHBC = Canale Homebrew
|
||||||
G01E01 = Super Smash Bros. Melee: Remix SD
|
|
||||||
G4MP69 = The Sims: Fuori Tutti
|
G4MP69 = The Sims: Fuori Tutti
|
||||||
G8MP01 = Paper Mario: Il Portale Millenario
|
G8MP01 = Paper Mario: Il Portale Millenario
|
||||||
GAZI69 = Harry Potter e il prigioniero di Azkaban
|
GAZI69 = Harry Potter e il Prigioniero di Azkaban
|
||||||
GCBP7D = Crash Bandicoot: L'ira di Cortex
|
GCBP7D = Crash Bandicoot: L'ira di Cortex
|
||||||
GCOP52 = Call of Duty: L'Ora Degli Eroi
|
GCOP52 = Call of Duty: L'Ora Degli Eroi
|
||||||
GDDP41 = Paperino: Oper@zione P@pero ?*!
|
GDDP41 = Paperino: Oper@zione P@pero ?*!
|
||||||
GDOP41 = Disney's Donald Chi è PK?
|
GDOP41 = Disney's Donald Chi è PK?
|
||||||
GF4I52 = I fantastici 4
|
GF4I52 = I Fantastici 4
|
||||||
|
GFSP69 = Mondiali FIFA 2002
|
||||||
GH4I69 = Harry Potter e il Calice di Fuoco
|
GH4I69 = Harry Potter e il Calice di Fuoco
|
||||||
GHBP7D = Lo Hobbit
|
GHBP7D = Lo Hobbit
|
||||||
GHLZ69 = Harry Potter e la Pietra Filosofale
|
GHLZ69 = Harry Potter e la Pietra Filosofale
|
||||||
|
@ -430,11 +669,17 @@ GKMP41 = Prince of Persia: I Due Troni
|
||||||
GLCP52 = Lemony Snicket Una serie di sfortunati eventi
|
GLCP52 = Lemony Snicket Una serie di sfortunati eventi
|
||||||
GLHPG9 = Giù Per il Tubo
|
GLHPG9 = Giù Per il Tubo
|
||||||
GLOI69 = Il Signore degli Anelli: Le Due Torri
|
GLOI69 = Il Signore degli Anelli: Le Due Torri
|
||||||
|
GNEP78 = Alla ricerca di Nemo
|
||||||
GOSX41 = Boog & Elliot
|
GOSX41 = Boog & Elliot
|
||||||
GPXP01 = Pokémon Box: Rubino e Zaffiro
|
GPXP01 = Pokémon Box: Rubino e Zaffiro
|
||||||
|
GQQD78 = SpongeBob: Ciak si gira!
|
||||||
|
GQQE78 = SpongeBob: Ciak si gira!
|
||||||
|
GQQF78 = SpongeBob: Ciak si gira!
|
||||||
|
GQQH78 = SpongeBob: Ciak si gira!
|
||||||
|
GQQP78 = SpongeBob: Ciak si gira!
|
||||||
GQWX69 = Harry Potter: La Coppa del Mundo di Quidditch
|
GQWX69 = Harry Potter: La Coppa del Mundo di Quidditch
|
||||||
GR9P6L = Il Regno del Fuoco
|
GR9P6L = Il Regno del Fuoco
|
||||||
GSXI64 = Star Wars - La Guerra dei Cloni
|
GSXI64 = Star Wars: La Guerra dei Cloni
|
||||||
GTYP69 = Ty la Tigre della Tasmania
|
GTYP69 = Ty la Tigre della Tasmania
|
||||||
GVLP69 = Marvel Nemesis: L'Ascesa degli Esseri Imperfetti
|
GVLP69 = Marvel Nemesis: L'Ascesa degli Esseri Imperfetti
|
||||||
GWHP41 = Winnie the Pooh e le Pance Brontolanti
|
GWHP41 = Winnie the Pooh e le Pance Brontolanti
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
TITLES = https://www.gametdb.com (type: Wii language: JA_unique version: 20191106234252)
|
TITLES = https://www.gametdb.com (type: Wii language: JA_unique version: 20230727194203)
|
||||||
D2AJAF = みんなで冒険!ファミリートレーナー 体験版
|
D2AJAF = みんなで冒険!ファミリートレーナー 体験版
|
||||||
DCHJAF = WE CHEER
|
DCHJAF = WE CHEER: おはスタプロデュース! 限定コラボゲームディスク
|
||||||
DHHJ8J = 平野綾 Premiumムービーディスク from 涼宮ハルヒの激動
|
DHHJ8J = 平野綾 Premiumムービーディスク from 涼宮ハルヒの激動
|
||||||
DK6J18 = コロリンパ2 -アンソニーと黃金のひまわりのタネ-
|
DK6J18 = コロリンパ2 -アンソニーと黃金のひまわりのタネ-
|
||||||
DQAJK2 = アクエリアスベースボール 〜限界の、その先へ〜
|
DQAJK2 = アクエリアスベースボール 〜限界の、その先へ〜
|
||||||
|
@ -14,7 +14,7 @@ R2JJAF = 太鼓の達人Wii
|
||||||
R2LJMS = Hula Wii フラで始める 美と健康!!
|
R2LJMS = Hula Wii フラで始める 美と健康!!
|
||||||
R2PJ9B = スイングゴルフ パンヤ 2ndショット!
|
R2PJ9B = スイングゴルフ パンヤ 2ndショット!
|
||||||
R2QJC0 = クッキングママ2 たいへん!ママは おおいそがし!!
|
R2QJC0 = クッキングママ2 たいへん!ママは おおいそがし!!
|
||||||
R2SJ18 = デカスポルタ2
|
R2SJ18 = Deca Sporta 2: Wiiでスポーツ"10"種目!
|
||||||
R2UJ8P = レッツタップ
|
R2UJ8P = レッツタップ
|
||||||
R2VJ01 = 罪と罰 宇宙の後継者
|
R2VJ01 = 罪と罰 宇宙の後継者
|
||||||
R2WJA4 = ウイニングイレブン プレーメーカー 2009
|
R2WJA4 = ウイニングイレブン プレーメーカー 2009
|
||||||
|
@ -28,7 +28,7 @@ R3OJ01 = メトロイド アザーエム
|
||||||
R3PJ52 = スピード・レーサー
|
R3PJ52 = スピード・レーサー
|
||||||
R3TJG9 = トップスピン3
|
R3TJG9 = トップスピン3
|
||||||
R3UJGD = おやこであそぼ ミッフィーのおもちゃばこ
|
R3UJGD = おやこであそぼ ミッフィーのおもちゃばこ
|
||||||
R43J13 = パーソナルトレーナーWii30日生活改善プログラム
|
R43J13 = EA Sports アクティブ パーソナルトレーナー: Wii30日生活改善プログラム
|
||||||
R44J8P = 涼宮ハルヒの並列
|
R44J8P = 涼宮ハルヒの並列
|
||||||
R46JKB = ファントム・ブレイブWii
|
R46JKB = ファントム・ブレイブWii
|
||||||
R49J01 = Wiiであそぶ ドンキーコングジャングルビート
|
R49J01 = Wiiであそぶ ドンキーコングジャングルビート
|
||||||
|
@ -69,7 +69,7 @@ R8DJA4 = 遊戯王ファイブディーズ デュエルトランサー
|
||||||
R8EJQC = アースシーカー
|
R8EJQC = アースシーカー
|
||||||
R8FJHA = 匠レストランは大繁盛!
|
R8FJHA = 匠レストランは大繁盛!
|
||||||
R8GJC8 = ジーワンジョッキー Wii 2008
|
R8GJC8 = ジーワンジョッキー Wii 2008
|
||||||
R8NJG0 = バッティング レボリューション
|
R8NJG0 = 日本野球機構承認 - バッティング レボリューション
|
||||||
R8PJ01 = スーパーペーパーマリオ
|
R8PJ01 = スーパーペーパーマリオ
|
||||||
R92J01 = Wiiであそぶ ピクミン2
|
R92J01 = Wiiであそぶ ピクミン2
|
||||||
R96JAF = 風のクロノア -door to phantomile-
|
R96JAF = 風のクロノア -door to phantomile-
|
||||||
|
@ -95,7 +95,7 @@ RC5JDQ = お掃除戦隊くりーんきーぱー
|
||||||
RCAJ78 = カーズ
|
RCAJ78 = カーズ
|
||||||
RCCJC0 = クッキングママ みんなといっしょにお料理大会
|
RCCJC0 = クッキングママ みんなといっしょにお料理大会
|
||||||
RCDE52 = コール オブ デューティ3
|
RCDE52 = コール オブ デューティ3
|
||||||
RCHJAF = WE CHEER ~ウィーチア~
|
RCHJAF = WE CHEER
|
||||||
RCOJ99 = 名探偵コナン -追憶の幻想-
|
RCOJ99 = 名探偵コナン -追憶の幻想-
|
||||||
RCPJ18 = コロリンパ
|
RCPJ18 = コロリンパ
|
||||||
RCQJDA = チョロQ Wii
|
RCQJDA = チョロQ Wii
|
||||||
|
@ -107,7 +107,7 @@ RDBJAF = ドラゴンボールZ Sparking! NEO
|
||||||
RDDJA4 = ダンスダンスレボリューション ホッテストパーティー
|
RDDJA4 = ダンスダンスレボリューション ホッテストパーティー
|
||||||
RDEJ0A = 全国デコトラ祭り
|
RDEJ0A = 全国デコトラ祭り
|
||||||
RDGJA4 = 悪魔城ドラキュラ ジャッジメント
|
RDGJA4 = 悪魔城ドラキュラ ジャッジメント
|
||||||
RDIJG2 = THE DOG ISLAND -ひとつの花の物語-
|
RDIJG2 = Artlist Collection: The Dog Island ~ひとつの花の物語~
|
||||||
RDKJ01 = ドンキーコング たるジェットレース
|
RDKJ01 = ドンキーコング たるジェットレース
|
||||||
RDMJ8N = Go!Go!ミノン
|
RDMJ8N = Go!Go!ミノン
|
||||||
RDOJ41 = わんこと魔法のぼうし
|
RDOJ41 = わんこと魔法のぼうし
|
||||||
|
@ -117,7 +117,7 @@ RDSJAF = ドラゴンボールZ Sparking! METEOR
|
||||||
RDTJAF = たまごっちのピカピカだいとーりょー!
|
RDTJAF = たまごっちのピカピカだいとーりょー!
|
||||||
RDUJDQ = スゴロクロニクル 〜右手に剣を左手にサイコロを〜
|
RDUJDQ = スゴロクロニクル 〜右手に剣を左手にサイコロを〜
|
||||||
RDWJG9 = ドラゴンブレイド
|
RDWJG9 = ドラゴンブレイド
|
||||||
RDXJ18 = デカスポルタ
|
RDXJ18 = Deca Sporta: Wiiでスポーツ"10"種目!
|
||||||
RDZJ01 = ディザスター デイ オブ クライシス
|
RDZJ01 = ディザスター デイ オブ クライシス
|
||||||
RE4J08 = バイオハザード
|
RE4J08 = バイオハザード
|
||||||
RE8J99 = 家庭教師ヒットマンREBORN! 禁斷の闇のデルタ
|
RE8J99 = 家庭教師ヒットマンREBORN! 禁斷の闇のデルタ
|
||||||
|
@ -151,13 +151,13 @@ RFUJA4 = 麻雀格闘倶楽部Wii Wi-Fi対応
|
||||||
RG2JJF = ギルティギア イグゼクス アクセントコア
|
RG2JJF = ギルティギア イグゼクス アクセントコア
|
||||||
RG4JC0 = 電車でGO! 新幹線EX 山陽新幹線編
|
RG4JC0 = 電車でGO! 新幹線EX 山陽新幹線編
|
||||||
RGCJJF = プチコプターWii アドベンチャーフライト
|
RGCJJF = プチコプターWii アドベンチャーフライト
|
||||||
RGEJJ9 = ザ ワールド オブ ゴールデンエッグス
|
RGEJJ9 = ザ ワールド オブ ゴールデンエッグス: ノリノリリズム系
|
||||||
RGGJAF = ゲゲゲの鬼太郎 妖怪大運動会
|
RGGJAF = ゲゲゲの鬼太郎 妖怪大運動会
|
||||||
RGHJ52 = ギターヒーロー3 レジェンド オブ ロック
|
RGHJ52 = ギターヒーロー3 レジェンド オブ ロック
|
||||||
RGIJC8 = ジーワンジョッキーWii
|
RGIJC8 = ジーワンジョッキーWii
|
||||||
RGNJAF = 銀魂 万事屋ちゅ〜ぶ ツッコマブル動画
|
RGNJAF = 銀魂 万事屋ちゅ〜ぶ ツッコマブル動画
|
||||||
RGOJJ9 = ザ・ワールド・オブ・ゴールデンエッグス日産NOTE版
|
RGOJJ9 = ザ ワールド オブ ゴールデンエッグス: ノリノリリズム系 - Nissan Note オリジナルバージョン
|
||||||
RGPJAF = パチスロ「機動戦士ガンダムII 〜哀・戦士編〜」
|
RGPJAF = アニメスロットレボリューション パチスロ機動戦士ガンダムII ~哀・戦士編~
|
||||||
RGSJ8P = ゴースト・スカッド
|
RGSJ8P = ゴースト・スカッド
|
||||||
RGTJBL = ジーティー プロ シリーズ
|
RGTJBL = ジーティー プロ シリーズ
|
||||||
RGVJ52 = ギターヒーロー エアロスミス
|
RGVJ52 = ギターヒーロー エアロスミス
|
||||||
|
@ -278,6 +278,7 @@ RQRJAF = スカイ・クロラ イノセン・テイセス
|
||||||
RR3JA4 = ファミリーチャレンジWii
|
RR3JA4 = ファミリーチャレンジWii
|
||||||
RRBJ41 = ラビッツ・パーティー
|
RRBJ41 = ラビッツ・パーティー
|
||||||
RRSJ4Q = ルイスと未来泥棒 ウィルバーの危険な時間旅行
|
RRSJ4Q = ルイスと未来泥棒 ウィルバーの危険な時間旅行
|
||||||
|
RRTE52 = 블록 파티! 20 게임들
|
||||||
RRUJJF = WINTER SPORTS 2009 - THE NEXT CHALLENGE
|
RRUJJF = WINTER SPORTS 2009 - THE NEXT CHALLENGE
|
||||||
RRWJAF = スーパーロボット大戦NEO
|
RRWJAF = スーパーロボット大戦NEO
|
||||||
RS3J52 = スパイダーマン3
|
RS3J52 = スパイダーマン3
|
||||||
|
@ -307,7 +308,7 @@ RT3JEL = Rockstar Games presents Table Tennis
|
||||||
RT4JAF = テイルズ オブ シンフォニア ラタトスクの騎士
|
RT4JAF = テイルズ オブ シンフォニア ラタトスクの騎士
|
||||||
RTDJES = 新・中華大仙 マイケルとメイメイの冒険
|
RTDJES = 新・中華大仙 マイケルとメイメイの冒険
|
||||||
RTFJ52 = トランスフォーマー THE GAME
|
RTFJ52 = トランスフォーマー THE GAME
|
||||||
RTGJ18 = Wi-Fi対応 厳選テーブルゲームWii
|
RTGJ18 = 厳選テーブルゲーム Wii
|
||||||
RTIJ8P = 珍スポーツ
|
RTIJ8P = 珍スポーツ
|
||||||
RTKJDQ = しゃるうぃ〜☆たころん
|
RTKJDQ = しゃるうぃ〜☆たころん
|
||||||
RTLJ18 = めざせ!!釣りマスター -世界にチャレンジ編-
|
RTLJ18 = めざせ!!釣りマスター -世界にチャレンジ編-
|
||||||
|
@ -315,6 +316,7 @@ RTNJCQ = 天誅4
|
||||||
RTOJ8P = 428 ~封鎖された渋谷で~
|
RTOJ8P = 428 ~封鎖された渋谷で~
|
||||||
RTRJ18 = めざせ!!釣りマスター
|
RTRJ18 = めざせ!!釣りマスター
|
||||||
RTTJAF = たまごっちのフリフリ歌劇団
|
RTTJAF = たまごっちのフリフリ歌劇団
|
||||||
|
RTYP01 = 通信対局 ワールドチェス
|
||||||
RTZJ08 = 宝島Z バルバロスの秘宝
|
RTZJ08 = 宝島Z バルバロスの秘宝
|
||||||
RUFJ99 = ルーンファクトリー フロンティア
|
RUFJ99 = ルーンファクトリー フロンティア
|
||||||
RUNJ0Q = NEW 右脳キッズWii
|
RUNJ0Q = NEW 右脳キッズWii
|
||||||
|
@ -365,7 +367,7 @@ RZ8JG9 = SIMPLE 2000シリーズWiiVol.1 THEテーブルゲーム
|
||||||
RZ9JG9 = SIMPLE 2000シリーズWii Vol.2 THEパーティーゲーム
|
RZ9JG9 = SIMPLE 2000シリーズWii Vol.2 THEパーティーゲーム
|
||||||
RZDJ01 = ゼルダの伝説 トワイライトプリンセス
|
RZDJ01 = ゼルダの伝説 トワイライトプリンセス
|
||||||
RZJJ13 = デッドスペース エクストラクション
|
RZJJ13 = デッドスペース エクストラクション
|
||||||
RZNJ01 = 斬撃のREGINLEIV
|
RZNJ01 = 斬撃のレギンレイヴ
|
||||||
RZPJ01 = リンクのボウガントレーニング
|
RZPJ01 = リンクのボウガントレーニング
|
||||||
RZTJ01 = Wiiスポーツ リゾート
|
RZTJ01 = Wiiスポーツ リゾート
|
||||||
RZTW01 = Wiiスポーツ リゾート
|
RZTW01 = Wiiスポーツ リゾート
|
||||||
|
@ -376,7 +378,7 @@ S2AJAF = みんなで冒険!ファミリートレーナー
|
||||||
S2LJ01 = ポケパーク2 ビヨンド・ザ・ワールド
|
S2LJ01 = ポケパーク2 ビヨンド・ザ・ワールド
|
||||||
S2PJA4 = ウイニングイレブン プレーメーカー 2012
|
S2PJA4 = ウイニングイレブン プレーメーカー 2012
|
||||||
S2TJAF = 太鼓の達人Wii ドドーンと2代目!
|
S2TJAF = 太鼓の達人Wii ドドーンと2代目!
|
||||||
S3DJ18 = デカスポルタ3
|
S3DJ18 = Deca Sporta 3: Wiiでスポーツ
|
||||||
S3HJ08 = 戦国BASARA3 宴
|
S3HJ08 = 戦国BASARA3 宴
|
||||||
S3RJMS = トウィンクルクイーン
|
S3RJMS = トウィンクルクイーン
|
||||||
S3SJ18 = カラオケJOYSOUND Wii SUPER DX
|
S3SJ18 = カラオケJOYSOUND Wii SUPER DX
|
||||||
|
@ -384,7 +386,7 @@ S3TJAF = 太鼓の達人Wii みんなでパーティ☆3代目!
|
||||||
S4MJGD = ドラゴンクエストX 目覚めし五つの種族 オンライン
|
S4MJGD = ドラゴンクエストX 目覚めし五つの種族 オンライン
|
||||||
S4SJGD = ドラゴンクエストX 眠れる勇者と導きの盟友 オンライン
|
S4SJGD = ドラゴンクエストX 眠れる勇者と導きの盟友 オンライン
|
||||||
S59JC8 = 戦国無双3
|
S59JC8 = 戦国無双3
|
||||||
S5KJAF = 太鼓の達人WII 超ごうか版
|
S5KJAF = 太鼓の達人Wii 超ごうか版
|
||||||
S5QJC8 = 戦国無双3 猛将伝
|
S5QJC8 = 戦国無双3 猛将伝
|
||||||
S5SJHF = イナズマイレブンGO ストライカーズ 2013
|
S5SJHF = イナズマイレブンGO ストライカーズ 2013
|
||||||
S6TJGD = ドラゴンクエストX オールインワンパッケージ
|
S6TJGD = ドラゴンクエストX オールインワンパッケージ
|
||||||
|
@ -409,7 +411,7 @@ SD9JAF = SDガンダム ガシャポンウォーズ
|
||||||
SDJJAF = SDガンダム Gジェネレーション ワールド
|
SDJJAF = SDガンダム Gジェネレーション ワールド
|
||||||
SDQJGD = ドラゴンクエストX いにしえの竜の伝承 オンライン
|
SDQJGD = ドラゴンクエストX いにしえの竜の伝承 オンライン
|
||||||
SDWJ18 = 影の塔
|
SDWJ18 = 影の塔
|
||||||
SEAJ13 = パーソナルトレーナーWii6週間ひきしめプログラム
|
SEAJ13 = EA Sports アクティブ パーソナルトレーナー: Wii 6週間集中ひきしめプログラム
|
||||||
SEKJ99 = イケニエノヨル
|
SEKJ99 = イケニエノヨル
|
||||||
SEMJ01 = ディズニー エピックミッキー ~ミッキーマウスと魔法の筆~
|
SEMJ01 = ディズニー エピックミッキー ~ミッキーマウスと魔法の筆~
|
||||||
SEPE41 = ブラック・アイド・ピーズ・エクスペリエンス スペシャル・エディション
|
SEPE41 = ブラック・アイド・ピーズ・エクスペリエンス スペシャル・エディション
|
||||||
|
@ -498,69 +500,507 @@ SVMJ01 = スーパーマリオコレクション
|
||||||
SW4JA4 = ウイニングイレブン プレーメーカー 2011
|
SW4JA4 = ウイニングイレブン プレーメーカー 2011
|
||||||
SX3J01 = パンドラの塔 君のもとへ帰るまで
|
SX3J01 = パンドラの塔 君のもとへ帰るまで
|
||||||
SX4J01 = ゼノブレイド
|
SX4J01 = ゼノブレイド
|
||||||
SX6JAF = プリキュア オールスターズ ぜんいんしゅうごう☆レッツダンス!
|
SX6JAF = プリキュア オールスターズ: ぜんいんしゅうごう☆レッツダンス!
|
||||||
DBSBT3 = Dragon ball z SparkingMeteor
|
DBSBT3 = Dragon ball z SparkingMeteor
|
||||||
DQAJSC = アクエリアスベースボール 限界の、その先へ
|
DQAJSC = アクエリアスベースボール 限界の、その先へ
|
||||||
|
G2MK01 = メトロイドプライム2 ダークエコーズ
|
||||||
|
G4NEDA = カンタン操作で、超爽快忍者アクションが楽しめる!
|
||||||
|
G4SK01 = ゼルダの伝説 4つの剣+
|
||||||
|
GBIK08 = バイオハザード
|
||||||
|
GCDK08 = バイオハザード コード:ベロニカ完全版
|
||||||
|
GEAK8P = エターナルアルカディア レジェンド
|
||||||
|
GFEK01 = ファイアーエムブレム 蒼炎の軌跡
|
||||||
GGPE01 = マリオカート アーケードグランプリ
|
GGPE01 = マリオカート アーケードグランプリ
|
||||||
GGPE02 = マリオカート アーケードグランプリ2
|
GGPE02 = マリオカート アーケードグランプリ2
|
||||||
|
GLMK01 = ルイージマンション
|
||||||
|
GM8K01 = メトロイドプライム
|
||||||
|
GMSE02 = Multiplayer Sunshine Super Mario
|
||||||
|
GMSK01 = スーパーマリオサンシャイン
|
||||||
GVS32J = バーチャストライカー3 Ver.2002 (トライフォース)
|
GVS32J = バーチャストライカー3 Ver.2002 (トライフォース)
|
||||||
GVS45J = バーチャストライカー4
|
GVS45J = バーチャストライカー4
|
||||||
|
GZ2K01 = ゼルダの伝説 トワイライトプリンセス
|
||||||
|
GZBEB2 = 金色のガッシュベル!! ゴー!ゴー!魔物ファイト!!
|
||||||
|
GZLK01 = ゼルダの伝説 風のタクト
|
||||||
|
R24E01 = Wiiであそぶ ちびロボ!
|
||||||
|
R7CE01 = キャプテン★レインボー
|
||||||
|
R8EEQC = アースシーカー
|
||||||
R8FJSC = 匠レストランは大繁盛!
|
R8FJSC = 匠レストランは大繁盛!
|
||||||
|
RMCEYP = ヨッシーレーシングリゾートプラス
|
||||||
RMCJ12 = マリオカートWii カスタム(2011-11 Wiimm)
|
RMCJ12 = マリオカートWii カスタム(2011-11 Wiimm)
|
||||||
|
RMCJ86 = マリオカートクリス3,500CT
|
||||||
|
RMCJBR = マリオカート Brown
|
||||||
|
RMCJYP = ヨッシーレーシングリゾートプラス
|
||||||
|
RMCKYP = ヨッシーレーシングリゾートプラス
|
||||||
|
RMCPCA = マリオカートWii(カタルーニャ語版)
|
||||||
|
RMCPYP = ヨッシーレーシングリゾートプラス
|
||||||
|
ROSE01 = タクトオブマジック
|
||||||
RYAJSC = ヤッターマンWii ビックリドッキリマシンで猛レースだコロン
|
RYAJSC = ヤッターマンWii ビックリドッキリマシンで猛レースだコロン
|
||||||
|
RZNE01 = 斬撃のレギンレイヴ
|
||||||
|
SEKE99 = Ikenie no Yoru
|
||||||
|
SMNEXE = 強化されたスーパーマリオブラザーズ.Wiiデラックス
|
||||||
|
SNBE66 = マグマスーパーマリオブラザーズWii黙示録
|
||||||
|
W2OJ = Blue Oasis: 미지의 심해
|
||||||
W2TJ = オニトレ~教官は鬼軍曹~
|
W2TJ = オニトレ~教官は鬼軍曹~
|
||||||
W34J = @SIMPLEシリーズ Vol.4 THE 密室からの脱出
|
W34J = @SIMPLEシリーズ Vol.4 THE 密室からの脱出
|
||||||
|
W3DJ = 3° C
|
||||||
W42J = F・O・R・T・U・N・E フォーチュン~星のふりそそぐ丘~
|
W42J = F・O・R・T・U・N・E フォーチュン~星のふりそそぐ丘~
|
||||||
|
W4KJ = Shikagari
|
||||||
|
W4OJ = Shikakui Atama wo Marukusuru Challenge
|
||||||
|
W82J = Jintori Action Taikokenchi Karakuri Shiro no Nazo
|
||||||
|
W8CJ = BIT.TRIP CORE: Rhythm Seijin no Gyakushuu
|
||||||
|
W8DJ = Mebius Drive
|
||||||
|
W8IJ = Hachi-One Diver Wii
|
||||||
|
W8PJ = Ouchi de Mugen Puchi Puchi Wii
|
||||||
W9IJ = 危険空域
|
W9IJ = 危険空域
|
||||||
WA2J = みんなでパズループ
|
WA2J = みんなでパズループ
|
||||||
WAQJ = 役満 Wii 井出洋介 の 健康 麻将
|
WA4J = WarioWare: D.I.Y. Showcase
|
||||||
WBTJ = ファンタジックタンバリン FANTASIC TAMBOURINE
|
WA8J = Art Style: Penta Tentacles
|
||||||
|
WALJ = Art Style: Lightstream
|
||||||
|
WAQJ = 役満 Wii 井出洋介 の 健康 麻将
|
||||||
|
WARJ = Tsuushin Taikyoku Igo Doujou 2700 Mon
|
||||||
|
WASJ = Tsuushin Taikyoku: Hayazashi Syogi Sandan
|
||||||
|
WAUJ = Tsūshin Taikyoku: World Chess
|
||||||
|
WBJJ = Bokujou Monogatari Series: Makiba no Omise
|
||||||
|
WBMJ = Minna no Pokémon Bokujou
|
||||||
|
WCKJ = chick chick BOOM
|
||||||
|
WCSJ = Cue Sports: Wi-Fi Taisen Billiards
|
||||||
|
WCUJ = Atsui 12-Game: FuriFuri Party!
|
||||||
|
WD2J = Simple Wii Series Vol. 2: The Number Puzzle Neo
|
||||||
WD9J = ドラキュラ伝説 ReBirth
|
WD9J = ドラキュラ伝説 ReBirth
|
||||||
WDBJ = ダービードッグ
|
WDBJ = ダービードッグ
|
||||||
|
WDHJ = Art Style: Dialhex
|
||||||
|
WDIJ = Simple Wii Series Vol. 1: The Block Kuzushi Neo
|
||||||
WDMJ = Dr.MARIO&細菌撲滅
|
WDMJ = Dr.MARIO&細菌撲滅
|
||||||
|
WDNJ = Discipline Teikoku no Tanjyou
|
||||||
|
WDPJ = Dr. Mario Online Rx (Friend Battle Demo)
|
||||||
|
WE6J = Sea Farm: Iruka to Watashi no Showtime
|
||||||
|
WEMJ = 1 Nuke! Dasshutsu Game * My Home Hen
|
||||||
|
WERJ = Blue Oasis: The Healing Space of Fish
|
||||||
|
WETJ = Asoberu Ehon: Tobida Sugoroku
|
||||||
|
WF2J = Final Fantasy Crystal Chronicles: Hikari to Yami no Himegimi to Sekai Seifuku no Tou
|
||||||
|
WF4J = Final Fantasy IV: The After Years - Tsuki no Kikan
|
||||||
|
WF5J = Okiraku Daifugou Wii
|
||||||
|
WFBJ = Beach e Oki o Tsukuccha Wow!
|
||||||
|
WFCJ = Final Fantasy Crystal Chronicles: Chiisana Ousama to Yakusoku no Kuni
|
||||||
WFPJ = ひらめきカードバトル メクルカ
|
WFPJ = ひらめきカードバトル メクルカ
|
||||||
|
WFSJ = みんなのシアターWii
|
||||||
|
WG2J = Sugar Bunnies Wii: Youkoso * Bunnies Field e
|
||||||
|
WGDJ = Gradius Rebirth: Updated
|
||||||
|
WGGJ = Ushimitsu Monstruo Puchi: Fushigi na Oshiro no Dance Party
|
||||||
|
WGMJ = Game SoundStation
|
||||||
|
WGOJ = World of Goo
|
||||||
|
WGPJ = Aqua Living: TV de Nagameru Uotachi
|
||||||
|
WGSJ = Gyakuten Saiban: Yomigaeru Gyakuten
|
||||||
WHHJ = Let's 全力ヒッチハイク!!!!!!!!!
|
WHHJ = Let's 全力ヒッチハイク!!!!!!!!!
|
||||||
|
WIKJ = Ivy the Kiwi? Mini
|
||||||
|
WINJ = Chokkan! Balance * Labyrinth
|
||||||
|
WJ2J = Jinsei Game: Happy Step
|
||||||
|
WK2J = Kappa-kun to Asobou: Kappa-kun to Ota no Shimikai
|
||||||
|
WK3J = Kappa-kun to Asobou: Kappa-kun to Mori no Nakamatachi
|
||||||
|
WK9J = Minna de Asobou Koinu de Kururin
|
||||||
|
WKEJ = RakuRaku Kinen Apori Wii: Kinenka no Isha ga Osheru Nanoka de yameru Houhou
|
||||||
|
WKKJ = Kurohige Kiki Ippatsu
|
||||||
|
WKNJ = Kanken Minna de Waiwai Kanji Nou
|
||||||
|
WKPJ = Kappa Kun to Mori no Nakama Tachi
|
||||||
|
WKQJ = Kentei! TV Wii Minna de Gotouchi Quiz Battle
|
||||||
|
WKWJ = Item Sagashi * Yousei to Fushigi no Shima
|
||||||
|
WLDJ = Boku mo Sekai o Sukuitai: Battle Tournament
|
||||||
|
WLEJ = Pooyoo to Asobou Episode 1
|
||||||
|
WLJJ = Boku mo Sekai o Sukuitai: Battle Tournament
|
||||||
|
WLKJ = リカちゃんおしゃれハウス
|
||||||
|
WLMJ = La Mulana
|
||||||
|
WLOJ = LostWinds: Winter of the Melodias
|
||||||
|
WM8J = Wi-Fi 8-Nin Battle Bomberman
|
||||||
WM9J = たたいて!モグポン
|
WM9J = たたいて!モグポン
|
||||||
|
WMBJ = Katachi no Game: Marubou Shikaku
|
||||||
|
WMLJ = Major League Eating: The Game
|
||||||
|
WMOJ = Antaga Mawashite Sukuu Puzzle: Mochimochi Q
|
||||||
WMPJ = ことばのパズル もじぴったんWii
|
WMPJ = ことばのパズル もじぴったんWii
|
||||||
|
WMXJ = Max & the Magic Marker
|
||||||
WN9J = NECTARIS(ネクタリス)
|
WN9J = NECTARIS(ネクタリス)
|
||||||
WNPJ = すぐスロDUO「ニューパルサーR&V」
|
WNPJ = すぐスロDUO「ニューパルサーR&V」
|
||||||
WNVJ = ハメコミ LUCKY PUZZLE Wii リターン
|
WNVJ = ハメコミ LUCKY PUZZLE Wii リターン
|
||||||
|
WNWJ = Hamekomi Lucky Puzzle Wii Return
|
||||||
|
WOBJ = Art Style: Orbital
|
||||||
WODJ = 王だぁ!
|
WODJ = 王だぁ!
|
||||||
WOKJ = カラオケJOYSOUND Wii
|
WOKJ = カラオケJOYSOUND Wii
|
||||||
|
WOXJ = Osu! Exercise Dojo
|
||||||
|
WOYJ = Bit Man
|
||||||
|
WOZJ = Kodomo Kyouiku Telebi Wii: Aiue-Oumuzu
|
||||||
WP5J = ポコスカれーしんぐ
|
WP5J = ポコスカれーしんぐ
|
||||||
|
WP6J = Boku wa Plarail Untenshi: Shinkansen Joukikikansha-Hen
|
||||||
|
WP9J = Po-Ka-Zu Wii
|
||||||
WPAJ = ポケモン不思議のダンジョン いくぞ!嵐の冒険団
|
WPAJ = ポケモン不思議のダンジョン いくぞ!嵐の冒険団
|
||||||
WPDJ = 珍道中!!ポールの大冒険
|
WPDJ = 珍道中!!ポールの大冒険
|
||||||
WPFJ = ポケモン不思議のダンジョン すすめ!炎の冒険団
|
WPFJ = ポケモン不思議のダンジョン すすめ!炎の冒険団
|
||||||
|
WPGJ = Penguin Life
|
||||||
WPHJ = ポケモン不思議のダンジョン めざせ!光の冒険団
|
WPHJ = ポケモン不思議のダンジョン めざせ!光の冒険団
|
||||||
|
WPIJ = Pit Crew Panic
|
||||||
|
WPNJ = Ponjan
|
||||||
|
WPPJ = Okiraku Ping Pong
|
||||||
|
WPRJ = Art Style: Cubeleo
|
||||||
|
WPSJ = Ransen Pokémon Scramble
|
||||||
WPTJ = FANTASIC CUBE ファンタジックキューブ
|
WPTJ = FANTASIC CUBE ファンタジックキューブ
|
||||||
|
WPVJ = Kumanage Battle-Hen: Kiina no Kirai na Aoi Hoseki
|
||||||
|
WPXJ = Minna de Tobikome Penguin Diving Hooper Looper
|
||||||
|
WQ4J = Kentoushi FuriFuri Boxing
|
||||||
WR9J = ロックマン9 野望の復活!!
|
WR9J = ロックマン9 野望の復活!!
|
||||||
|
WRIJ = Rainbow Islands: Towering Adventure!
|
||||||
|
WRNJ = BIT.TRIP RUNNER
|
||||||
WRXJ = 宇宙からの脅威!!
|
WRXJ = 宇宙からの脅威!!
|
||||||
|
WS8J = Minna de Taisen Puzzle Shanghai
|
||||||
|
WSAJ = MadSecta
|
||||||
|
WSCJ = Out of Galaxy: Gin no Koshika
|
||||||
WSGJ = さめがめ Wii
|
WSGJ = さめがめ Wii
|
||||||
|
WSLJ = Shadow Walker
|
||||||
|
WSNJ = Sonic the Hedgehog 4: Episode I
|
||||||
WSUJ = シュータント過去編
|
WSUJ = シュータント過去編
|
||||||
WT8J = はじいて! ブロック ラッシュ
|
WT8J = はじいて! ブロック ラッシュ
|
||||||
WTBJ = ファンタジックタンバリン FANTASIC TAMBOURINE
|
WTBJ = ファンタジックタンバリン FANTASIC TAMBOURINE
|
||||||
|
WTDJ = Tomica Drive
|
||||||
|
WTRJ = BIT.TRIP BEAT
|
||||||
WUHJ = Wiiでウルトラハンド
|
WUHJ = Wiiでウルトラハンド
|
||||||
|
WUKJ = Unou Kids Okigaru Unou Training
|
||||||
|
WUNJ = Uno
|
||||||
|
WVBJ = BIT.TRIP VOID
|
||||||
|
WVDJ = Kodomo Kyouiku TV Wii: Aiue-O-Chan
|
||||||
|
WVOJ = Rock n' Roll Climber
|
||||||
|
WWRJ = Excitebike: World Race
|
||||||
|
WYKJ = Yomi Kiku Asobi
|
||||||
|
WZHJ = Animal Life: Doubutsu Fureai Seikatsu
|
||||||
WZJJ = @ SIMPLEシリーズ Vol.5 THE 柔道
|
WZJJ = @ SIMPLEシリーズ Vol.5 THE 柔道
|
||||||
|
WZMJ = Simple Wii Series Vol. 3: The Mahjong
|
||||||
WZPJ = ゾンビ イン ワンダーランド
|
WZPJ = ゾンビ イン ワンダーランド
|
||||||
|
WZZJ = Kumanage Puzzle-Hen: Piina no Suki na Akai Candy
|
||||||
|
FA5J = Fire Emblem: Ankoku Ryu to Hikari no Tsurugi
|
||||||
|
FA6J = Donkey Kong Jr. no Sansuu Asobi
|
||||||
|
FA8J = Hoshi no Kirby: Yume no Izumi no Monogatari
|
||||||
|
FA9J = The Legend of Zelda 2: Link no Bouken
|
||||||
|
FAQJ = Ninja Jajamaru-kun
|
||||||
FB2J = スーパーマリオブラザーズ2
|
FB2J = スーパーマリオブラザーズ2
|
||||||
|
FB3J = Valkyrie no Bouken: Toki no Kagi Densetsu
|
||||||
|
FBDJ = Hikari Shinwa: Palutena no Kagami
|
||||||
|
FBNJ = Ninja Ryuukenden
|
||||||
|
FBOJ = Gradius II
|
||||||
|
FBSJ = Meikyuu Kumikyoku: Milon no Daibouken
|
||||||
|
FC5J = Ganbare Goemon Karakuki Douchuu
|
||||||
|
FC8J = Dracula II: Noroi no Fuuin
|
||||||
|
FCFJ = Yie Ar Kung Fu
|
||||||
|
FCIJ = Volguard 2
|
||||||
|
FCJJ = SD Gundam World: Gachapon Senshi 2 - Capsule Senki
|
||||||
|
FCRJ = Takahashi Meijin no Boukenjima
|
||||||
|
FCTJ = RockMan
|
||||||
|
FCZJ = Kings Knight
|
||||||
|
FD3J = Nekketsu Koukou Dodgeball-bu Soccer-hen
|
||||||
|
FD7J = RockMan 3: Dr. Wily no Saigo?!
|
||||||
|
FDBJ = Famicom Mukashi Banashi: Shin Onigashima - Kouhen
|
||||||
|
FDGJ = Makai-Mura
|
||||||
|
FDNJ = RockMan 2
|
||||||
|
FDSJ = Famicom Tantei Club: Kieta Koukeisha (Kouhen)
|
||||||
|
FDTJ = Renegade
|
||||||
|
FDUJ = Nekketsu Koukou Dodge Ball Bu
|
||||||
|
FDWJ = Downtown Special: Kunio-kun no Jidaigeki Dayo Zenin Shuugou!
|
||||||
|
FDXJ = Famicom Tantei Club Part II: Ushiro ni Tatsu Shoujo (Kouhen)
|
||||||
|
FDZJ = Downtown Nekketsu Koushinkyoku
|
||||||
|
FE5J = Toukaidou Gojuusan Tsugi
|
||||||
|
FE6J = Ninja kun Majyou no Bouken
|
||||||
|
FE7J = Ninja kun Ashura no Shou
|
||||||
|
FE9J = Ike Ike! Nekketsu Hockey-bu: Subette Koronde Dairantou
|
||||||
|
FEEJ = Tantei Jingūji Saburō: Shinjuku Chūō Kōen Satsujin Jiken
|
||||||
|
FEFJ = Detective Saburo Jinguji 2: Yokohama-Ko Renzoku Satsujin Jiken
|
||||||
|
FEHJ = Tantei Jinguuji Saburo: Toki no Sugiyuku Mama ni
|
||||||
|
FEJJ = Nazo no Murasame Jou
|
||||||
|
FELJ = Transformers: Convoy no Nazo
|
||||||
|
FEMJ = Bio-Miracle Bokutte Upa
|
||||||
|
FEOJ = Zoids: Mokushiroku
|
||||||
|
FEQJ = Akumajo Densetsu
|
||||||
|
FESJ = Clu Clu Land
|
||||||
|
FEXJ = Wagyan Land
|
||||||
|
FF2J = Sugoro Quest: Dice no Senshi Tachi
|
||||||
|
FF5J = Double Dragon 2: The Revenge
|
||||||
|
FF7J = Ganbare Goemon Gaiden: Kieta Ougon Kiseru
|
||||||
|
FFGJ = SD Gundam World: Gachapon Senshi - Scramble Wars
|
||||||
|
FFLJ = Salad no Kuni no Tomato Hime
|
||||||
|
FFMJ = Chou-Wakusei Senki MetaFight
|
||||||
|
FFNJ = RockMan 4: Aratanaru Yabou!!
|
||||||
|
FFOJ = Moero TwinBee: Cinnamon Hakase o Sukue!
|
||||||
|
FFPJ = Furu Furu Park
|
||||||
|
FFUJ = Takahashi Meijin no Bouken Jima II
|
||||||
FFXJ = 25th スーパーマリオブラザーズ
|
FFXJ = 25th スーパーマリオブラザーズ
|
||||||
|
FFYJ = RockMan 5: Blues no Wana!?
|
||||||
|
JA4J = Chou-Makai-Mura
|
||||||
|
JA5J = Heracles no Eikou III: Kamigami no Chinmoku
|
||||||
|
JA7J = Actraiser
|
||||||
|
JADJ = Zelda no Densetsu: Kamigami no Triforce
|
||||||
|
JAFJ = SimCity
|
||||||
|
JAGJ = Fire Emblem: Monshou no Nazo
|
||||||
|
JAHJ = R-Type III: The Third Lightning
|
||||||
|
JAJJ = Street Fighter II
|
||||||
|
JAPJ = Fire Emblem: Seisen no Keifu
|
||||||
|
JAUJ = Famicom Bunko: Hajimari no Mori
|
||||||
|
JAWJ = San Goku Shi IV
|
||||||
|
JAZJ = Ganbare Goemon: Yukihime Kyuushutsu Emaki
|
||||||
|
JB7J = Front Mission: Gun Hazard
|
||||||
|
JBBJ = Super Street Fighter II: The New Challengers
|
||||||
|
JBDJ = Super Donkey Kong 2: Dixie & Diddy
|
||||||
|
JBGJ = Mystery Dungeon: Shiren the Wanderer
|
||||||
|
JBHJ = Heracles no Eikou IV: Kamigami-kara no Okurimono
|
||||||
|
JBIJ = Street Fighter II Turbo: Hyper Fighting
|
||||||
|
JBKJ = Breath of Fire II: Shimei no Ko
|
||||||
|
JBPJ = Super Donkey Kong 3: Nazo no Krems Shima
|
||||||
|
JBVJ = Der Langrisser
|
||||||
|
JBWJ = Assault Suits Valken
|
||||||
|
JCAJ = DoReMi Fantasy: Milon no DokiDoki Daibouken
|
||||||
|
JCEJ = Fire Emblem: Thracia 776
|
||||||
|
JCGJ = Ganbare Goemon 2: Kiteretsu Shougun Magginesu
|
||||||
|
JCHJ = Ganbare Goemon 3
|
||||||
|
JCIJ = Famicom Tantei Club Part II: Ushiro ni Tatsu Shoujo
|
||||||
|
JCKJ = Space Invaders: The Original Game
|
||||||
|
JCMJ = Super Wagyan Land
|
||||||
|
JCTJ = Densetsu no Ogre Battle: The March of the Black Queen
|
||||||
|
JCUJ = Tactics Ogre: Let Us Cling Together
|
||||||
|
JCXJ = Super Nobunaga no Yabou: Zengokuban
|
||||||
|
JCZJ = Super Aoki Ookami to Shiroki Meshika: Genchou Hishi
|
||||||
|
JD3J = Super E.D.F. Earth Defense Force
|
||||||
|
JD5J = Rushing Beat Ran: Fukusei Toshi
|
||||||
|
JD9J = Chou-Genjin
|
||||||
|
JDOJ = Heisei Shin Onigashima: Zenpen
|
||||||
|
JDPJ = Heisei Shin Onigashima: Kouhen
|
||||||
|
JDQJ = Romancing Sa-Ga 3
|
||||||
|
JDTJ = Shin Megami Tensei if...
|
||||||
|
JDYJ = Rudra no Hihou
|
||||||
|
JDZJ = Final Fantasy USA: Mystic Quest
|
||||||
|
JEBJ = RockMan X
|
||||||
|
JEDJ = Kunio-Kun no Dodge Ball Dayo Zenin Shuugo!
|
||||||
|
JEFJ = Majin Tensei II: Spiral Nemesis
|
||||||
|
JEGJ = Gouketuji Ichizoku
|
||||||
|
JEHJ = RockMan X2
|
||||||
|
JEKJ = Kyūyaku Megami Tensei: Megami Tensei I・II
|
||||||
|
NA3J = Bomberman Hero
|
||||||
|
NACJ = Zelda no Densetsu: Toki no Ocarina
|
||||||
|
NAIJ = Wave Race 64: Kawasaki Jet Ski
|
||||||
|
NAJJ = Tsumi to Batsu
|
||||||
|
NALJ = Nintendo All-Star Dairantou Smash Brothers
|
||||||
|
NAOJ = 1080° Snowboarding
|
||||||
|
NARJ = Zelda no Densetsu: Majora no Kamen
|
||||||
|
NAYJ = Ogre Battle 64: Person of Lordly Caliber
|
||||||
|
LAEJ = Alex Kidd in Miracle World
|
||||||
|
LAGJ = Sonic the Hedgehog
|
||||||
|
LAJJ = Sonic the Hedgehog 2
|
||||||
|
LAKJ = Super Wonder Boy: Monster World
|
||||||
|
LALJ = Fantasy Zone II: The Tears of Opa-Opa
|
||||||
|
LANJ = Alex Kidd: The Lost Stars
|
||||||
|
MA3J = Puyo Puyo Tsuu
|
||||||
|
MA6J = Bare Knuckle II: Shitou no Chinkon Uta
|
||||||
|
MA7J = Shining and the Darkness
|
||||||
|
MAAJ = Juuouki
|
||||||
|
MAEJ = Golden Axe
|
||||||
|
MAHJ = Sonic the Hedgehog
|
||||||
|
MAKJ = Shadow Dancer: The Secret of Shinobi
|
||||||
|
MALJ = Bonanza Bros.
|
||||||
|
MAMJ = Vermilion
|
||||||
|
MAOJ = Crying: Aseimei Sensou
|
||||||
|
MAQJ = Bare Knuckle: Ikari no Tekken
|
||||||
|
MARJ = The Story of Thor: Hikari o Tsugu Mono
|
||||||
|
MAUJ = Puzzle & Action: Tant-R
|
||||||
|
MAVJ = Wonder Boy V: Monster World III
|
||||||
|
MAXJ = Alex Kidd: Tenkuu Mashiro
|
||||||
|
MB5J = Rangurissah II
|
||||||
|
MB6J = Shining Force II: Inishie no Fuuin
|
||||||
|
MB8J = Phantasy Star II: Kaerazaru Toki no Owari ni
|
||||||
|
MB9J = Pepenga Pengo
|
||||||
|
MBBJ = Sonic the Hedgehog 2
|
||||||
|
MBDJ = Golden Axe II
|
||||||
|
MBEJ = Shining Force: Kamigami no Isan
|
||||||
|
MBFJ = The Super Soldier II
|
||||||
|
MBHJ = Puzzle & Action: Ichidant-R
|
||||||
MBIJ = ランドストーカー 皇帝の財宝
|
MBIJ = ランドストーカー 皇帝の財宝
|
||||||
|
MBJJ = Dai Makai-Mura
|
||||||
|
MBLJ = ESWAT: Cyber Police
|
||||||
|
MBMJ = Sonic the Hedgehog 3
|
||||||
|
MBOJ = Golden Axe III
|
||||||
|
MBQJ = Bare Knuckle III
|
||||||
|
MBVJ = Jusu Kihei Leynos
|
||||||
|
MBWJ = Columns III: Taiketsu! Columns World
|
||||||
|
MC3J = Super Street Fighter 2: The New Challengers
|
||||||
|
MCCJ = Toki no Keishousha: Phantasy Star III
|
||||||
MCFJ = フェリオス(メガドライブ版)
|
MCFJ = フェリオス(メガドライブ版)
|
||||||
|
MCHJ = Musha Aleste
|
||||||
|
MCJJ = Splatterhouse Part 2
|
||||||
|
MCKJ = Phantasy Star: Sennenki no Owari ni
|
||||||
|
MCLJ = Street Fighter II' Plus: Champion Edition
|
||||||
|
MCMJ = Lord Monarch: Tokoton Sentou Densetsu
|
||||||
|
MCNJ = Hokuto no Ken: Shin Seikimatu Kyuseisyu Densetsu
|
||||||
|
MCRJ = Senjou no Ookami II
|
||||||
|
MCSJ = Wonder Boy III: Monster Lair
|
||||||
|
MCUJ = Dragon Slayer: The Legend of Heroes
|
||||||
|
MCVJ = Pitfall: The Mayan Adventure
|
||||||
|
PA2J = Nekketsu Koukou Dodgeball Bu: CD Soccer Hen
|
||||||
|
PA6J = Narazumono Sentou Butai: Bloody Wolf
|
||||||
|
PABJ = PC Genjin
|
||||||
|
PADJ = R-Type I
|
||||||
|
PAFJ = Victory Run: Eikou no 13,000KM
|
||||||
|
PAJJ = Joshoken Necromancer
|
||||||
|
PAMJ = Neutopia: Frey no Shou
|
||||||
|
PARJ = Detana TwinBee
|
||||||
|
PATJ = Kiki Kaikai
|
||||||
|
PAUJ = Kaizou Chounin Shubibinman
|
||||||
|
PBFJ = Fire ProWrestling: Combination Tag
|
||||||
|
PBHJ = PC Genjin 2
|
||||||
|
PBIJ = PC Genjin 3
|
||||||
|
PBJJ = Genpei Toumaden: Kannoni
|
||||||
|
PBNJ = Saigou no Nindou: Ninja Spirit
|
||||||
|
PBUJ = Chouzetsu Rinjin Bravoman
|
||||||
|
PBWJ = PC Denjin: Punkic Cyborgs
|
||||||
|
PBXJ = Kaizou Chounin Shubibinman 2: Atanaru Teki
|
||||||
|
PC4J = Space Invaders: Fukkatsu no Hi
|
||||||
|
PCBJ = Dead Moon: Tsuki Sekai no Akumu
|
||||||
|
PCMC = Gokuraku! Chuuka Taisen
|
||||||
|
PCSJ = Digital Champ: Battle Boxing
|
||||||
PDAJ = 熱血高校ドッジボール部® PC番外編
|
PDAJ = 熱血高校ドッジボール部® PC番外編
|
||||||
|
PDEJ = S.C.I.: Special Criminal Investigation
|
||||||
|
PDGJ = Fire ProWrestling 3: Legend Bout
|
||||||
PDIJ = チャンピオンレスラー®
|
PDIJ = チャンピオンレスラー®
|
||||||
|
PDJJ = Street Fighter II': Champion Edition
|
||||||
|
QA2J = Nekketsu Koukou Dodge Ball-Bu: CD Soccer-hen
|
||||||
|
QA4J = Super Darius II
|
||||||
|
QA5J = Space Invaders: The Original Game
|
||||||
|
QA7J = Legend of Xanadu: Kaze no Densetsu Xanadu
|
||||||
|
QA9J = Kaze no Densetsu: Xanadu II
|
||||||
|
QAAJ = CD Denjin: Rockabilly Tengoku
|
||||||
|
QABJ = Ys I + II
|
||||||
|
QADJ = Gradius II: Gofer no Yabou
|
||||||
|
QAEJ = A.III: A-Ressha de Ikou III
|
||||||
|
QAFJ = Chou Eiyuu Densetsu: Dynastic Hero
|
||||||
|
QAKJ = Ai Chou Aniki
|
||||||
|
QALJ = The Atlas: Renaissance Voyager
|
||||||
|
QAPJ = Akumajou Dracula X: Chi no Rondo
|
||||||
|
QAQJ = Dragon Slayer: Eiyuu Densetsu
|
||||||
|
QAUJ = Wonder Boy III: Monster Lair
|
||||||
|
QAVJ = Bomberman: Panic Bomber
|
||||||
|
QAZJ = Eikan wa Kimi ni: Kōkō Yakyū Zenkoku Taikai
|
||||||
|
QBAJ = L Dis
|
||||||
|
EA3J = Galaxy Fight: Universal Warriors
|
||||||
|
EA4J = Samurai Spirits Kibeniro Musouken
|
||||||
|
EA5J = Garou Densetsu 3: Road to the Final Victory
|
||||||
|
EA7J = Samurai Spirits: Amakusa Kourin
|
||||||
|
EA8J = Ironclad: Chotetsu Brikinger
|
||||||
|
EAAJ = Garou Densetsu: Shukumei no Takatai
|
||||||
|
EAEJ = Shin Samurai Spirits: Haohmaru Jigokuhen
|
||||||
|
EAIJ = Top Hunter
|
||||||
|
EANJ = Garou Densetsu 2: Aratanaru Tatakai
|
||||||
|
EASJ = Shin Samurai Spirits Haoumaru Jigokuhen
|
||||||
|
EAYJ = King of The Monsters 2
|
||||||
|
EB4J = ASO II: Last Guardian
|
||||||
|
EB5J = The Last Blade
|
||||||
|
EBNJ = Fu'un Mokushiroku: Kakutou Sousei
|
||||||
|
EBSJ = Art of Fighting: Ryuuko no Ken Gaiden
|
||||||
|
ECAJ = Real Bout Garou Densetsu 2: The Newcomers
|
||||||
|
ECDJ = Stakes Winner: G1 Kanzen Seihahe no Michi
|
||||||
|
ECEJ = Bakumatsu Rouman Dai Ni Maku: Gekka no Kenshi
|
||||||
|
ECGJ = Shock Troopers: 2nd Squad
|
||||||
|
ECHJ = The King of Fighters '98: Dream Match Never Ends
|
||||||
|
ECMJ = Tokuten Oh: Honoo no Libero
|
||||||
|
E55J = Senji no Ookami
|
||||||
|
E56J = Exed Eyes
|
||||||
|
E5VJ = Renegade
|
||||||
|
E6JJ = Bakutotsu Kijuutei: BaRaDuKe II
|
||||||
|
E6LJ = Marchen Maze
|
||||||
|
E6NJ = Solomon no Kagi
|
||||||
|
E6OJ = Bomb Jack Arcade
|
||||||
|
E6PJ = Ninja Ryukenden Arcade
|
||||||
|
E6QJ = Argos no Senshi
|
||||||
E6XJ = 獣王記(アーケード版)
|
E6XJ = 獣王記(アーケード版)
|
||||||
|
E72J = Starblade
|
||||||
|
E74J = Cosmo Gang the Puzzle
|
||||||
|
E77J = The Return of Ishtar
|
||||||
|
E7LJ = Cosmo Gang the Video
|
||||||
|
E7XJ = Youkai Douchuki
|
||||||
|
C9SP = 불가능한 임무 II
|
||||||
|
XADJ = Yie Ar Kung-Fu 2
|
||||||
|
XAHJ = Penguin Adventure: Yume Tairiku Adventure
|
||||||
|
XAKJ = Parodius - Tako wa Chikyuu wo Sukuu
|
||||||
|
XAMJ = Knightmare: Majou Densetsu
|
||||||
|
XAOJ = Gofer no Yabou: Episode II
|
||||||
|
XAPJ = Metal Gear 2: Solid Snake
|
||||||
|
HAAA = 写真チヤンネル
|
||||||
|
HABA = Wiiショッピングチャンネル
|
||||||
|
HADE = インターネットチャンネル
|
||||||
HADJ = インターネットチャンネル
|
HADJ = インターネットチャンネル
|
||||||
HAFJ = お天気チャンネル
|
HAFJ = お天気チャンネル
|
||||||
|
HAFP = お天気チャンネル
|
||||||
|
HAGA = ニュースチャンネル
|
||||||
|
HAGE = ニュースチャンネル
|
||||||
HAGJ = ニュースチャンネル
|
HAGJ = ニュースチャンネル
|
||||||
|
HAGP = ニュースチャンネル
|
||||||
|
HAPP = Miiコンテストチャンネル
|
||||||
|
HATJ = Nintendo Channel
|
||||||
|
HATP = みんなのニンテンドーチャンネル
|
||||||
|
HAVJ = Today and Tomorrow Fortune Teller
|
||||||
|
HAVP = きょうとあしたの占いラッキーチャンネル
|
||||||
HBNJ = テレビの友チャンネル Gガイド for Wii
|
HBNJ = テレビの友チャンネル Gガイド for Wii
|
||||||
HC3J = USB乄モリ一修復プ囗グラム
|
HC3J = USB乄モリ一修復プ囗グラム
|
||||||
HCAJ = バンブラDXスピーカーチャンネル
|
HCAJ = バンブラDXスピーカーチャンネル
|
||||||
|
HCCJ = 住所情報
|
||||||
|
HCDJ = デジカメプリントチャンネル
|
||||||
|
HCFP = Wiiスピークチャンネル
|
||||||
|
HCGJ = インターネットにつなぐとできること
|
||||||
|
HCHJ = 出前チャンネル
|
||||||
HCIJ = Wiiの間
|
HCIJ = Wiiの間
|
||||||
|
HCRE = ゼルダの伝説スカイウォードソード データ修復チャンネル
|
||||||
|
HCRJ = The Legend of Zelda Skyward Sword Update
|
||||||
|
HCRP = ゼルダの伝説スカイウォードソード データ修復チャンネル
|
||||||
HCYJ = Wii U本体更新 修復プログラム
|
HCYJ = Wii U本体更新 修復プログラム
|
||||||
HFNJ = Wii Fit からだチェックチャンネル
|
HFNJ = Wii Fit からだチェックチャンネル
|
||||||
|
RMCJ = マリオカートチャンネル
|
||||||
|
DSYA = 시스체크
|
||||||
|
D29J01 = 月刊任天堂店頭デモ 5月号
|
||||||
|
D32J01 = 月刊任天堂店頭デモ 6月号
|
||||||
|
D33J01 = 月刊任天堂店頭デモ 7月号
|
||||||
|
D34J01 = 月刊任天堂店頭デモ 7月増刊号
|
||||||
|
D38J01 = 月刊任天堂店頭デモ 9月号
|
||||||
|
D39J01 = 月刊任天堂店頭デモ 10月号
|
||||||
|
D42J01 = 月刊任天堂店頭デモ 11月号
|
||||||
D43J01 = ゼルダの伝説 時のオカリナ GC
|
D43J01 = ゼルダの伝説 時のオカリナ GC
|
||||||
|
D44J01 = 月刊任天堂店頭デモ 12月号
|
||||||
|
D46J01 = 月刊任天堂店頭デモ 1月号
|
||||||
|
D47J01 = 月刊任天堂店頭デモ 2月号
|
||||||
|
D48J01 = 月刊任天堂店頭デモ 3月号
|
||||||
|
D49J01 = 月刊任天堂店頭デモ 4月号
|
||||||
|
D52J01 = 月刊任天堂店頭デモ 5月号
|
||||||
D53J01 = ニンテンドーゲームキューブ ソフトeカタログ2003・春
|
D53J01 = ニンテンドーゲームキューブ ソフトeカタログ2003・春
|
||||||
|
D54J01 = 月刊任天堂店頭デモ 6月号
|
||||||
|
D59J01 = 月刊任天堂店頭デモ 7月号
|
||||||
|
D62J01 = 月刊任天堂店頭デモ 8月号
|
||||||
|
D64J01 = 月刊任天堂店頭デモ 10月号
|
||||||
|
D65J01 = 月刊任天堂店頭デモ 11月号
|
||||||
|
D67J01 = 月刊任天堂店頭デモ 12月号
|
||||||
|
D68J01 = 月刊任天堂店頭デモ 1月号
|
||||||
|
D73J01 = 月刊任天堂店頭デモ 2月号
|
||||||
|
D75J01 = 月刊任天堂店頭デモ 3月号
|
||||||
|
D77J01 = 月刊任天堂店頭デモ 4月号
|
||||||
|
D78J01 = 月刊任天堂店頭デモ 5月号
|
||||||
|
D79J01 = 月刊任天堂店頭デモ 6月号
|
||||||
|
D82J01 = 月刊任天堂店頭デモ 7月号
|
||||||
|
D84J01 = 月刊任天堂店頭デモ 8月号
|
||||||
|
D85J01 = 月刊任天堂店頭デモ 9月号
|
||||||
|
D86J01 = 月刊任天堂店頭デモ 10月号
|
||||||
|
D87J01 = 月刊任天堂店頭デモ 11月号
|
||||||
|
D88J01 = 月刊任天堂店頭デモ 12月号
|
||||||
D89J01 = クラブニンテンドー オリジナルeカタログ 2004
|
D89J01 = クラブニンテンドー オリジナルeカタログ 2004
|
||||||
|
D92J01 = 月刊任天堂店頭デモ 2004‐2005年末年始号
|
||||||
|
D93J01 = 月刊任天堂店頭デモ 1月号
|
||||||
|
D94J01 = 月刊任天堂店頭デモ 2月号
|
||||||
|
D97J01 = 月刊任天堂店頭デモ 5月号
|
||||||
|
E23J01 = 月刊任天堂店頭デモ 9月号
|
||||||
|
E24J01 = 月刊任天堂店頭デモ 10月号
|
||||||
|
E25J01 = 月刊任天堂店頭デモ 11月号
|
||||||
|
E27J01 = 月刊任天堂店頭デモ 1月号
|
||||||
|
E32J01 = 月刊任天堂店頭デモ 4月号
|
||||||
|
E34J01 = 月刊任天堂店頭デモ 6月号
|
||||||
|
E35J01 = 月刊任天堂店頭デモ 7月号
|
||||||
|
E36J01 = 月刊任天堂店頭デモ 8月号
|
||||||
|
E37J01 = 月刊任天堂店頭デモ 9月号
|
||||||
G2DJB2 = デジモンバトルクロニクル
|
G2DJB2 = デジモンバトルクロニクル
|
||||||
G2GJB2 = 機動戦士ガンダム ガンダムvs.Zガンダム
|
G2GJB2 = 機動戦士ガンダム ガンダムvs.Zガンダム
|
||||||
G2MJ01 = メトロイドプライム2 ダークエコーズ
|
G2MJ01 = メトロイドプライム2 ダークエコーズ
|
||||||
|
@ -569,7 +1009,7 @@ G2SJGE = 式神の城II
|
||||||
G2VJ08 = ビューティフル ジョー 2 ブラックフィルムの謎
|
G2VJ08 = ビューティフル ジョー 2 ブラックフィルムの謎
|
||||||
G2XJ8P = ソニックジェムズコレクション
|
G2XJ8P = ソニックジェムズコレクション
|
||||||
G3AJ13 = ロード・オブ・ザ・リング 中つ国第三紀
|
G3AJ13 = ロード・オブ・ザ・リング 中つ国第三紀
|
||||||
G3EJ51 = エクストリームG3
|
G3EJB0 = エクストリームG3
|
||||||
G3NJDA = NARUTO-ナルト-激闘忍者大戦!3
|
G3NJDA = NARUTO-ナルト-激闘忍者大戦!3
|
||||||
G3SJC0 = スーパーパズルボブル オールスターズ
|
G3SJC0 = スーパーパズルボブル オールスターズ
|
||||||
G3TJ8P = ダビつく3 ダービー馬をつくろう!
|
G3TJ8P = ダビつく3 ダービー馬をつくろう!
|
||||||
|
@ -584,6 +1024,7 @@ G4SJ01 = ゼルダの伝説 4つの剣+
|
||||||
G4WJ99 = 牧場物語 しあわせの詩 for ワールド
|
G4WJ99 = 牧場物語 しあわせの詩 for ワールド
|
||||||
G8FJ8P = バーチャファイター サイバージェネレーション
|
G8FJ8P = バーチャファイター サイバージェネレーション
|
||||||
G8MJ01 = ペーパーマリオRPG
|
G8MJ01 = ペーパーマリオRPG
|
||||||
|
G8MK01 = ペーパーマリオRPG
|
||||||
G8OJ18 = ボボボーボ・ボーボボ 脱出!!ハジケ・ロワイヤル
|
G8OJ18 = ボボボーボ・ボーボボ 脱出!!ハジケ・ロワイヤル
|
||||||
G8SJAF = バトルスタジアムD.O.N
|
G8SJAF = バトルスタジアムD.O.N
|
||||||
G8WJ01 = 突撃!!ファミコンウォーズ
|
G8WJ01 = 突撃!!ファミコンウォーズ
|
||||||
|
@ -693,6 +1134,7 @@ GKBJAF = バテン・カイトス 終わらない翼と失われた海
|
||||||
GKDJ01 = 巨人のドシン
|
GKDJ01 = 巨人のドシン
|
||||||
GKEJA4 = 実況パワフルプロ野球12決定版
|
GKEJA4 = 実況パワフルプロ野球12決定版
|
||||||
GKFJ8P = カオスフィールド エクスパンデッド
|
GKFJ8P = カオスフィールド エクスパンデッド
|
||||||
|
GKFJMS = カオスフィールド エクスパンデッド
|
||||||
GKGJ01 = ドンキーコンガ
|
GKGJ01 = ドンキーコンガ
|
||||||
GKJJ78 = カーズ
|
GKJJ78 = カーズ
|
||||||
GKLJ13 = ロード・オブ・ザ・リング/王の帰還
|
GKLJ13 = ロード・オブ・ザ・リング/王の帰還
|
||||||
|
@ -771,7 +1213,7 @@ GSMJ08 = スパイダーマン
|
||||||
GSOJ8P = ソニック メガコレクション
|
GSOJ8P = ソニック メガコレクション
|
||||||
GSSJ8P = セガ サッカースラム
|
GSSJ8P = セガ サッカースラム
|
||||||
GSTJ13 = SSX トリッキー
|
GSTJ13 = SSX トリッキー
|
||||||
GSWJ64 = スター・ウォーズ ローグ スコードロン2
|
GSWJ13 = スター・ウォーズ ローグ スコードロン2
|
||||||
GSXJ13 = スター・ウォーズ クローン戦争
|
GSXJ13 = スター・ウォーズ クローン戦争
|
||||||
GT2J18 = 天外魔境II MANJIMARU
|
GT2J18 = 天外魔境II MANJIMARU
|
||||||
GT3J52 = トニーホークのプロスケーター3
|
GT3J52 = トニーホークのプロスケーター3
|
||||||
|
@ -797,7 +1239,7 @@ GVWJDQ = 学園都市 ヴァラノワールローゼス
|
||||||
GW3JG2 = レッスルマニアX8
|
GW3JG2 = レッスルマニアX8
|
||||||
GW6JEM = ワールドサッカー ウイニングイレブン6 ファイナルエヴォリューション
|
GW6JEM = ワールドサッカー ウイニングイレブン6 ファイナルエヴォリューション
|
||||||
GW9JG2 = レッスルマニアXIX
|
GW9JG2 = レッスルマニアXIX
|
||||||
GWEJ51 = 18 Wheeler
|
GWEJB0 = 18 Wheeler
|
||||||
GWGJ4F = わいわいゴルフ
|
GWGJ4F = わいわいゴルフ
|
||||||
GWPJG2 = WWE デイ・オブ・レコニング
|
GWPJG2 = WWE デイ・オブ・レコニング
|
||||||
GWRJ01 = ウェーブレース ブルーストーム
|
GWRJ01 = ウェーブレース ブルーストーム
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
||||||
TITLES = https://www.gametdb.com (type: Wii language: NL_unique version: 20191106234309)
|
TITLES = https://www.gametdb.com (type: Wii language: NL_unique version: 20230727194218)
|
||||||
R23P52 = Barbie en De Drie Musketiers
|
R23P52 = Barbie en De Drie Musketiers
|
||||||
R25PWR = LEGO Harry Potter: Jaren 1-4
|
R25PWR = LEGO Harry Potter: Jaren 1-4
|
||||||
R27X54 = Dora redt het Land van Kristal
|
R27X54 = Dora redt het Land van Kristal
|
||||||
|
@ -12,11 +12,11 @@ R42P69 = De Sims 2: Op een Onbewoond Eiland
|
||||||
R4CP69 = Simcity Creator
|
R4CP69 = Simcity Creator
|
||||||
R4EP01 = Endless Ocean 2: Een zee vol avontuur
|
R4EP01 = Endless Ocean 2: Een zee vol avontuur
|
||||||
R4PP69 = De Sims 2: Huisdieren
|
R4PP69 = De Sims 2: Huisdieren
|
||||||
R55F41 = Weekend Miljonairs
|
|
||||||
R55P41 = Weekend Miljonairs 1e Editie
|
R55P41 = Weekend Miljonairs 1e Editie
|
||||||
R5FP41 = Academy of Champions
|
R5FP41 = Academy of Champions
|
||||||
R5PP69 = Harry Potter en de Orde van de Feniks
|
R5PP69 = Harry Potter en de Orde van de Feniks
|
||||||
R5PX69 = Harry Potter en de Orde van de Feniks
|
R5PX69 = Harry Potter en de Orde van de Feniks
|
||||||
|
R5XJ13 = MySims Agents
|
||||||
R6XP69 = Hasbro: Familie Spellen Avond 2
|
R6XP69 = Hasbro: Familie Spellen Avond 2
|
||||||
R72P5G = Cake Mania: In The Mix!
|
R72P5G = Cake Mania: In The Mix!
|
||||||
R7YFMR = Peking Express
|
R7YFMR = Peking Express
|
||||||
|
@ -65,7 +65,6 @@ RHNP70 = My Horse and Me
|
||||||
RHZP41 = Horsez: Plezier op de manege
|
RHZP41 = Horsez: Plezier op de manege
|
||||||
RI2P4Q = High School Musical: Sing It!
|
RI2P4Q = High School Musical: Sing It!
|
||||||
RIGP54 = Go, Diego, Go! Het Grote Dinosaurus Avontuur
|
RIGP54 = Go, Diego, Go! Het Grote Dinosaurus Avontuur
|
||||||
RIPPAF = One Piece Unlimited Cruise 1 - The Treasure Beneath the Waves
|
|
||||||
RIQPUJ = Dansen op het ijs
|
RIQPUJ = Dansen op het ijs
|
||||||
RJ9HMN = Think: Train je Brein
|
RJ9HMN = Think: Train je Brein
|
||||||
RJDPKM = Mijn Dierenkliniek
|
RJDPKM = Mijn Dierenkliniek
|
||||||
|
@ -76,7 +75,7 @@ RL2HMN = Paard & Pony: Mijn Paardenstal
|
||||||
RL2PFR = Paard & Pony: Mijn Paardenstal
|
RL2PFR = Paard & Pony: Mijn Paardenstal
|
||||||
RL7P69 = Littlest Pet Shop: Vrienden
|
RL7P69 = Littlest Pet Shop: Vrienden
|
||||||
RLHP52 = Little League World Series Baseball
|
RLHP52 = Little League World Series Baseball
|
||||||
RLLP70 = Go West!: Een Lucky Luke Avontuur!
|
RLLP70 = Go West! Een Lucky Luke Avontuur!
|
||||||
RLNFMR = Expeditie Robinson
|
RLNFMR = Expeditie Robinson
|
||||||
RLNHMR = Expeditie Robinson
|
RLNHMR = Expeditie Robinson
|
||||||
RLNIMR = Expeditie Robinson
|
RLNIMR = Expeditie Robinson
|
||||||
|
@ -89,7 +88,6 @@ RNNP4Q = De Kronieken van Narnia: Prins Caspian
|
||||||
RNNX4Q = De Kronieken van Narnia: Prins Caspian
|
RNNX4Q = De Kronieken van Narnia: Prins Caspian
|
||||||
RNNY4Q = De Kronieken van Narnia: Prins Caspian
|
RNNY4Q = De Kronieken van Narnia: Prins Caspian
|
||||||
RNOP01 = Another Code: R - A Journey Into Lost Memories
|
RNOP01 = Another Code: R - A Journey Into Lost Memories
|
||||||
RNSP69 = Need for Speed: Carbon
|
|
||||||
RO7P7D = De Legende van Spyro: De Eeuwige Nacht
|
RO7P7D = De Legende van Spyro: De Eeuwige Nacht
|
||||||
RO8P7D = De Legende van Spyro: De Opkomst van een Draak
|
RO8P7D = De Legende van Spyro: De Opkomst van een Draak
|
||||||
ROEPGT = Honden Hotel
|
ROEPGT = Honden Hotel
|
||||||
|
@ -107,7 +105,6 @@ RQPP52 = cabela's big game hunter 2009
|
||||||
RQWPG9 = Puzzle Quest - Challenge of the Warlords
|
RQWPG9 = Puzzle Quest - Challenge of the Warlords
|
||||||
RQXP70 = Asterix en de Olympische Spelen
|
RQXP70 = Asterix en de Olympische Spelen
|
||||||
RRCP52 = Barbie Paardenavonturen: Het Paardrijkamp
|
RRCP52 = Barbie Paardenavonturen: Het Paardrijkamp
|
||||||
RRHXUJ = In Mary Kings Riding School 2
|
|
||||||
RRMP69 = Hasbro Familie Spellen Avond
|
RRMP69 = Hasbro Familie Spellen Avond
|
||||||
RRMX69 = Hasbro: Familie Spellen Avond
|
RRMX69 = Hasbro: Familie Spellen Avond
|
||||||
RRQP52 = Shrek - Crazy Party Games
|
RRQP52 = Shrek - Crazy Party Games
|
||||||
|
@ -198,12 +195,143 @@ STOP4Q = Cars Toon: Takel's Sterke Verhalen
|
||||||
STYP52 = Tony Hawk : Shred
|
STYP52 = Tony Hawk : Shred
|
||||||
SVDP52 = SpongeBob Squarepants: Plankton's Robotic Revenge
|
SVDP52 = SpongeBob Squarepants: Plankton's Robotic Revenge
|
||||||
SVMP01 = Super Mario All-Stars : 25th Anniversary Edition
|
SVMP01 = Super Mario All-Stars : 25th Anniversary Edition
|
||||||
|
SVQEVZ = Barbie En Haar Zusjes In Het Grote Puppy Avontuur
|
||||||
SVQPVZ = Barbie En Haar Zusjes In Het Grote Puppy Avontuur
|
SVQPVZ = Barbie En Haar Zusjes In Het Grote Puppy Avontuur
|
||||||
SVZPVZ = Hoe Tem Je Een Draak 2
|
SVZPVZ = Hoe Tem Je Een Draak 2
|
||||||
CG1P52 = Guitar Hero III Custom : Guitar Hero I
|
CG1P52 = Guitar Hero III Custom : Guitar Hero I
|
||||||
|
RMCPCA = Mario Kart Wii (Catalaanse vertaling)
|
||||||
|
W2FP = Physiofun - Balance Training
|
||||||
|
W2GP = Phoenix Wright Ace Attorney: Justice for All
|
||||||
|
W2MP = Blaster Master: Overdrive
|
||||||
|
W2PP = Physiofun: Pelvic Floor Training
|
||||||
|
W3GP = Phoenix Wright Ace Attorney: Trials and Tribulations
|
||||||
|
W3KP = ThruSpace: High Velocity 3D Puzzle
|
||||||
|
W3MP = The Three Musketeers: One for all
|
||||||
|
W44P = Stop Stress: A Day of Fury
|
||||||
|
W4AP = Arcade Sports: Air Hockey, Bowling, Pool, Snooker
|
||||||
|
W6BP = Eco-Shooter: Plant 530
|
||||||
|
W72P = Successfully Learning German Year 3
|
||||||
|
W73P = Successfully Learning German Year 4
|
||||||
|
W74P = Successfully Learning German Year 5
|
||||||
|
W7IP = Successfully Learning German Year 2
|
||||||
|
W8CP = Bit.Trip Core
|
||||||
|
W8WP = Happy Holidays: Halloween
|
||||||
|
W9BP = Big Town Shoot
|
||||||
|
W9RP = Happy Holidays: Christmas
|
||||||
|
WA4P = WarioWare: Do It Yourself - Showcase
|
||||||
|
WA7P = Toribash Violence Perfected
|
||||||
|
WA8P = Art Style: Penta Tentacles
|
||||||
|
WAEP = Around the world
|
||||||
|
WAFP = Airport Mania: First Flight
|
||||||
|
WAHP = Trenches: Generals
|
||||||
|
WALP = Art Style: light trax
|
||||||
|
WAOP = The Very Hungry Caterpillar´s ABC
|
||||||
|
WB2P = Strong Bad Episode 4: Dangeresque 3
|
||||||
|
WB3P = Strong Bad Episode 5: 8-bit is Enough
|
||||||
|
WBEP = Beer Pong: Frat Party Games
|
||||||
|
WBFP = Bit.Trip Fate
|
||||||
|
WBGP = Bang Attack
|
||||||
|
WBPP = PLÄTTCHEN - twist 'n' paint
|
||||||
|
WBRP = Pirates: The Key of Dreams
|
||||||
|
WBXP = Strong Bad Episode 1: Homestar Ruiner
|
||||||
|
WBYP = Strong Bad Episode 2: Strong Badia - The Free
|
||||||
|
WBZP = Strong Bad Episode 3: Baddest of the Bands
|
||||||
|
WCHP = Chess Challenge
|
||||||
|
WCJP = Cocoto: Platform Jumper
|
||||||
|
WCKP = chick chick BOOM
|
||||||
|
WCSP = CueSports: Snooker vs Billiards
|
||||||
|
WD9P = Castlevania: The Adventure ReBirth
|
||||||
|
WDEP = Magic Destiny Astrological Games
|
||||||
|
WDFP = Defend your Castle
|
||||||
|
WDHP = Art Style: ROTOHEX
|
||||||
|
WDPP = Dr. Mario & Germ Buster (Friend Battle Demo)
|
||||||
|
WEMP = Aha! I Got It! Escape Game
|
||||||
|
WETP = PictureBook Games: A Pop-Up Adventure
|
||||||
|
WF2P = Final Fantasy Crystal Chronicles: My Life as a Darklord
|
||||||
|
WF4P = Final Fantasy IV: The After Years
|
||||||
|
WFCP = Final Fantasy Crystal Chronicles: My Life as a King
|
||||||
|
WFQP = Frogger: Hyper Arcade Edition
|
||||||
|
WFTP = Fish'em All!
|
||||||
|
WFVP = Football Up
|
||||||
|
WFWP = Flowerworks: Follie's Adventure
|
||||||
|
WFYP = Family Games Pen & Paper Edition
|
||||||
|
WGDP = Gradius Rebirth
|
||||||
|
WGFP = Girlfriends Forever: Magic Skate
|
||||||
|
WGGP = Gabrielle's Ghostly Groove: Monster Mix
|
||||||
|
WGPP = Zenquaria: Virtual Aquarium
|
||||||
|
WGSP = Phoenix Wright: Ace Attorney
|
||||||
|
WHEP = Heracles: Chariot Racing
|
||||||
|
WHFP = Heavy Fire: Special Operations
|
||||||
|
WHRP = Heron: Steam Machine
|
||||||
|
WHWP = HoopWorld: BasketBrawl
|
||||||
|
WICP = NyxQuest: Kindred Spirits
|
||||||
|
WIDP = Dracula: Undead Awakening
|
||||||
|
WIEP = Tales of Monkey Island Chapter 3: Lair of the Leviathan
|
||||||
|
WILP = Tales of Monkey Island Chapter 1: Launch of the Screaming Narwhal
|
||||||
|
WIRP = Tales of Monkey Island Chapter 5: Rise Of The Pirate God
|
||||||
|
WISP = Tales of Monkey Island Chapter 2: The Siege of Spinner Cay
|
||||||
|
WITP = Aha! I Found It! Hidden Object Game
|
||||||
|
WIYP = Tales of Monkey Island Chapter 4: The Trial and Execution of Guybrush Threepwood
|
||||||
|
WJKP = Jewel Keepers: Easter Island
|
||||||
|
WKBP = You, Me and the Cubes
|
||||||
|
WKFP = Kung Fu Funk: Everybody Is Kung Fu Fighting
|
||||||
|
WKKP = Pop-Up Pirates!
|
||||||
|
WKRP = Karate Phants: Gloves of Glory
|
||||||
|
WKWP = Adventure on LOST ISLAND: Hidden Object Game
|
||||||
WLEE = Leren met de PooYoo's: Aflevering 1
|
WLEE = Leren met de PooYoo's: Aflevering 1
|
||||||
WLEP = Leren met de PooYoo's: Aflevering 1
|
WLEP = Leren met de PooYoo's: Aflevering 1
|
||||||
WLNP = Leren met de PooYoo's: Aflevering 2
|
WLNP = Leren met de PooYoo's: Aflevering 2
|
||||||
|
WLOP = LostWinds: Winter of the Melodias
|
||||||
|
WLZP = lilt line
|
||||||
|
WM7P = Anima Ark of Sinners
|
||||||
|
WMBP = MaBoShi: The Three Shape Arcade
|
||||||
|
WMCP = Monsteca Corral: Monsters Vs. Robots
|
||||||
|
WMJP = Dive: The Medes Islands Secret
|
||||||
|
WMSP = Enjoy your massage!
|
||||||
|
WN9P = Military Madness: Nectaris
|
||||||
|
WNEP = Penguins & Friends Hey! That’s my Fish!
|
||||||
|
WNVP = Neves Plus: Phantheon of Tangrams
|
||||||
|
WOBP = Art Style: ORBIENT
|
||||||
|
WOTP = Overturn: Mecha Wars
|
||||||
|
WP3P = Pearl Harbor Trilogy 1941: Red Sun Rising
|
||||||
|
WP4P = Learning with the PooYoos: Episode 3
|
||||||
|
WPKP = Texas Hold'Em Poker
|
||||||
|
WPQP = Protöthea
|
||||||
|
WPRP = Art Style: CUBELLO
|
||||||
|
WPVP = The Tales of Bearsworth Manor: Chaotic Conflicts
|
||||||
|
WREP = Racers Islands Crazy Arenas
|
||||||
|
WRIP = Rainbow Islands: Towering Adventure!
|
||||||
|
WRJP = Racers Islands - Crazy Racers
|
||||||
|
WRLP = FAST Racing League
|
||||||
|
WRRP = Robin Hood: The Return Of Richard
|
||||||
|
WRUP = Bit.Trip Runner
|
||||||
|
WSGP = Pop Them, Drop Them SAMEGAME
|
||||||
|
WSNP = Sonic The Hedgehog 4 Episode I
|
||||||
|
WSUP = Shootanto: Evolutionary Mayhem
|
||||||
|
WTEP = Tales of Elastic Boy Mission 1
|
||||||
|
WTFP = Bit.Trip Flux
|
||||||
|
WTMP = Adventure Island: The Beginning
|
||||||
|
WTRP = Bit.Trip Beat
|
||||||
|
WTWP = Fenimore Fillmore: The Westerner
|
||||||
|
WTXP = Texas Hold’em Tournament
|
||||||
|
WU2P = Successfully Learning Mathematics Year 3
|
||||||
|
WU3P = Successfully Learning Mathematics Year 4
|
||||||
|
WU4P = Successfully Learning Mathematics Year 5
|
||||||
|
WUIP = Successfully Learning Mathematics Year 2
|
||||||
|
WVBP = Bit.Trip Void
|
||||||
|
WVOP = Rock'n Roll Climber
|
||||||
|
WVSP = Gods Vs Humans
|
||||||
|
WVUP = Mr Bumblebee Racing Champion
|
||||||
|
WW2P = Where's Wally? Fantastic Journey 2
|
||||||
|
WW3P = Where's Wally? Fantastic Journey 3
|
||||||
|
WWIP = Where's Wally? Fantastic Journey 1
|
||||||
|
WWRP = Excitebike: World Challenge
|
||||||
|
WWXP = Paper Wars Cannon Fodder
|
||||||
|
WXBP = Ben 10: Alien Force - The Rise of Hex
|
||||||
|
WYIP = escapeVektor: Chapter 1
|
||||||
|
WYSP = Yard Sale Hidden Treasures Sunnyville
|
||||||
|
WZIP = Rubik's Puzzle Galaxy: RUSH
|
||||||
|
WZZP = The Tales of Bearsworth Manor: Puzzling Pages
|
||||||
XIBP = Fish em All Demo
|
XIBP = Fish em All Demo
|
||||||
XICP = Gods vs Humans Demo
|
XICP = Gods vs Humans Demo
|
||||||
XIDP = Racers Islands Crazy Racers Demo
|
XIDP = Racers Islands Crazy Racers Demo
|
||||||
|
@ -220,19 +348,143 @@ XIUP = Soccer Bashi Demo
|
||||||
XIVP = Mix Superstar Demo
|
XIVP = Mix Superstar Demo
|
||||||
XIZP = 3D Pixel Racing Demo
|
XIZP = 3D Pixel Racing Demo
|
||||||
XJEP = Aya and the Cubes of Light Demo
|
XJEP = Aya and the Cubes of Light Demo
|
||||||
|
FA9P = Zelda II: The Adventure of Link
|
||||||
|
FB2L = Super Mario Bros.: The Lost Levels
|
||||||
|
FBKP = Teenage Mutant Ninja Turles
|
||||||
|
FC8P = Castlevania II: Simon's Quest
|
||||||
|
FCSP = Probotector II: Return of the Evil Forces
|
||||||
|
FDGP = Ghosts'n Goblins
|
||||||
|
FDRP = Skate or Die
|
||||||
|
FEML = Bio Miracle Bokutte UPA
|
||||||
|
FEQP = Castlevania III Dracula's Curse
|
||||||
|
FERM = Startropics II: Zoda's Revenge
|
||||||
|
FF5P = Double Dragon II: The Revenge
|
||||||
|
FFEP = A Boy and His Blob: Trouble on Blobolonia
|
||||||
|
FFPP = Ufouria: THE SAGA
|
||||||
|
FFUP = Adventure Island 2
|
||||||
|
FFVM = S.C.A.T.: Special Cybernetic Attack Team
|
||||||
|
JA4P = Super Ghouls'n Ghosts
|
||||||
|
JABL = Mario’s Super Picross
|
||||||
|
JADP = The Legend of Zelda: A Link to the Past
|
||||||
|
JAFP = SimCity
|
||||||
|
JAHP = R-TYPE III: The Third Lightning
|
||||||
|
JAJP = Street Fighter II: The World Warrior
|
||||||
|
JALP = Super Probotector: Alien Rebels
|
||||||
|
JAZP = The Legend of the Mystical Ninja
|
||||||
|
JBBP = Super Street Fighter II: The New Challengers
|
||||||
|
JBDP = Donkey Kong Country 2: Diddy's Kong-Quest
|
||||||
|
JBIP = Street Fighter II Turbo: Hyper Fighting
|
||||||
|
JBPP = Donkey Kong Country 3: Dixie Kong’s Double Trouble
|
||||||
|
JCAL = DoReMi Fantasy - Milon’s DokiDoki Adventure
|
||||||
|
JCBM = Super Mario RPG: Legend of the Seven Stars
|
||||||
|
JCCP = Kirby’s Fun Pak
|
||||||
|
JCDM = Kirby’s Dream Land 3
|
||||||
|
JCJP = Super Punch Out!!
|
||||||
|
JCKP = Space Invaders -The Original Game-
|
||||||
|
JCTM = Ogre Battle: The March of the Black Queen
|
||||||
|
JD3P = SUPER E.D.F.: Earth Defense Force
|
||||||
|
JDJP = Super Star Wars: The Empire Strikes Back
|
||||||
|
JDLP = Super Star Wars: Return of the Jedi
|
||||||
|
JDWP = Aero The Acrobat
|
||||||
|
JDZP = Mystic Quest Legend
|
||||||
|
NACP = The Legend of Zelda: Ocarina of Time
|
||||||
|
NAMP = Kirby 64: The Crystal Shards
|
||||||
|
NAOP = 1080°: TenEighty Snowboarding
|
||||||
|
NARP = The Legend of Zelda: Majora's Mask
|
||||||
|
NAYM = Ogre Battle 64: Person of Lordly Caliber
|
||||||
|
LALP = Fantasy Zone II
|
||||||
|
LANP = Alex Kidd: The Lost Stars
|
||||||
|
LAPP = Wonder Boy III: The Dragon's Trap
|
||||||
|
MA8P = Ecco: The Tides of Time
|
||||||
|
MAHP = Sonic the Hedgehog
|
||||||
|
MAKP = Shadow Dancer: The Secret of Shinobi
|
||||||
|
MALP = Bonanza Bros.
|
||||||
|
MAOP = Bio-Hazard Battle
|
||||||
|
MAVP = Wonder Boy In Monster World
|
||||||
|
MAXP = Alex Kidd In The Enchanted Castle
|
||||||
|
MB6P = Shining Force II
|
||||||
|
MBBP = Sonic the Hedgehog 2
|
||||||
|
MBFP = Shinobi III: Return of the Ninja master
|
||||||
|
MBIP = Landstalker: The Treasures of King Nole
|
||||||
|
MBJP = Ghouls'n Ghosts
|
||||||
|
MBLP = ESWAT City Under Siege
|
||||||
|
MBMP = Sonic the Hedgehog 3
|
||||||
|
MBUP = Sonic 3D: Flickies' Island
|
||||||
|
MBWM = Columns III: Revenge of Columns
|
||||||
|
MC3P = Super Street Fighter II: The New Challengers
|
||||||
|
MCCP = Phantasy Star III: Generations of Doom
|
||||||
|
MCHM = MUSHA
|
||||||
|
MCLP = Street Fighter II’: Special Champion Edition
|
||||||
|
MCQP = Boogerman - A Pick and Flick Adventure
|
||||||
|
MCRP = Wolf of the Battlefield: MERCS
|
||||||
|
MCSP = Wonder Boy III: Monster Lair
|
||||||
|
MCVP = Pitfall: The Mayan Adventure
|
||||||
|
MCZP = Shanghai II Dragon's Eye
|
||||||
|
PAAP = Bomberman'93
|
||||||
|
PAGL = Bomberman'94
|
||||||
|
PARL = Detana Twin Bee
|
||||||
|
PAWP = Galaga'90
|
||||||
|
PBEP = Motoroader
|
||||||
|
PBIP = Bonk III: Bonk's Big Adventure
|
||||||
|
PBSP = Chew Man Fu
|
||||||
|
PBWP = Air 'Zonk'
|
||||||
|
PCSL = Digital Champ: Battle Boxing
|
||||||
|
PDJL = Street Fighter II': Champion Edition
|
||||||
|
QA3P = SimEarth: The Living Planet
|
||||||
|
QAAP = Super Air Zonk
|
||||||
|
QABP = Ys Book I & II
|
||||||
|
QADL = Gradius II: Gofer no Yabou
|
||||||
|
QAPL = Castlevania: Rondo of Blood
|
||||||
|
EA5P = Fatal Fury 3: Road To The Final Victory
|
||||||
|
EA7P = Samurai Shodown IV: Amakusa's Revenge
|
||||||
|
EA8M = Iron Clad
|
||||||
|
EAIP = Top Hunter
|
||||||
|
EBDP = Magical Drop 3
|
||||||
|
EBFP = Spin master
|
||||||
|
EBSP = The Path of the Warrior: Art of Fighting 3
|
||||||
|
ECAP = Real Bout Fatal Fury 2: The Newcomers
|
||||||
|
ECGP = Shock Troopers: 2nd Squad
|
||||||
|
E54P = GHOSTS'N GOBLINS
|
||||||
|
E55P = Commando
|
||||||
|
E57P = SonSon
|
||||||
|
E6PP = NINJA GAIDEN
|
||||||
|
C93P = The Last Ninja 2
|
||||||
|
C96P = Summer Games 2
|
||||||
|
C9IP = Cybernoid
|
||||||
HAAA = Fotokanaal
|
HAAA = Fotokanaal
|
||||||
|
HABA = Wii-winkelkanaal
|
||||||
|
HACA = Mii-personagekanaal
|
||||||
|
HADE = Internetkanaal
|
||||||
HADP = Internetkanaal
|
HADP = Internetkanaal
|
||||||
HAFP = Weerkanaal
|
HAFP = Weerkanaal
|
||||||
|
HAGA = Nachrichtenkanaal
|
||||||
HAGP = Nieuwskanaal
|
HAGP = Nieuwskanaal
|
||||||
|
HAJP = Enquêtekanaal
|
||||||
|
HAPP = Mii-wedstrijdkanaal
|
||||||
|
HATP = Nintendo-kanaal
|
||||||
|
HAVP = Geluksdagkanaal
|
||||||
|
HAWP = Metroid Prime 3 Preview
|
||||||
HAYA = Fotokanaal
|
HAYA = Fotokanaal
|
||||||
|
HCAP = Jam with the Band Live
|
||||||
|
HCFE = Wii Speak-Kanaal
|
||||||
|
HCFP = Wii Speak-Kanaal
|
||||||
|
OHBC = Homebrew-Kanaal
|
||||||
G4BP08 = Resident Evil 4: Wii Edition
|
G4BP08 = Resident Evil 4: Wii Edition
|
||||||
G4CP54 = Sjakie en chocolade
|
G4CP54 = Sjakie en chocolade
|
||||||
G4MP69 = De Sims: Erop uit!
|
G4MP69 = De Sims: Erop uit!
|
||||||
|
G4OP69 = De Sims 2: Huisdieren
|
||||||
G4ZP69 = De Sims 2
|
G4ZP69 = De Sims 2
|
||||||
GAZH69 = Harry Potter en de gevangene van Azkaban
|
GAZH69 = Harry Potter en de gevangene van Azkaban
|
||||||
GF4H52 = Fantastic Four™ and ©2005
|
GF4H52 = Fantastic Four™ and ©2005
|
||||||
GH4H69 = Harry Potter en de Vuurbeker
|
GH4H69 = Harry Potter en de Vuurbeker
|
||||||
|
GHSP69 = Harry Potter en de Geheime Kamer
|
||||||
GIQX78 = The Incredibles: De opkomst van De Ondermijner
|
GIQX78 = The Incredibles: De opkomst van De Ondermijner
|
||||||
GQQH78 = Nickelodeon SpongeBob Squarepants: Licht uit, Camera aan!
|
GQLP54 = Dora the Explorer: Reis naar de Paarse Planeet
|
||||||
|
GQQD78 = SpongeBob SquarePants: Licht uit, camera aan!
|
||||||
|
GQQE78 = SpongeBob SquarePants: Licht uit, camera aan!
|
||||||
|
GQQF78 = SpongeBob SquarePants: Licht uit, camera aan!
|
||||||
|
GQQH78 = SpongeBob SquarePants: Licht uit, camera aan!
|
||||||
|
GQQP78 = SpongeBob SquarePants: Licht uit, camera aan!
|
||||||
GQWP69 = Harry Potter: WK Zwerkbal
|
GQWP69 = Harry Potter: WK Zwerkbal
|
||||||
|
GUBP69 = De Urbz: Sims in the City
|
||||||
GWHP41 = Winnie de Poeh en het Knaagje in zijn Maagje
|
GWHP41 = Winnie de Poeh en het Knaagje in zijn Maagje
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
TITLES = https://www.gametdb.com (type: Wii language: PT_unique version: 20191106234316)
|
TITLES = https://www.gametdb.com (type: Wii language: PT_unique version: 20230727194225)
|
||||||
R42P69 = Os SIMS 2: Naufragos
|
R42P69 = Os SIMS 2: Naufragos
|
||||||
R43P69 = EA Sports Active
|
R43P69 = EA Sports Active
|
||||||
R4PP69 = Os SIMS 2: Animais de Estimação
|
R4PP69 = Os SIMS 2: Animais de Estimação
|
||||||
|
@ -6,7 +6,9 @@ R5AP8P = A Bússola Dourada
|
||||||
R5AX8P = A Bússola Dourada
|
R5AX8P = A Bússola Dourada
|
||||||
R5PP69 = Harry Potter e a Ordem da Fénix
|
R5PP69 = Harry Potter e a Ordem da Fénix
|
||||||
R5PX69 = Harry Potter e a Ordem da Fénix
|
R5PX69 = Harry Potter e a Ordem da Fénix
|
||||||
|
R5XJ13 = MySims Agents
|
||||||
R6XP69 = Hasbro Family Game Night 2
|
R6XP69 = Hasbro Family Game Night 2
|
||||||
|
RBYJ78 = Barnyard
|
||||||
RBYP78 = Balbúrdia Na Quinta
|
RBYP78 = Balbúrdia Na Quinta
|
||||||
RCAP78 = Carros
|
RCAP78 = Carros
|
||||||
RCAX78 = Carros
|
RCAX78 = Carros
|
||||||
|
@ -15,6 +17,7 @@ RG6P69 = Boogie Superstar
|
||||||
RGQP70 = Os Caça-Fantasmas: O Vídeo Jogo
|
RGQP70 = Os Caça-Fantasmas: O Vídeo Jogo
|
||||||
RH6P69 = Harry Potter e o Príncipe Misterioso
|
RH6P69 = Harry Potter e o Príncipe Misterioso
|
||||||
RHNP70 = O meu Cavalo e eu
|
RHNP70 = O meu Cavalo e eu
|
||||||
|
RJ2JGD = 007: Quantum of Solace
|
||||||
RL7P69 = Littlest Pet Shop: Novos Amigos
|
RL7P69 = Littlest Pet Shop: Novos Amigos
|
||||||
RLWP78 = Ratatui
|
RLWP78 = Ratatui
|
||||||
RLWX78 = Ratatui
|
RLWX78 = Ratatui
|
||||||
|
@ -32,7 +35,61 @@ RZRPGT = Destiny Of Zorro
|
||||||
SERF4Q = Disney Epic Mickey 2: O Regresso dos Heróis
|
SERF4Q = Disney Epic Mickey 2: O Regresso dos Heróis
|
||||||
SERP4Q = Disney Epic Mickey 2: O Regresso dos Heróis
|
SERP4Q = Disney Epic Mickey 2: O Regresso dos Heróis
|
||||||
SHDP52 = Como Treinares o teu Dragão
|
SHDP52 = Como Treinares o teu Dragão
|
||||||
|
SIIP8P = Mario & Sonic nos Jogos Olímpicos de Londres 2012
|
||||||
|
GFEK01 = Fire Emblem: Path of Radiance
|
||||||
|
GMSE02 = Super Mario Sunshine Multijogador
|
||||||
PT2PSI = SingIt Portugal Hits Festa de Verão
|
PT2PSI = SingIt Portugal Hits Festa de Verão
|
||||||
|
RMCPCA = Mario Kart Wii (tradução catalã)
|
||||||
|
WA4E = WarioWare: D.I.Y. Showcase
|
||||||
|
WA4P = _D.I.Y. Showcase
|
||||||
|
WAQJ = Yakuman Wii: Ide Yousuke no Kenkou Mahjong
|
||||||
|
WCSE = CueSports: Pool Revolution
|
||||||
|
WCSP = CueSports: Snooker vs Billiards
|
||||||
|
WL2E = Target Toss Pro: Lawn Darts
|
||||||
|
WN9E = Military Madness: Nectaris
|
||||||
|
WN9J = Military Madness: Nectaris
|
||||||
|
WN9P = Military Madness: Nectaris
|
||||||
|
WPKE = Texas Hold'Em Poker
|
||||||
|
WPKP = Texas Hold'Em Poker
|
||||||
|
WRIE = Rainbow Islands: Towering Adventure!
|
||||||
|
WRIP = Rainbow Islands: Towering Adventure!
|
||||||
|
WRXJ = Mega Man 10
|
||||||
|
WSNE = Sonic The Hedgehog 4 Episode I
|
||||||
|
WSNP = Sonic The Hedgehog 4 Episode I
|
||||||
|
WTXE = Texas Hold’em Tournament
|
||||||
|
WTXP = Texas Hold’em Tournament
|
||||||
|
WZIE = Rubik's Puzzle Galaxy RUSH
|
||||||
|
WZIP = Rubik's Puzzle Galaxy RUSH
|
||||||
|
MC3E = Super Street Fighter II: The New Challengers
|
||||||
|
MC3P = Super Street Fighter II: The New Challengers
|
||||||
HAAA = Canal Photo
|
HAAA = Canal Photo
|
||||||
HAYA = Canal Photo
|
G6TE5G = Os Jovens Titãs
|
||||||
|
GAXE5D = Lucas: Um Intruso no Formigueiro
|
||||||
|
GAZD69 = Harry Potter e o Prisoneiro de Azkaban
|
||||||
|
GAZE69 = Harry Potter e o Prisoneiro de Azkaban
|
||||||
|
GAZF69 = Harry Potter e o Prisoneiro de Azkaban
|
||||||
|
GAZH69 = Harry Potter e o Prisoneiro de Azkaban
|
||||||
|
GAZI69 = Harry Potter e o Prisoneiro de Azkaban
|
||||||
|
GAZJ13 = Harry Potter e o Prisoneiro de Azkaban
|
||||||
|
GAZM69 = Harry Potter e o Prisoneiro de Azkaban
|
||||||
|
GAZP69 = Harry Potter e o Prisoneiro de Azkaban
|
||||||
|
GAZS69 = Harry Potter e o Prisoneiro de Azkaban
|
||||||
|
GB4E51 = Burnout 2: Ponto de Impacto
|
||||||
|
GB4P51 = Burnout 2: Ponto de Impacto
|
||||||
|
GEDJ01 = Eternal Darkness: Sanity's Requiem
|
||||||
|
GENP69 = 007: Everything Or Nothing
|
||||||
|
GFEJ01 = Fire Emblem: Path of Radiance
|
||||||
GHSX69 = Harry Potter e a Câmara dos Segredos
|
GHSX69 = Harry Potter e a Câmara dos Segredos
|
||||||
|
GP3E78 = O Expresso Polar
|
||||||
|
GPQE6L = As Meninas Super-Poderosas: Relish Rampage
|
||||||
|
GR9E6L = Reino de Fogo
|
||||||
|
GT6E70 = O Exterminador do Futuro 3: A Redenção
|
||||||
|
GUBE69 = Os Urbz: Sims na Cidade
|
||||||
|
GW7E69 = 007: Agent Under Fire
|
||||||
|
GW7F69 = 007: Agent Under Fire
|
||||||
|
GW7P69 = 007: Agent Under Fire
|
||||||
|
GWKE41 = Peter Jackson's King Kong: O Jogo Oficial do Filme
|
||||||
|
GXFF69 = FIFA Footeball 2004
|
||||||
|
GXFI69 = FIFA Footeball 2004
|
||||||
|
GXFP69 = FIFA Football
|
||||||
|
GZQE7D = Robôs
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
TITLES = https://www.gametdb.com (type: Wii language: RU_unique version: 20191106234325)
|
TITLES = https://www.gametdb.com (type: Wii language: RU_unique version: 20230727194232)
|
||||||
R5IR4Q = История игрушек: Парк развлечений
|
R5IR4Q = История игрушек: Парк развлечений
|
||||||
RN4P41 = Anno: Create A New World
|
RN4P41 = Anno: Create A New World
|
||||||
RWAR78 = Валл-И
|
RWAR78 = Валл-И
|
||||||
RXDR4Q = Disney Отвечай Не Зевай
|
RXDR4Q = Disney Отвечай Не Зевай
|
||||||
RY2R41 = Возвращение бешеных кролегов
|
RY2R41 = Возвращение бешеных кроликов
|
||||||
RYBP69 = BOOM BLOX Bash Party
|
RYBP69 = BOOM BLOX Bash Party
|
||||||
SFDPAF = 家庭训练机 梦幻主题乐园(欧)
|
SFDPAF = 家庭训练机 梦幻主题乐园(欧)
|
||||||
|
SKSE54 = NBA 2K13(美)
|
||||||
SP5E70 = 恶徒 来自地底的侵略者(美)
|
SP5E70 = 恶徒 来自地底的侵略者(美)
|
||||||
STNP41 = Приключения Тинтина: Тайна Единорога
|
STNP41 = Приключения Тинтина: Тайна Единорога
|
||||||
|
GMSE02 = Супер Марио Саншайн Мультиплеер
|
||||||
|
SOMR01 = Ритм небес
|
||||||
|
G3EP51 = XGIII: 익스트림 G 레이싱
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -14,6 +14,7 @@ import android.widget.Toast;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AppCompatDelegate;
|
import androidx.appcompat.app.AppCompatDelegate;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
@ -72,9 +73,13 @@ public final class DirectoryInitialization
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!setDolphinUserDirectory(context))
|
if (!setDolphinUserDirectory(context))
|
||||||
|
{
|
||||||
|
ContextCompat.getMainExecutor(context).execute(() ->
|
||||||
{
|
{
|
||||||
Toast.makeText(context, R.string.external_storage_not_mounted, Toast.LENGTH_LONG).show();
|
Toast.makeText(context, R.string.external_storage_not_mounted, Toast.LENGTH_LONG).show();
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
extractSysDirectory(context);
|
extractSysDirectory(context);
|
||||||
|
|
|
@ -119,6 +119,8 @@ const Info<std::string> GFX_DRIVER_LIB_NAME{{System::GFX, "Settings", "DriverLib
|
||||||
const Info<TextureFilteringMode> GFX_ENHANCE_FORCE_TEXTURE_FILTERING{
|
const Info<TextureFilteringMode> GFX_ENHANCE_FORCE_TEXTURE_FILTERING{
|
||||||
{System::GFX, "Enhancements", "ForceTextureFiltering"}, TextureFilteringMode::Default};
|
{System::GFX, "Enhancements", "ForceTextureFiltering"}, TextureFilteringMode::Default};
|
||||||
const Info<int> GFX_ENHANCE_MAX_ANISOTROPY{{System::GFX, "Enhancements", "MaxAnisotropy"}, 0};
|
const Info<int> GFX_ENHANCE_MAX_ANISOTROPY{{System::GFX, "Enhancements", "MaxAnisotropy"}, 0};
|
||||||
|
const Info<OutputResamplingMode> GFX_ENHANCE_OUTPUT_RESAMPLING{
|
||||||
|
{System::GFX, "Enhancements", "OutputResampling"}, OutputResamplingMode::Default};
|
||||||
const Info<std::string> GFX_ENHANCE_POST_SHADER{
|
const Info<std::string> GFX_ENHANCE_POST_SHADER{
|
||||||
{System::GFX, "Enhancements", "PostProcessingShader"}, ""};
|
{System::GFX, "Enhancements", "PostProcessingShader"}, ""};
|
||||||
const Info<bool> GFX_ENHANCE_FORCE_TRUE_COLOR{{System::GFX, "Enhancements", "ForceTrueColor"},
|
const Info<bool> GFX_ENHANCE_FORCE_TRUE_COLOR{{System::GFX, "Enhancements", "ForceTrueColor"},
|
||||||
|
|
|
@ -11,6 +11,7 @@ enum class AspectMode : int;
|
||||||
enum class ShaderCompilationMode : int;
|
enum class ShaderCompilationMode : int;
|
||||||
enum class StereoMode : int;
|
enum class StereoMode : int;
|
||||||
enum class TextureFilteringMode : int;
|
enum class TextureFilteringMode : int;
|
||||||
|
enum class OutputResamplingMode : int;
|
||||||
enum class ColorCorrectionRegion : int;
|
enum class ColorCorrectionRegion : int;
|
||||||
enum class TriState : int;
|
enum class TriState : int;
|
||||||
|
|
||||||
|
@ -102,6 +103,7 @@ extern const Info<bool> GFX_MODS_ENABLE;
|
||||||
|
|
||||||
extern const Info<TextureFilteringMode> GFX_ENHANCE_FORCE_TEXTURE_FILTERING;
|
extern const Info<TextureFilteringMode> GFX_ENHANCE_FORCE_TEXTURE_FILTERING;
|
||||||
extern const Info<int> GFX_ENHANCE_MAX_ANISOTROPY; // NOTE - this is x in (1 << x)
|
extern const Info<int> GFX_ENHANCE_MAX_ANISOTROPY; // NOTE - this is x in (1 << x)
|
||||||
|
extern const Info<OutputResamplingMode> GFX_ENHANCE_OUTPUT_RESAMPLING;
|
||||||
extern const Info<std::string> GFX_ENHANCE_POST_SHADER;
|
extern const Info<std::string> GFX_ENHANCE_POST_SHADER;
|
||||||
extern const Info<bool> GFX_ENHANCE_FORCE_TRUE_COLOR;
|
extern const Info<bool> GFX_ENHANCE_FORCE_TRUE_COLOR;
|
||||||
extern const Info<bool> GFX_ENHANCE_DISABLE_COPY_FILTER;
|
extern const Info<bool> GFX_ENHANCE_DISABLE_COPY_FILTER;
|
||||||
|
@ -118,7 +120,7 @@ static constexpr float GFX_CC_DISPLAY_GAMMA_MIN = 2.2f;
|
||||||
static constexpr float GFX_CC_DISPLAY_GAMMA_MAX = 2.4f;
|
static constexpr float GFX_CC_DISPLAY_GAMMA_MAX = 2.4f;
|
||||||
|
|
||||||
static constexpr float GFX_CC_HDR_PAPER_WHITE_NITS_MIN = 80.f;
|
static constexpr float GFX_CC_HDR_PAPER_WHITE_NITS_MIN = 80.f;
|
||||||
static constexpr float GFX_CC_HDR_PAPER_WHITE_NITS_MAX = 400.f;
|
static constexpr float GFX_CC_HDR_PAPER_WHITE_NITS_MAX = 500.f;
|
||||||
|
|
||||||
extern const Info<bool> GFX_CC_CORRECT_COLOR_SPACE;
|
extern const Info<bool> GFX_CC_CORRECT_COLOR_SPACE;
|
||||||
extern const Info<ColorCorrectionRegion> GFX_CC_GAME_COLOR_SPACE;
|
extern const Info<ColorCorrectionRegion> GFX_CC_GAME_COLOR_SPACE;
|
||||||
|
|
|
@ -818,8 +818,6 @@ static bool PauseAndLock(Core::System& system, bool do_lock, bool unpause_on_unl
|
||||||
was_unpaused = system.GetCPU().PauseAndLock(true);
|
was_unpaused = system.GetCPU().PauseAndLock(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
system.GetExpansionInterface().PauseAndLock(do_lock, false);
|
|
||||||
|
|
||||||
// audio has to come after CPU, because CPU thread can wait for audio thread (m_throttle).
|
// audio has to come after CPU, because CPU thread can wait for audio thread (m_throttle).
|
||||||
system.GetDSP().GetDSPEmulator()->PauseAndLock(do_lock);
|
system.GetDSP().GetDSPEmulator()->PauseAndLock(do_lock);
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,15 @@
|
||||||
|
|
||||||
#include "Core/HLE/HLE_OS.h"
|
#include "Core/HLE/HLE_OS.h"
|
||||||
|
|
||||||
|
#include <cinttypes>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <fmt/printf.h>
|
||||||
|
|
||||||
|
#include "Common/BitUtils.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
|
@ -204,82 +210,365 @@ void HLE_LogVFPrint(const Core::CPUThreadGuard& guard)
|
||||||
HLE_LogFPrint(guard, ParameterType::VariableArgumentList);
|
HLE_LogFPrint(guard, ParameterType::VariableArgumentList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class HLEPrintArgsVAList final : public HLEPrintArgs
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HLEPrintArgsVAList(const Core::CPUThreadGuard& guard, HLE::SystemVABI::VAList* va_list)
|
||||||
|
: m_guard(guard), m_va_list(va_list)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 GetU32() override { return m_va_list->GetArgT<u32>(); }
|
||||||
|
u64 GetU64() override { return m_va_list->GetArgT<u64>(); }
|
||||||
|
double GetF64() override { return m_va_list->GetArgT<double>(); }
|
||||||
|
std::string GetString(std::optional<u32> max_length) override
|
||||||
|
{
|
||||||
|
return max_length == 0u ? std::string() :
|
||||||
|
PowerPC::MMU::HostGetString(m_guard, m_va_list->GetArgT<u32>(),
|
||||||
|
max_length.value_or(0u));
|
||||||
|
}
|
||||||
|
std::u16string GetU16String(std::optional<u32> max_length) override
|
||||||
|
{
|
||||||
|
return max_length == 0u ? std::u16string() :
|
||||||
|
PowerPC::MMU::HostGetU16String(m_guard, m_va_list->GetArgT<u32>(),
|
||||||
|
max_length.value_or(0u));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Core::CPUThreadGuard& m_guard;
|
||||||
|
HLE::SystemVABI::VAList* m_va_list;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
std::string GetStringVA(Core::System& system, const Core::CPUThreadGuard& guard, u32 str_reg,
|
std::string GetStringVA(Core::System& system, const Core::CPUThreadGuard& guard, u32 str_reg,
|
||||||
ParameterType parameter_type)
|
ParameterType parameter_type)
|
||||||
{
|
{
|
||||||
auto& ppc_state = system.GetPPCState();
|
auto& ppc_state = system.GetPPCState();
|
||||||
|
|
||||||
std::string ArgumentBuffer;
|
|
||||||
std::string result;
|
|
||||||
std::string string = PowerPC::MMU::HostGetString(guard, ppc_state.gpr[str_reg]);
|
std::string string = PowerPC::MMU::HostGetString(guard, ppc_state.gpr[str_reg]);
|
||||||
auto ap =
|
std::unique_ptr<HLE::SystemVABI::VAList> ap =
|
||||||
parameter_type == ParameterType::VariableArgumentList ?
|
parameter_type == ParameterType::VariableArgumentList ?
|
||||||
std::make_unique<HLE::SystemVABI::VAListStruct>(system, guard,
|
std::make_unique<HLE::SystemVABI::VAListStruct>(guard, ppc_state.gpr[str_reg + 1]) :
|
||||||
ppc_state.gpr[str_reg + 1]) :
|
std::make_unique<HLE::SystemVABI::VAList>(guard, ppc_state.gpr[1] + 0x8, str_reg + 1);
|
||||||
std::make_unique<HLE::SystemVABI::VAList>(system, ppc_state.gpr[1] + 0x8, str_reg + 1);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < string.size(); i++)
|
HLEPrintArgsVAList args(guard, ap.get());
|
||||||
|
return GetStringVA(&args, string);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetStringVA(HLEPrintArgs* args, std::string_view string)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
for (size_t i = 0; i < string.size(); ++i)
|
||||||
{
|
{
|
||||||
if (string[i] == '%')
|
if (string[i] != '%')
|
||||||
{
|
{
|
||||||
ArgumentBuffer = '%';
|
result += string[i];
|
||||||
i++;
|
continue;
|
||||||
if (string[i] == '%')
|
}
|
||||||
|
|
||||||
|
const size_t formatting_start_position = i;
|
||||||
|
++i;
|
||||||
|
if (i < string.size() && string[i] == '%')
|
||||||
{
|
{
|
||||||
result += '%';
|
result += '%';
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (i < string.size() &&
|
bool left_justified_flag = false;
|
||||||
(string[i] < 'A' || string[i] > 'z' || string[i] == 'l' || string[i] == '-'))
|
bool sign_prepended_flag = false;
|
||||||
|
bool space_prepended_flag = false;
|
||||||
|
bool alternative_form_flag = false;
|
||||||
|
bool padding_zeroes_flag = false;
|
||||||
|
while (i < string.size())
|
||||||
{
|
{
|
||||||
ArgumentBuffer += string[i++];
|
if (string[i] == '-')
|
||||||
}
|
left_justified_flag = true;
|
||||||
if (i >= string.size())
|
else if (string[i] == '+')
|
||||||
|
sign_prepended_flag = true;
|
||||||
|
else if (string[i] == ' ')
|
||||||
|
space_prepended_flag = true;
|
||||||
|
else if (string[i] == '#')
|
||||||
|
alternative_form_flag = true;
|
||||||
|
else if (string[i] == '0')
|
||||||
|
padding_zeroes_flag = true;
|
||||||
|
else
|
||||||
break;
|
break;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
ArgumentBuffer += string[i];
|
const auto take_field_or_precision = [&](bool* left_justified_flag_ptr) -> std::optional<u32> {
|
||||||
|
if (i >= string.size())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
switch (string[i])
|
if (string[i] == '*')
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
const s32 result = Common::BitCast<s32>(args->GetU32());
|
||||||
|
if (result >= 0)
|
||||||
|
return static_cast<u32>(result);
|
||||||
|
|
||||||
|
if (left_justified_flag_ptr)
|
||||||
|
{
|
||||||
|
// field width; this results in positive field width and left_justified flag set
|
||||||
|
*left_justified_flag_ptr = true;
|
||||||
|
return static_cast<u32>(-static_cast<s64>(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
// precision; this is ignored
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t start = i;
|
||||||
|
while (i < string.size() && string[i] >= '0' && string[i] <= '9')
|
||||||
|
++i;
|
||||||
|
if (start != i)
|
||||||
|
{
|
||||||
|
while (start < i && string[start] == '0')
|
||||||
|
++start;
|
||||||
|
if (start == i)
|
||||||
|
return 0;
|
||||||
|
u32 result = 0;
|
||||||
|
const std::string tmp(string, start, i - start);
|
||||||
|
if (TryParse(tmp, &result, 10))
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::optional<u32> field_width = take_field_or_precision(&left_justified_flag);
|
||||||
|
std::optional<u32> precision = std::nullopt;
|
||||||
|
if (i < string.size() && string[i] == '.')
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
precision = take_field_or_precision(nullptr).value_or(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class LengthModifier
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
hh,
|
||||||
|
h,
|
||||||
|
l,
|
||||||
|
ll,
|
||||||
|
L,
|
||||||
|
};
|
||||||
|
auto length_modifier = LengthModifier::None;
|
||||||
|
|
||||||
|
if (i < string.size() && (string[i] == 'h' || string[i] == 'l' || string[i] == 'L'))
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
if (i < string.size() && string[i - 1] == 'h' && string[i] == 'h')
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
length_modifier = LengthModifier::hh;
|
||||||
|
}
|
||||||
|
else if (i < string.size() && string[i - 1] == 'l' && string[i] == 'l')
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
length_modifier = LengthModifier::ll;
|
||||||
|
}
|
||||||
|
else if (string[i - 1] == 'h')
|
||||||
|
{
|
||||||
|
length_modifier = LengthModifier::h;
|
||||||
|
}
|
||||||
|
else if (string[i - 1] == 'l')
|
||||||
|
{
|
||||||
|
length_modifier = LengthModifier::l;
|
||||||
|
}
|
||||||
|
else if (string[i - 1] == 'L')
|
||||||
|
{
|
||||||
|
length_modifier = LengthModifier::L;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= string.size())
|
||||||
|
{
|
||||||
|
// not a valid formatting string, print the formatting string as-is
|
||||||
|
result += string.substr(formatting_start_position);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char format_specifier = string[i];
|
||||||
|
switch (format_specifier)
|
||||||
{
|
{
|
||||||
case 's':
|
case 's':
|
||||||
result +=
|
{
|
||||||
StringFromFormat(ArgumentBuffer.c_str(),
|
if (length_modifier == LengthModifier::l)
|
||||||
PowerPC::MMU::HostGetString(guard, ap->GetArgT<u32>(guard)).c_str());
|
{
|
||||||
|
// This is a bit of a mess... wchar_t could be 16 bits or 32 bits per character depending
|
||||||
|
// on the software. Retail software seems usually to use 16 bits and homebrew 32 bits, but
|
||||||
|
// that's really just a guess. Ideally we can figure out a way to autodetect this, but if
|
||||||
|
// not we should probably just expose a setting for it in the debugger somewhere. For now
|
||||||
|
// we just assume 16 bits.
|
||||||
|
fmt::format_to(
|
||||||
|
std::back_inserter(result), fmt::runtime(left_justified_flag ? "{0:<{1}}" : "{0:>{1}}"),
|
||||||
|
UTF8ToSHIFTJIS(UTF16ToUTF8(args->GetU16String(precision))), field_width.value_or(0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fmt::format_to(std::back_inserter(result),
|
||||||
|
fmt::runtime(left_justified_flag ? "{0:<{1}}" : "{0:>{1}}"),
|
||||||
|
args->GetString(precision), field_width.value_or(0));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'a':
|
case 'c':
|
||||||
case 'A':
|
{
|
||||||
case 'e':
|
const s32 value = Common::BitCast<s32>(args->GetU32());
|
||||||
case 'E':
|
if (length_modifier == LengthModifier::l)
|
||||||
|
{
|
||||||
|
// Same problem as with wide strings here.
|
||||||
|
const char16_t wide_char = static_cast<char16_t>(value);
|
||||||
|
fmt::format_to(std::back_inserter(result),
|
||||||
|
fmt::runtime(left_justified_flag ? "{0:<{1}}" : "{0:>{1}}"),
|
||||||
|
UTF8ToSHIFTJIS(UTF16ToUTF8(std::u16string_view(&wide_char, 1))),
|
||||||
|
field_width.value_or(0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fmt::format_to(std::back_inserter(result),
|
||||||
|
fmt::runtime(left_justified_flag ? "{0:<{1}}" : "{0:>{1}}"),
|
||||||
|
static_cast<char>(value), field_width.value_or(0));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'd':
|
||||||
|
case 'i':
|
||||||
|
{
|
||||||
|
const auto options = fmt::format(
|
||||||
|
"{}{}{}{}{}{}", left_justified_flag ? "-" : "", sign_prepended_flag ? "+" : "",
|
||||||
|
space_prepended_flag ? " " : "", padding_zeroes_flag ? "0" : "",
|
||||||
|
field_width ? fmt::format("{}", *field_width) : "",
|
||||||
|
precision ? fmt::format(".{}", *precision) : "");
|
||||||
|
if (length_modifier == LengthModifier::ll)
|
||||||
|
{
|
||||||
|
const s64 value = Common::BitCast<s64>(args->GetU64());
|
||||||
|
result += fmt::sprintf(fmt::format("%{}" PRId64, options).c_str(), value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s32 value = Common::BitCast<s32>(args->GetU32());
|
||||||
|
if (length_modifier == LengthModifier::h)
|
||||||
|
value = static_cast<s16>(value);
|
||||||
|
else if (length_modifier == LengthModifier::hh)
|
||||||
|
value = static_cast<s8>(value);
|
||||||
|
result += fmt::sprintf(fmt::format("%{}" PRId32, options).c_str(), value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'o':
|
||||||
|
{
|
||||||
|
const auto options = fmt::format(
|
||||||
|
"{}{}{}{}{}{}{}", left_justified_flag ? "-" : "", sign_prepended_flag ? "+" : "",
|
||||||
|
space_prepended_flag ? " " : "", alternative_form_flag ? "#" : "",
|
||||||
|
padding_zeroes_flag ? "0" : "", field_width ? fmt::format("{}", *field_width) : "",
|
||||||
|
precision ? fmt::format(".{}", *precision) : "");
|
||||||
|
if (length_modifier == LengthModifier::ll)
|
||||||
|
{
|
||||||
|
const u64 value = args->GetU64();
|
||||||
|
result += fmt::sprintf(fmt::format("%{}" PRIo64, options).c_str(), value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u32 value = args->GetU32();
|
||||||
|
if (length_modifier == LengthModifier::h)
|
||||||
|
value = static_cast<u16>(value);
|
||||||
|
else if (length_modifier == LengthModifier::hh)
|
||||||
|
value = static_cast<u8>(value);
|
||||||
|
result += fmt::sprintf(fmt::format("%{}" PRIo32, options).c_str(), value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'x':
|
||||||
|
case 'X':
|
||||||
|
{
|
||||||
|
const auto options = fmt::format(
|
||||||
|
"{}{}{}{}{}{}{}", left_justified_flag ? "-" : "", sign_prepended_flag ? "+" : "",
|
||||||
|
space_prepended_flag ? " " : "", alternative_form_flag ? "#" : "",
|
||||||
|
padding_zeroes_flag ? "0" : "", field_width ? fmt::format("{}", *field_width) : "",
|
||||||
|
precision ? fmt::format(".{}", *precision) : "");
|
||||||
|
if (length_modifier == LengthModifier::ll)
|
||||||
|
{
|
||||||
|
const u64 value = args->GetU64();
|
||||||
|
result += fmt::sprintf(
|
||||||
|
fmt::format("%{}{}", options, format_specifier == 'x' ? PRIx64 : PRIX64).c_str(),
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u32 value = args->GetU32();
|
||||||
|
if (length_modifier == LengthModifier::h)
|
||||||
|
value = static_cast<u16>(value);
|
||||||
|
else if (length_modifier == LengthModifier::hh)
|
||||||
|
value = static_cast<u8>(value);
|
||||||
|
result += fmt::sprintf(
|
||||||
|
fmt::format("%{}{}", options, format_specifier == 'x' ? PRIx32 : PRIX32).c_str(),
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'u':
|
||||||
|
{
|
||||||
|
const auto options = fmt::format(
|
||||||
|
"{}{}{}{}{}{}", left_justified_flag ? "-" : "", sign_prepended_flag ? "+" : "",
|
||||||
|
space_prepended_flag ? " " : "", padding_zeroes_flag ? "0" : "",
|
||||||
|
field_width ? fmt::format("{}", *field_width) : "",
|
||||||
|
precision ? fmt::format(".{}", *precision) : "");
|
||||||
|
if (length_modifier == LengthModifier::ll)
|
||||||
|
{
|
||||||
|
const u64 value = args->GetU64();
|
||||||
|
result += fmt::sprintf(fmt::format("%{}" PRIu64, options).c_str(), value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u32 value = args->GetU32();
|
||||||
|
if (length_modifier == LengthModifier::h)
|
||||||
|
value = static_cast<u16>(value);
|
||||||
|
else if (length_modifier == LengthModifier::hh)
|
||||||
|
value = static_cast<u8>(value);
|
||||||
|
result += fmt::sprintf(fmt::format("%{}" PRIu32, options).c_str(), value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'f':
|
case 'f':
|
||||||
case 'F':
|
case 'F':
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
case 'a':
|
||||||
|
case 'A':
|
||||||
case 'g':
|
case 'g':
|
||||||
case 'G':
|
case 'G':
|
||||||
result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT<double>(guard));
|
{
|
||||||
|
const auto options = fmt::format(
|
||||||
|
"{}{}{}{}{}{}{}", left_justified_flag ? "-" : "", sign_prepended_flag ? "+" : "",
|
||||||
|
space_prepended_flag ? " " : "", alternative_form_flag ? "#" : "",
|
||||||
|
padding_zeroes_flag ? "0" : "", field_width ? fmt::format("{}", *field_width) : "",
|
||||||
|
precision ? fmt::format(".{}", *precision) : "");
|
||||||
|
double value = args->GetF64();
|
||||||
|
result += fmt::sprintf(fmt::format("%{}{}", options, format_specifier).c_str(), value);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'p':
|
|
||||||
// Override, so 64bit Dolphin prints 32bit pointers, since the ppc is 32bit :)
|
|
||||||
result += StringFromFormat("%x", ap->GetArgT<u32>(guard));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'n':
|
case 'n':
|
||||||
// %n doesn't output anything, so the result variable is untouched
|
// %n doesn't output anything, so the result variable is untouched
|
||||||
// the actual PPC function will take care of the memory write
|
// the actual PPC function will take care of the memory write
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
default:
|
{
|
||||||
if (string[i - 1] == 'l' && string[i - 2] == 'l')
|
const auto options =
|
||||||
result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT<u64>(guard));
|
fmt::format("{}{}{}{}{}", left_justified_flag ? "-" : "", sign_prepended_flag ? "+" : "",
|
||||||
else
|
space_prepended_flag ? " " : "", padding_zeroes_flag ? "0" : "",
|
||||||
result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT<u32>(guard));
|
field_width ? fmt::format("{}", *field_width) : "");
|
||||||
|
const u32 value = args->GetU32();
|
||||||
|
result += fmt::sprintf(fmt::format("%{}" PRIx32, options).c_str(), value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
default:
|
||||||
else
|
// invalid conversion specifier, print the formatting string as-is
|
||||||
{
|
result += string.substr(formatting_start_position, formatting_start_position - i + 1);
|
||||||
result += string[i];
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
namespace Core
|
namespace Core
|
||||||
{
|
{
|
||||||
class CPUThreadGuard;
|
class CPUThreadGuard;
|
||||||
|
@ -10,6 +15,18 @@ class CPUThreadGuard;
|
||||||
|
|
||||||
namespace HLE_OS
|
namespace HLE_OS
|
||||||
{
|
{
|
||||||
|
class HLEPrintArgs
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual u32 GetU32() = 0;
|
||||||
|
virtual u64 GetU64() = 0;
|
||||||
|
virtual double GetF64() = 0;
|
||||||
|
virtual std::string GetString(std::optional<u32> max_length) = 0;
|
||||||
|
virtual std::u16string GetU16String(std::optional<u32> max_length) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string GetStringVA(HLEPrintArgs* args, std::string_view string);
|
||||||
|
|
||||||
void HLE_GeneralDebugPrint(const Core::CPUThreadGuard& guard);
|
void HLE_GeneralDebugPrint(const Core::CPUThreadGuard& guard);
|
||||||
void HLE_GeneralDebugVPrint(const Core::CPUThreadGuard& guard);
|
void HLE_GeneralDebugVPrint(const Core::CPUThreadGuard& guard);
|
||||||
void HLE_write_console(const Core::CPUThreadGuard& guard);
|
void HLE_write_console(const Core::CPUThreadGuard& guard);
|
||||||
|
|
|
@ -2,29 +2,29 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "Core/HLE/HLE_VarArgs.h"
|
#include "Core/HLE/HLE_VarArgs.h"
|
||||||
|
#include "Core/Core.h"
|
||||||
#include "Core/System.h"
|
#include "Core/System.h"
|
||||||
|
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
HLE::SystemVABI::VAList::~VAList() = default;
|
HLE::SystemVABI::VAList::~VAList() = default;
|
||||||
|
|
||||||
u32 HLE::SystemVABI::VAList::GetGPR(const Core::CPUThreadGuard&, u32 gpr) const
|
u32 HLE::SystemVABI::VAList::GetGPR(u32 gpr) const
|
||||||
{
|
{
|
||||||
return m_system.GetPPCState().gpr[gpr];
|
return m_guard.GetSystem().GetPPCState().gpr[gpr];
|
||||||
}
|
}
|
||||||
|
|
||||||
double HLE::SystemVABI::VAList::GetFPR(const Core::CPUThreadGuard&, u32 fpr) const
|
double HLE::SystemVABI::VAList::GetFPR(u32 fpr) const
|
||||||
{
|
{
|
||||||
return m_system.GetPPCState().ps[fpr].PS0AsDouble();
|
return m_guard.GetSystem().GetPPCState().ps[fpr].PS0AsDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
HLE::SystemVABI::VAListStruct::VAListStruct(Core::System& system, const Core::CPUThreadGuard& guard,
|
HLE::SystemVABI::VAListStruct::VAListStruct(const Core::CPUThreadGuard& guard, u32 address)
|
||||||
u32 address)
|
: VAList(guard, 0), m_va_list{PowerPC::MMU::HostRead_U8(guard, address),
|
||||||
: VAList(system, 0), m_va_list{PowerPC::MMU::HostRead_U8(guard, address),
|
|
||||||
PowerPC::MMU::HostRead_U8(guard, address + 1),
|
PowerPC::MMU::HostRead_U8(guard, address + 1),
|
||||||
PowerPC::MMU::HostRead_U32(guard, address + 4),
|
PowerPC::MMU::HostRead_U32(guard, address + 4),
|
||||||
PowerPC::MMU::HostRead_U32(guard, address + 8)},
|
PowerPC::MMU::HostRead_U32(guard, address + 8)},
|
||||||
m_address(address), m_has_fpr_area(system.GetPPCState().cr.GetBit(6) == 1)
|
m_address(address), m_has_fpr_area(guard.GetSystem().GetPPCState().cr.GetBit(6) == 1)
|
||||||
{
|
{
|
||||||
m_stack = m_va_list.overflow_arg_area;
|
m_stack = m_va_list.overflow_arg_area;
|
||||||
m_gpr += m_va_list.gpr;
|
m_gpr += m_va_list.gpr;
|
||||||
|
@ -41,7 +41,7 @@ u32 HLE::SystemVABI::VAListStruct::GetFPRArea() const
|
||||||
return GetGPRArea() + 4 * 8;
|
return GetGPRArea() + 4 * 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 HLE::SystemVABI::VAListStruct::GetGPR(const Core::CPUThreadGuard& guard, u32 gpr) const
|
u32 HLE::SystemVABI::VAListStruct::GetGPR(u32 gpr) const
|
||||||
{
|
{
|
||||||
if (gpr < 3 || gpr > 10)
|
if (gpr < 3 || gpr > 10)
|
||||||
{
|
{
|
||||||
|
@ -49,10 +49,10 @@ u32 HLE::SystemVABI::VAListStruct::GetGPR(const Core::CPUThreadGuard& guard, u32
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const u32 gpr_address = Common::AlignUp(GetGPRArea() + 4 * (gpr - 3), 4);
|
const u32 gpr_address = Common::AlignUp(GetGPRArea() + 4 * (gpr - 3), 4);
|
||||||
return PowerPC::MMU::HostRead_U32(guard, gpr_address);
|
return PowerPC::MMU::HostRead_U32(m_guard, gpr_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
double HLE::SystemVABI::VAListStruct::GetFPR(const Core::CPUThreadGuard& guard, u32 fpr) const
|
double HLE::SystemVABI::VAListStruct::GetFPR(u32 fpr) const
|
||||||
{
|
{
|
||||||
if (!m_has_fpr_area || fpr < 1 || fpr > 8)
|
if (!m_has_fpr_area || fpr < 1 || fpr > 8)
|
||||||
{
|
{
|
||||||
|
@ -60,5 +60,5 @@ double HLE::SystemVABI::VAListStruct::GetFPR(const Core::CPUThreadGuard& guard,
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
const u32 fpr_address = Common::AlignUp(GetFPRArea() + 8 * (fpr - 1), 8);
|
const u32 fpr_address = Common::AlignUp(GetFPRArea() + 8 * (fpr - 1), 8);
|
||||||
return PowerPC::MMU::HostRead_F64(guard, fpr_address);
|
return PowerPC::MMU::HostRead_F64(m_guard, fpr_address);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#include "Common/Align.h"
|
#include "Common/Align.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
#include "Core/PowerPC/MMU.h"
|
#include "Core/PowerPC/MMU.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace Core
|
namespace Core
|
||||||
{
|
{
|
||||||
class CPUThreadGuard;
|
class CPUThreadGuard;
|
||||||
|
@ -38,9 +38,9 @@ constexpr bool IS_ARG_REAL = std::is_floating_point<T>();
|
||||||
class VAList
|
class VAList
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit VAList(Core::System& system, u32 stack, u32 gpr = 3, u32 fpr = 1, u32 gpr_max = 10,
|
explicit VAList(const Core::CPUThreadGuard& guard, u32 stack, u32 gpr = 3, u32 fpr = 1,
|
||||||
u32 fpr_max = 8)
|
u32 gpr_max = 10, u32 fpr_max = 8)
|
||||||
: m_system(system), m_gpr(gpr), m_fpr(fpr), m_gpr_max(gpr_max), m_fpr_max(fpr_max),
|
: m_guard(guard), m_gpr(gpr), m_fpr(fpr), m_gpr_max(gpr_max), m_fpr_max(fpr_max),
|
||||||
m_stack(stack)
|
m_stack(stack)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -48,14 +48,14 @@ public:
|
||||||
|
|
||||||
// 0 - arg_ARGPOINTER
|
// 0 - arg_ARGPOINTER
|
||||||
template <typename T, typename std::enable_if_t<IS_ARG_POINTER<T>>* = nullptr>
|
template <typename T, typename std::enable_if_t<IS_ARG_POINTER<T>>* = nullptr>
|
||||||
T GetArg(const Core::CPUThreadGuard& guard)
|
T GetArg()
|
||||||
{
|
{
|
||||||
T obj;
|
T obj;
|
||||||
u32 addr = GetArg<u32>(guard);
|
u32 addr = GetArg<u32>();
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(T); i += 1, addr += 1)
|
for (size_t i = 0; i < sizeof(T); i += 1, addr += 1)
|
||||||
{
|
{
|
||||||
reinterpret_cast<u8*>(&obj)[i] = PowerPC::MMU::HostRead_U8(guard, addr);
|
reinterpret_cast<u8*>(&obj)[i] = PowerPC::MMU::HostRead_U8(m_guard, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
|
@ -63,20 +63,20 @@ public:
|
||||||
|
|
||||||
// 1 - arg_WORD
|
// 1 - arg_WORD
|
||||||
template <typename T, typename std::enable_if_t<IS_WORD<T>>* = nullptr>
|
template <typename T, typename std::enable_if_t<IS_WORD<T>>* = nullptr>
|
||||||
T GetArg(const Core::CPUThreadGuard& guard)
|
T GetArg()
|
||||||
{
|
{
|
||||||
static_assert(!std::is_pointer<T>(), "VAList doesn't support pointers");
|
static_assert(!std::is_pointer<T>(), "VAList doesn't support pointers");
|
||||||
u64 value;
|
u64 value;
|
||||||
|
|
||||||
if (m_gpr <= m_gpr_max)
|
if (m_gpr <= m_gpr_max)
|
||||||
{
|
{
|
||||||
value = GetGPR(guard, m_gpr);
|
value = GetGPR(m_gpr);
|
||||||
m_gpr += 1;
|
m_gpr += 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_stack = Common::AlignUp(m_stack, 4);
|
m_stack = Common::AlignUp(m_stack, 4);
|
||||||
value = PowerPC::MMU::HostRead_U32(guard, m_stack);
|
value = PowerPC::MMU::HostRead_U32(m_guard, m_stack);
|
||||||
m_stack += 4;
|
m_stack += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ public:
|
||||||
|
|
||||||
// 2 - arg_DOUBLEWORD
|
// 2 - arg_DOUBLEWORD
|
||||||
template <typename T, typename std::enable_if_t<IS_DOUBLE_WORD<T>>* = nullptr>
|
template <typename T, typename std::enable_if_t<IS_DOUBLE_WORD<T>>* = nullptr>
|
||||||
T GetArg(const Core::CPUThreadGuard& guard)
|
T GetArg()
|
||||||
{
|
{
|
||||||
u64 value;
|
u64 value;
|
||||||
|
|
||||||
|
@ -93,13 +93,13 @@ public:
|
||||||
m_gpr += 1;
|
m_gpr += 1;
|
||||||
if (m_gpr < m_gpr_max)
|
if (m_gpr < m_gpr_max)
|
||||||
{
|
{
|
||||||
value = static_cast<u64>(GetGPR(guard, m_gpr)) << 32 | GetGPR(guard, m_gpr + 1);
|
value = static_cast<u64>(GetGPR(m_gpr)) << 32 | GetGPR(m_gpr + 1);
|
||||||
m_gpr += 2;
|
m_gpr += 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_stack = Common::AlignUp(m_stack, 8);
|
m_stack = Common::AlignUp(m_stack, 8);
|
||||||
value = PowerPC::MMU::HostRead_U64(guard, m_stack);
|
value = PowerPC::MMU::HostRead_U64(m_guard, m_stack);
|
||||||
m_stack += 8;
|
m_stack += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,19 +108,19 @@ public:
|
||||||
|
|
||||||
// 3 - arg_ARGREAL
|
// 3 - arg_ARGREAL
|
||||||
template <typename T, typename std::enable_if_t<IS_ARG_REAL<T>>* = nullptr>
|
template <typename T, typename std::enable_if_t<IS_ARG_REAL<T>>* = nullptr>
|
||||||
T GetArg(const Core::CPUThreadGuard& guard)
|
T GetArg()
|
||||||
{
|
{
|
||||||
double value;
|
double value;
|
||||||
|
|
||||||
if (m_fpr <= m_fpr_max)
|
if (m_fpr <= m_fpr_max)
|
||||||
{
|
{
|
||||||
value = GetFPR(guard, m_fpr);
|
value = GetFPR(m_fpr);
|
||||||
m_fpr += 1;
|
m_fpr += 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_stack = Common::AlignUp(m_stack, 8);
|
m_stack = Common::AlignUp(m_stack, 8);
|
||||||
value = PowerPC::MMU::HostRead_F64(guard, m_stack);
|
value = PowerPC::MMU::HostRead_F64(m_guard, m_stack);
|
||||||
m_stack += 8;
|
m_stack += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,13 +129,13 @@ public:
|
||||||
|
|
||||||
// Helper
|
// Helper
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T GetArgT(const Core::CPUThreadGuard& guard)
|
T GetArgT()
|
||||||
{
|
{
|
||||||
return static_cast<T>(GetArg<T>(guard));
|
return static_cast<T>(GetArg<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Core::System& m_system;
|
const Core::CPUThreadGuard& m_guard;
|
||||||
u32 m_gpr = 3;
|
u32 m_gpr = 3;
|
||||||
u32 m_fpr = 1;
|
u32 m_fpr = 1;
|
||||||
const u32 m_gpr_max = 10;
|
const u32 m_gpr_max = 10;
|
||||||
|
@ -143,8 +143,8 @@ protected:
|
||||||
u32 m_stack;
|
u32 m_stack;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual u32 GetGPR(const Core::CPUThreadGuard& guard, u32 gpr) const;
|
virtual u32 GetGPR(u32 gpr) const;
|
||||||
virtual double GetFPR(const Core::CPUThreadGuard& guard, u32 fpr) const;
|
virtual double GetFPR(u32 fpr) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// See System V ABI (SVR4) for more details
|
// See System V ABI (SVR4) for more details
|
||||||
|
@ -156,7 +156,7 @@ private:
|
||||||
class VAListStruct : public VAList
|
class VAListStruct : public VAList
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit VAListStruct(Core::System& system, const Core::CPUThreadGuard& guard, u32 address);
|
explicit VAListStruct(const Core::CPUThreadGuard& guard, u32 address);
|
||||||
~VAListStruct() = default;
|
~VAListStruct() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -174,8 +174,8 @@ private:
|
||||||
u32 GetGPRArea() const;
|
u32 GetGPRArea() const;
|
||||||
u32 GetFPRArea() const;
|
u32 GetFPRArea() const;
|
||||||
|
|
||||||
u32 GetGPR(const Core::CPUThreadGuard& guard, u32 gpr) const override;
|
u32 GetGPR(u32 gpr) const override;
|
||||||
double GetFPR(const Core::CPUThreadGuard& guard, u32 fpr) const override;
|
double GetFPR(u32 fpr) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace HLE::SystemVABI
|
} // namespace HLE::SystemVABI
|
||||||
|
|
|
@ -169,12 +169,6 @@ void ExpansionInterfaceManager::DoState(PointerWrap& p)
|
||||||
channel->DoState(p);
|
channel->DoState(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpansionInterfaceManager::PauseAndLock(bool doLock, bool unpauseOnUnlock)
|
|
||||||
{
|
|
||||||
for (auto& channel : m_channels)
|
|
||||||
channel->PauseAndLock(doLock, unpauseOnUnlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpansionInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
void ExpansionInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAX_EXI_CHANNELS; ++i)
|
for (int i = 0; i < MAX_EXI_CHANNELS; ++i)
|
||||||
|
|
|
@ -72,7 +72,6 @@ public:
|
||||||
void Init(const Sram* override_sram);
|
void Init(const Sram* override_sram);
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
void DoState(PointerWrap& p);
|
void DoState(PointerWrap& p);
|
||||||
void PauseAndLock(bool doLock, bool unpauseOnUnlock);
|
|
||||||
|
|
||||||
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
|
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
|
||||||
|
|
||||||
|
|
|
@ -286,12 +286,6 @@ void CEXIChannel::DoState(PointerWrap& p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIChannel::PauseAndLock(bool do_lock, bool resume_on_unlock)
|
|
||||||
{
|
|
||||||
for (auto& device : m_devices)
|
|
||||||
device->PauseAndLock(do_lock, resume_on_unlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CEXIChannel::SetEXIINT(bool exiint)
|
void CEXIChannel::SetEXIINT(bool exiint)
|
||||||
{
|
{
|
||||||
m_status.EXIINT = !!exiint;
|
m_status.EXIINT = !!exiint;
|
||||||
|
|
|
@ -45,7 +45,6 @@ public:
|
||||||
|
|
||||||
bool IsCausingInterrupt();
|
bool IsCausingInterrupt();
|
||||||
void DoState(PointerWrap& p);
|
void DoState(PointerWrap& p);
|
||||||
void PauseAndLock(bool do_lock, bool resume_on_unlock);
|
|
||||||
|
|
||||||
// This should only be used to transition interrupts from SP1 to Channel 2
|
// This should only be used to transition interrupts from SP1 to Channel 2
|
||||||
void SetEXIINT(bool exiint);
|
void SetEXIINT(bool exiint);
|
||||||
|
|
|
@ -89,10 +89,6 @@ void IEXIDevice::DoState(PointerWrap& p)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void IEXIDevice::PauseAndLock(bool do_lock, bool resume_on_unlock)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IEXIDevice::IsInterruptSet()
|
bool IEXIDevice::IsInterruptSet()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -64,7 +64,6 @@ public:
|
||||||
virtual bool IsPresent() const;
|
virtual bool IsPresent() const;
|
||||||
virtual void SetCS(int cs);
|
virtual void SetCS(int cs);
|
||||||
virtual void DoState(PointerWrap& p);
|
virtual void DoState(PointerWrap& p);
|
||||||
virtual void PauseAndLock(bool do_lock, bool resume_on_unlock = true);
|
|
||||||
|
|
||||||
// Is generating interrupt ?
|
// Is generating interrupt ?
|
||||||
virtual bool IsInterruptSet();
|
virtual bool IsInterruptSet();
|
||||||
|
|
|
@ -169,7 +169,7 @@ NetPlayServer::NetPlayServer(const u16 port, const bool forward_port, NetPlayUI*
|
||||||
m_chunked_data_thread = std::thread(&NetPlayServer::ChunkedDataThreadFunc, this);
|
m_chunked_data_thread = std::thread(&NetPlayServer::ChunkedDataThreadFunc, this);
|
||||||
|
|
||||||
#ifdef USE_UPNP
|
#ifdef USE_UPNP
|
||||||
if (forward_port)
|
if (forward_port && !traversal_config.use_traversal)
|
||||||
Common::UPnP::TryPortmapping(port);
|
Common::UPnP::TryPortmapping(port);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -490,6 +490,21 @@ void Jit64::FakeBLCall(u32 after)
|
||||||
SetJumpTarget(skip_exit);
|
SetJumpTarget(skip_exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Jit64::EmitUpdateMembase()
|
||||||
|
{
|
||||||
|
MOV(64, R(RMEM), PPCSTATE(mem_ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Jit64::EmitStoreMembase(const OpArg& msr, X64Reg scratch_reg)
|
||||||
|
{
|
||||||
|
auto& memory = m_system.GetMemory();
|
||||||
|
MOV(64, R(RMEM), ImmPtr(memory.GetLogicalBase()));
|
||||||
|
MOV(64, R(scratch_reg), ImmPtr(memory.GetPhysicalBase()));
|
||||||
|
TEST(32, msr, Imm32(1 << (31 - 27)));
|
||||||
|
CMOVcc(64, RMEM, R(scratch_reg), CC_Z);
|
||||||
|
MOV(64, PPCSTATE(mem_ptr), R(RMEM));
|
||||||
|
}
|
||||||
|
|
||||||
void Jit64::WriteExit(u32 destination, bool bl, u32 after)
|
void Jit64::WriteExit(u32 destination, bool bl, u32 after)
|
||||||
{
|
{
|
||||||
if (!m_enable_blr_optimization)
|
if (!m_enable_blr_optimization)
|
||||||
|
@ -599,6 +614,7 @@ void Jit64::WriteRfiExitDestInRSCRATCH()
|
||||||
ABI_PushRegistersAndAdjustStack({}, 0);
|
ABI_PushRegistersAndAdjustStack({}, 0);
|
||||||
ABI_CallFunctionP(PowerPC::CheckExceptionsFromJIT, &m_system.GetPowerPC());
|
ABI_CallFunctionP(PowerPC::CheckExceptionsFromJIT, &m_system.GetPowerPC());
|
||||||
ABI_PopRegistersAndAdjustStack({}, 0);
|
ABI_PopRegistersAndAdjustStack({}, 0);
|
||||||
|
EmitUpdateMembase();
|
||||||
SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount));
|
SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount));
|
||||||
JMP(asm_routines.dispatcher, Jump::Near);
|
JMP(asm_routines.dispatcher, Jump::Near);
|
||||||
}
|
}
|
||||||
|
@ -620,6 +636,7 @@ void Jit64::WriteExceptionExit()
|
||||||
ABI_PushRegistersAndAdjustStack({}, 0);
|
ABI_PushRegistersAndAdjustStack({}, 0);
|
||||||
ABI_CallFunctionP(PowerPC::CheckExceptionsFromJIT, &m_system.GetPowerPC());
|
ABI_CallFunctionP(PowerPC::CheckExceptionsFromJIT, &m_system.GetPowerPC());
|
||||||
ABI_PopRegistersAndAdjustStack({}, 0);
|
ABI_PopRegistersAndAdjustStack({}, 0);
|
||||||
|
EmitUpdateMembase();
|
||||||
SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount));
|
SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount));
|
||||||
JMP(asm_routines.dispatcher, Jump::Near);
|
JMP(asm_routines.dispatcher, Jump::Near);
|
||||||
}
|
}
|
||||||
|
@ -632,6 +649,7 @@ void Jit64::WriteExternalExceptionExit()
|
||||||
ABI_PushRegistersAndAdjustStack({}, 0);
|
ABI_PushRegistersAndAdjustStack({}, 0);
|
||||||
ABI_CallFunctionP(PowerPC::CheckExternalExceptionsFromJIT, &m_system.GetPowerPC());
|
ABI_CallFunctionP(PowerPC::CheckExternalExceptionsFromJIT, &m_system.GetPowerPC());
|
||||||
ABI_PopRegistersAndAdjustStack({}, 0);
|
ABI_PopRegistersAndAdjustStack({}, 0);
|
||||||
|
EmitUpdateMembase();
|
||||||
SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount));
|
SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount));
|
||||||
JMP(asm_routines.dispatcher, Jump::Near);
|
JMP(asm_routines.dispatcher, Jump::Near);
|
||||||
}
|
}
|
||||||
|
@ -639,6 +657,7 @@ void Jit64::WriteExternalExceptionExit()
|
||||||
void Jit64::Run()
|
void Jit64::Run()
|
||||||
{
|
{
|
||||||
ProtectStack();
|
ProtectStack();
|
||||||
|
m_system.GetJitInterface().UpdateMembase();
|
||||||
|
|
||||||
CompiledCode pExecAddr = (CompiledCode)asm_routines.enter_code;
|
CompiledCode pExecAddr = (CompiledCode)asm_routines.enter_code;
|
||||||
pExecAddr();
|
pExecAddr();
|
||||||
|
@ -649,6 +668,7 @@ void Jit64::Run()
|
||||||
void Jit64::SingleStep()
|
void Jit64::SingleStep()
|
||||||
{
|
{
|
||||||
ProtectStack();
|
ProtectStack();
|
||||||
|
m_system.GetJitInterface().UpdateMembase();
|
||||||
|
|
||||||
CompiledCode pExecAddr = (CompiledCode)asm_routines.enter_code;
|
CompiledCode pExecAddr = (CompiledCode)asm_routines.enter_code;
|
||||||
pExecAddr();
|
pExecAddr();
|
||||||
|
@ -745,6 +765,7 @@ void Jit64::Jit(u32 em_address, bool clear_cache_and_retry_on_failure)
|
||||||
m_ppc_state.npc = nextPC;
|
m_ppc_state.npc = nextPC;
|
||||||
m_ppc_state.Exceptions |= EXCEPTION_ISI;
|
m_ppc_state.Exceptions |= EXCEPTION_ISI;
|
||||||
m_system.GetPowerPC().CheckExceptions();
|
m_system.GetPowerPC().CheckExceptions();
|
||||||
|
m_system.GetJitInterface().UpdateMembase();
|
||||||
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
|
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,6 +87,8 @@ public:
|
||||||
|
|
||||||
// Utilities for use by opcodes
|
// Utilities for use by opcodes
|
||||||
|
|
||||||
|
void EmitUpdateMembase();
|
||||||
|
void EmitStoreMembase(const Gen::OpArg& msr, Gen::X64Reg scratch_reg);
|
||||||
void FakeBLCall(u32 after);
|
void FakeBLCall(u32 after);
|
||||||
void WriteExit(u32 destination, bool bl = false, u32 after = 0);
|
void WriteExit(u32 destination, bool bl = false, u32 after = 0);
|
||||||
void JustWriteExit(u32 destination, bool bl, u32 after);
|
void JustWriteExit(u32 destination, bool bl, u32 after);
|
||||||
|
|
|
@ -65,6 +65,11 @@ void Jit64AsmRoutineManager::Generate()
|
||||||
ABI_CallFunction(CoreTiming::GlobalAdvance);
|
ABI_CallFunction(CoreTiming::GlobalAdvance);
|
||||||
ABI_PopRegistersAndAdjustStack({}, 0);
|
ABI_PopRegistersAndAdjustStack({}, 0);
|
||||||
|
|
||||||
|
// When we've just entered the jit we need to update the membase
|
||||||
|
// GlobalAdvance also checks exceptions after which we need to
|
||||||
|
// update the membase so it makes sense to do this here.
|
||||||
|
MOV(64, R(RMEM), PPCSTATE(mem_ptr));
|
||||||
|
|
||||||
// skip the sync and compare first time
|
// skip the sync and compare first time
|
||||||
FixupBranch skipToRealDispatch = J(enable_debugging ? Jump::Near : Jump::Short);
|
FixupBranch skipToRealDispatch = J(enable_debugging ? Jump::Near : Jump::Short);
|
||||||
|
|
||||||
|
@ -104,8 +109,6 @@ void Jit64AsmRoutineManager::Generate()
|
||||||
|
|
||||||
dispatcher_no_check = GetCodePtr();
|
dispatcher_no_check = GetCodePtr();
|
||||||
|
|
||||||
auto& memory = system.GetMemory();
|
|
||||||
|
|
||||||
// The following is a translation of JitBaseBlockCache::Dispatch into assembly.
|
// The following is a translation of JitBaseBlockCache::Dispatch into assembly.
|
||||||
const bool assembly_dispatcher = true;
|
const bool assembly_dispatcher = true;
|
||||||
if (assembly_dispatcher)
|
if (assembly_dispatcher)
|
||||||
|
@ -165,13 +168,6 @@ void Jit64AsmRoutineManager::Generate()
|
||||||
FixupBranch state_mismatch = J_CC(CC_NE);
|
FixupBranch state_mismatch = J_CC(CC_NE);
|
||||||
|
|
||||||
// Success; branch to the block we found.
|
// Success; branch to the block we found.
|
||||||
// Switch to the correct memory base, in case MSR.DR has changed.
|
|
||||||
TEST(32, PPCSTATE(msr), Imm32(1 << (31 - 27)));
|
|
||||||
FixupBranch physmem = J_CC(CC_Z);
|
|
||||||
MOV(64, R(RMEM), ImmPtr(memory.GetLogicalBase()));
|
|
||||||
JMPptr(MDisp(RSCRATCH, static_cast<s32>(offsetof(JitBlockData, normalEntry))));
|
|
||||||
SetJumpTarget(physmem);
|
|
||||||
MOV(64, R(RMEM), ImmPtr(memory.GetPhysicalBase()));
|
|
||||||
JMPptr(MDisp(RSCRATCH, static_cast<s32>(offsetof(JitBlockData, normalEntry))));
|
JMPptr(MDisp(RSCRATCH, static_cast<s32>(offsetof(JitBlockData, normalEntry))));
|
||||||
|
|
||||||
SetJumpTarget(not_found);
|
SetJumpTarget(not_found);
|
||||||
|
@ -189,13 +185,7 @@ void Jit64AsmRoutineManager::Generate()
|
||||||
TEST(64, R(ABI_RETURN), R(ABI_RETURN));
|
TEST(64, R(ABI_RETURN), R(ABI_RETURN));
|
||||||
FixupBranch no_block_available = J_CC(CC_Z);
|
FixupBranch no_block_available = J_CC(CC_Z);
|
||||||
|
|
||||||
// Switch to the correct memory base, in case MSR.DR has changed.
|
// Jump to the block
|
||||||
TEST(32, PPCSTATE(msr), Imm32(1 << (31 - 27)));
|
|
||||||
FixupBranch physmem = J_CC(CC_Z);
|
|
||||||
MOV(64, R(RMEM), ImmPtr(memory.GetLogicalBase()));
|
|
||||||
JMPptr(R(ABI_RETURN));
|
|
||||||
SetJumpTarget(physmem);
|
|
||||||
MOV(64, R(RMEM), ImmPtr(memory.GetPhysicalBase()));
|
|
||||||
JMPptr(R(ABI_RETURN));
|
JMPptr(R(ABI_RETURN));
|
||||||
|
|
||||||
SetJumpTarget(no_block_available);
|
SetJumpTarget(no_block_available);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||||
#include "Core/PowerPC/PPCAnalyst.h"
|
#include "Core/PowerPC/PPCAnalyst.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
|
#include "Core/System.h"
|
||||||
|
|
||||||
// The branches are known good, or at least reasonably good.
|
// The branches are known good, or at least reasonably good.
|
||||||
// No need for a disable-mechanism.
|
// No need for a disable-mechanism.
|
||||||
|
@ -54,6 +55,9 @@ void Jit64::rfi(UGeckoInstruction inst)
|
||||||
MOV(32, R(RSCRATCH), PPCSTATE_SRR1);
|
MOV(32, R(RSCRATCH), PPCSTATE_SRR1);
|
||||||
AND(32, R(RSCRATCH), Imm32(mask & clearMSR13));
|
AND(32, R(RSCRATCH), Imm32(mask & clearMSR13));
|
||||||
OR(32, PPCSTATE(msr), R(RSCRATCH));
|
OR(32, PPCSTATE(msr), R(RSCRATCH));
|
||||||
|
|
||||||
|
EmitStoreMembase(R(RSCRATCH), RSCRATCH2);
|
||||||
|
|
||||||
// NPC = SRR0;
|
// NPC = SRR0;
|
||||||
MOV(32, R(RSCRATCH), PPCSTATE_SRR0);
|
MOV(32, R(RSCRATCH), PPCSTATE_SRR0);
|
||||||
WriteRfiExitDestInRSCRATCH();
|
WriteRfiExitDestInRSCRATCH();
|
||||||
|
|
|
@ -438,7 +438,10 @@ void Jit64::mtmsr(UGeckoInstruction inst)
|
||||||
RCOpArg Rs = gpr.BindOrImm(inst.RS, RCMode::Read);
|
RCOpArg Rs = gpr.BindOrImm(inst.RS, RCMode::Read);
|
||||||
RegCache::Realize(Rs);
|
RegCache::Realize(Rs);
|
||||||
MOV(32, PPCSTATE(msr), Rs);
|
MOV(32, PPCSTATE(msr), Rs);
|
||||||
|
|
||||||
|
EmitStoreMembase(PPCSTATE(msr), RSCRATCH2);
|
||||||
}
|
}
|
||||||
|
|
||||||
gpr.Flush();
|
gpr.Flush();
|
||||||
fpr.Flush();
|
fpr.Flush();
|
||||||
|
|
||||||
|
|
|
@ -127,8 +127,11 @@ bool JitArm64::HandleFault(uintptr_t access_address, SContext* ctx)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(DYNA_REC,
|
ERROR_LOG_FMT(DYNA_REC,
|
||||||
"JitArm64 address calculation overflowed. This should never happen! "
|
"JitArm64 address calculation overflowed. This should never happen! "
|
||||||
"PC {:#018x}, access address {:#018x}, memory base {:#018x}, MSR.DR {}",
|
"PC {:#018x}, access address {:#018x}, memory base {:#018x}, MSR.DR {}, "
|
||||||
ctx->CTX_PC, access_address, memory_base, m_ppc_state.msr.DR);
|
"mem_ptr {}, pbase {}, lbase {}",
|
||||||
|
ctx->CTX_PC, access_address, memory_base, m_ppc_state.msr.DR,
|
||||||
|
fmt::ptr(m_ppc_state.mem_ptr), fmt::ptr(memory.GetPhysicalBase()),
|
||||||
|
fmt::ptr(memory.GetLogicalBase()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -353,6 +356,24 @@ void JitArm64::IntializeSpeculativeConstants()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JitArm64::EmitUpdateMembase()
|
||||||
|
{
|
||||||
|
LDR(IndexType::Unsigned, MEM_REG, PPC_REG, PPCSTATE_OFF(mem_ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
void JitArm64::EmitStoreMembase(const ARM64Reg& msr)
|
||||||
|
{
|
||||||
|
auto& memory = m_system.GetMemory();
|
||||||
|
ARM64Reg WD = gpr.GetReg();
|
||||||
|
ARM64Reg XD = EncodeRegTo64(WD);
|
||||||
|
MOVP2R(MEM_REG, jo.fastmem_arena ? memory.GetLogicalBase() : memory.GetLogicalPageMappingsBase());
|
||||||
|
MOVP2R(XD, jo.fastmem_arena ? memory.GetPhysicalBase() : memory.GetPhysicalPageMappingsBase());
|
||||||
|
TST(msr, LogicalImm(1 << (31 - 27), 32));
|
||||||
|
CSEL(MEM_REG, MEM_REG, XD, CCFlags::CC_NEQ);
|
||||||
|
STR(IndexType::Unsigned, MEM_REG, PPC_REG, PPCSTATE_OFF(mem_ptr));
|
||||||
|
gpr.Unlock(WD);
|
||||||
|
}
|
||||||
|
|
||||||
void JitArm64::WriteExit(u32 destination, bool LK, u32 exit_address_after_return)
|
void JitArm64::WriteExit(u32 destination, bool LK, u32 exit_address_after_return)
|
||||||
{
|
{
|
||||||
Cleanup();
|
Cleanup();
|
||||||
|
@ -523,6 +544,7 @@ void JitArm64::WriteExceptionExit(ARM64Reg dest, bool only_external, bool always
|
||||||
else
|
else
|
||||||
MOVP2R(EncodeRegTo64(DISPATCHER_PC), &PowerPC::CheckExceptionsFromJIT);
|
MOVP2R(EncodeRegTo64(DISPATCHER_PC), &PowerPC::CheckExceptionsFromJIT);
|
||||||
BLR(EncodeRegTo64(DISPATCHER_PC));
|
BLR(EncodeRegTo64(DISPATCHER_PC));
|
||||||
|
EmitUpdateMembase();
|
||||||
|
|
||||||
LDR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(npc));
|
LDR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(npc));
|
||||||
|
|
||||||
|
@ -636,6 +658,7 @@ void JitArm64::EndTimeProfile(JitBlock* b)
|
||||||
void JitArm64::Run()
|
void JitArm64::Run()
|
||||||
{
|
{
|
||||||
ProtectStack();
|
ProtectStack();
|
||||||
|
m_system.GetJitInterface().UpdateMembase();
|
||||||
|
|
||||||
CompiledCode pExecAddr = (CompiledCode)enter_code;
|
CompiledCode pExecAddr = (CompiledCode)enter_code;
|
||||||
pExecAddr();
|
pExecAddr();
|
||||||
|
@ -646,6 +669,7 @@ void JitArm64::Run()
|
||||||
void JitArm64::SingleStep()
|
void JitArm64::SingleStep()
|
||||||
{
|
{
|
||||||
ProtectStack();
|
ProtectStack();
|
||||||
|
m_system.GetJitInterface().UpdateMembase();
|
||||||
|
|
||||||
CompiledCode pExecAddr = (CompiledCode)enter_code;
|
CompiledCode pExecAddr = (CompiledCode)enter_code;
|
||||||
pExecAddr();
|
pExecAddr();
|
||||||
|
@ -747,6 +771,7 @@ void JitArm64::Jit(u32 em_address, bool clear_cache_and_retry_on_failure)
|
||||||
m_ppc_state.npc = nextPC;
|
m_ppc_state.npc = nextPC;
|
||||||
m_ppc_state.Exceptions |= EXCEPTION_ISI;
|
m_ppc_state.Exceptions |= EXCEPTION_ISI;
|
||||||
m_system.GetPowerPC().CheckExceptions();
|
m_system.GetPowerPC().CheckExceptions();
|
||||||
|
m_system.GetJitInterface().UpdateMembase();
|
||||||
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
|
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -311,6 +311,9 @@ protected:
|
||||||
void BeginTimeProfile(JitBlock* b);
|
void BeginTimeProfile(JitBlock* b);
|
||||||
void EndTimeProfile(JitBlock* b);
|
void EndTimeProfile(JitBlock* b);
|
||||||
|
|
||||||
|
void EmitUpdateMembase();
|
||||||
|
void EmitStoreMembase(const Arm64Gen::ARM64Reg& msr);
|
||||||
|
|
||||||
// Exits
|
// Exits
|
||||||
void WriteExit(u32 destination, bool LK = false, u32 exit_address_after_return = 0);
|
void WriteExit(u32 destination, bool LK = false, u32 exit_address_after_return = 0);
|
||||||
void WriteExit(Arm64Gen::ARM64Reg dest, bool LK = false, u32 exit_address_after_return = 0);
|
void WriteExit(Arm64Gen::ARM64Reg dest, bool LK = false, u32 exit_address_after_return = 0);
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "Core/PowerPC/JitArm64/JitArm64_RegCache.h"
|
#include "Core/PowerPC/JitArm64/JitArm64_RegCache.h"
|
||||||
#include "Core/PowerPC/PPCTables.h"
|
#include "Core/PowerPC/PPCTables.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
|
#include "Core/System.h"
|
||||||
|
|
||||||
using namespace Arm64Gen;
|
using namespace Arm64Gen;
|
||||||
|
|
||||||
|
@ -64,6 +65,8 @@ void JitArm64::rfi(UGeckoInstruction inst)
|
||||||
|
|
||||||
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(msr)); // STR rB in to rA
|
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(msr)); // STR rB in to rA
|
||||||
|
|
||||||
|
EmitStoreMembase(WA);
|
||||||
|
|
||||||
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF_SPR(SPR_SRR0));
|
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF_SPR(SPR_SRR0));
|
||||||
gpr.Unlock(WB, WC);
|
gpr.Unlock(WB, WC);
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,8 @@ void JitArm64::mtmsr(UGeckoInstruction inst)
|
||||||
gpr.BindToRegister(inst.RS, true);
|
gpr.BindToRegister(inst.RS, true);
|
||||||
STR(IndexType::Unsigned, gpr.R(inst.RS), PPC_REG, PPCSTATE_OFF(msr));
|
STR(IndexType::Unsigned, gpr.R(inst.RS), PPC_REG, PPCSTATE_OFF(msr));
|
||||||
|
|
||||||
|
EmitStoreMembase(gpr.R(inst.RS));
|
||||||
|
|
||||||
gpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG);
|
gpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG);
|
||||||
fpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG);
|
fpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG);
|
||||||
|
|
||||||
|
|
|
@ -95,26 +95,13 @@ void JitArm64::GenerateAsm()
|
||||||
|
|
||||||
bool assembly_dispatcher = true;
|
bool assembly_dispatcher = true;
|
||||||
|
|
||||||
auto& memory = m_system.GetMemory();
|
|
||||||
|
|
||||||
if (assembly_dispatcher)
|
if (assembly_dispatcher)
|
||||||
{
|
{
|
||||||
// set the mem_base based on MSR flags
|
|
||||||
LDR(IndexType::Unsigned, ARM64Reg::W28, PPC_REG, PPCSTATE_OFF(msr));
|
|
||||||
FixupBranch physmem = TBNZ(ARM64Reg::W28, 31 - 27);
|
|
||||||
MOVP2R(MEM_REG,
|
|
||||||
jo.fastmem_arena ? memory.GetPhysicalBase() : memory.GetPhysicalPageMappingsBase());
|
|
||||||
FixupBranch membaseend = B();
|
|
||||||
SetJumpTarget(physmem);
|
|
||||||
MOVP2R(MEM_REG,
|
|
||||||
jo.fastmem_arena ? memory.GetLogicalBase() : memory.GetLogicalPageMappingsBase());
|
|
||||||
SetJumpTarget(membaseend);
|
|
||||||
|
|
||||||
if (GetBlockCache()->GetFastBlockMap())
|
if (GetBlockCache()->GetFastBlockMap())
|
||||||
{
|
{
|
||||||
// Check if there is a block
|
// Check if there is a block
|
||||||
ARM64Reg pc_masked = ARM64Reg::X25;
|
ARM64Reg pc_masked = ARM64Reg::X25;
|
||||||
ARM64Reg cache_base = ARM64Reg::X27;
|
ARM64Reg cache_base = ARM64Reg::X24;
|
||||||
ARM64Reg block = ARM64Reg::X30;
|
ARM64Reg block = ARM64Reg::X30;
|
||||||
LSL(pc_masked, DISPATCHER_PC, 1);
|
LSL(pc_masked, DISPATCHER_PC, 1);
|
||||||
MOVP2R(cache_base, GetBlockCache()->GetFastBlockMap());
|
MOVP2R(cache_base, GetBlockCache()->GetFastBlockMap());
|
||||||
|
@ -122,7 +109,7 @@ void JitArm64::GenerateAsm()
|
||||||
FixupBranch not_found = CBZ(block);
|
FixupBranch not_found = CBZ(block);
|
||||||
|
|
||||||
// b.msrBits != msr
|
// b.msrBits != msr
|
||||||
ARM64Reg msr = ARM64Reg::W25;
|
ARM64Reg msr = ARM64Reg::W27;
|
||||||
ARM64Reg msr2 = ARM64Reg::W24;
|
ARM64Reg msr2 = ARM64Reg::W24;
|
||||||
LDR(IndexType::Unsigned, msr, PPC_REG, PPCSTATE_OFF(msr));
|
LDR(IndexType::Unsigned, msr, PPC_REG, PPCSTATE_OFF(msr));
|
||||||
AND(msr, msr, LogicalImm(JitBaseBlockCache::JIT_CACHE_MSR_MASK, 32));
|
AND(msr, msr, LogicalImm(JitBaseBlockCache::JIT_CACHE_MSR_MASK, 32));
|
||||||
|
@ -181,14 +168,6 @@ void JitArm64::GenerateAsm()
|
||||||
|
|
||||||
FixupBranch no_block_available = CBZ(ARM64Reg::X0);
|
FixupBranch no_block_available = CBZ(ARM64Reg::X0);
|
||||||
|
|
||||||
// set the mem_base based on MSR flags and jump to next block.
|
|
||||||
LDR(IndexType::Unsigned, ARM64Reg::W28, PPC_REG, PPCSTATE_OFF(msr));
|
|
||||||
FixupBranch physmem = TBNZ(ARM64Reg::W28, 31 - 27);
|
|
||||||
MOVP2R(MEM_REG,
|
|
||||||
jo.fastmem_arena ? memory.GetPhysicalBase() : memory.GetPhysicalPageMappingsBase());
|
|
||||||
BR(ARM64Reg::X0);
|
|
||||||
SetJumpTarget(physmem);
|
|
||||||
MOVP2R(MEM_REG, jo.fastmem_arena ? memory.GetLogicalBase() : memory.GetLogicalPageMappingsBase());
|
|
||||||
BR(ARM64Reg::X0);
|
BR(ARM64Reg::X0);
|
||||||
|
|
||||||
// Call JIT
|
// Call JIT
|
||||||
|
@ -217,6 +196,11 @@ void JitArm64::GenerateAsm()
|
||||||
MOVP2R(ARM64Reg::X8, &CoreTiming::GlobalAdvance);
|
MOVP2R(ARM64Reg::X8, &CoreTiming::GlobalAdvance);
|
||||||
BLR(ARM64Reg::X8);
|
BLR(ARM64Reg::X8);
|
||||||
|
|
||||||
|
// When we've just entered the jit we need to update the membase
|
||||||
|
// GlobalAdvance also checks exceptions after which we need to
|
||||||
|
// update the membase so it makes sense to do this here.
|
||||||
|
EmitUpdateMembase();
|
||||||
|
|
||||||
// Load the PC back into DISPATCHER_PC (the exception handler might have changed it)
|
// Load the PC back into DISPATCHER_PC (the exception handler might have changed it)
|
||||||
LDR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc));
|
LDR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc));
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,25 @@ void JitInterface::SetProfilingState(ProfilingState state)
|
||||||
m_jit->jo.profile_blocks = state == ProfilingState::Enabled;
|
m_jit->jo.profile_blocks = state == ProfilingState::Enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JitInterface::UpdateMembase()
|
||||||
|
{
|
||||||
|
if (!m_jit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& ppc_state = m_system.GetPPCState();
|
||||||
|
auto& memory = m_system.GetMemory();
|
||||||
|
if (ppc_state.msr.DR)
|
||||||
|
{
|
||||||
|
ppc_state.mem_ptr =
|
||||||
|
m_jit->jo.fastmem_arena ? memory.GetLogicalBase() : memory.GetLogicalPageMappingsBase();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ppc_state.mem_ptr =
|
||||||
|
m_jit->jo.fastmem_arena ? memory.GetPhysicalBase() : memory.GetPhysicalPageMappingsBase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void JitInterface::WriteProfileResults(const std::string& filename) const
|
void JitInterface::WriteProfileResults(const std::string& filename) const
|
||||||
{
|
{
|
||||||
Profiler::ProfileStats prof_stats;
|
Profiler::ProfileStats prof_stats;
|
||||||
|
|
|
@ -61,6 +61,7 @@ public:
|
||||||
u32 entry_address;
|
u32 entry_address;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void UpdateMembase();
|
||||||
void SetProfilingState(ProfilingState state);
|
void SetProfilingState(ProfilingState state);
|
||||||
void WriteProfileResults(const std::string& filename) const;
|
void WriteProfileResults(const std::string& filename) const;
|
||||||
void GetProfileResults(Profiler::ProfileStats* prof_stats) const;
|
void GetProfileResults(Profiler::ProfileStats* prof_stats) const;
|
||||||
|
|
|
@ -867,6 +867,22 @@ std::string MMU::HostGetString(const Core::CPUThreadGuard& guard, u32 address, s
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::u16string MMU::HostGetU16String(const Core::CPUThreadGuard& guard, u32 address, size_t size)
|
||||||
|
{
|
||||||
|
std::u16string s;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!HostIsRAMAddress(guard, address) || !HostIsRAMAddress(guard, address + 1))
|
||||||
|
break;
|
||||||
|
const u16 res = HostRead_U16(guard, address);
|
||||||
|
if (!res)
|
||||||
|
break;
|
||||||
|
s += static_cast<char16_t>(res);
|
||||||
|
address += 2;
|
||||||
|
} while (size == 0 || s.length() < size);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<ReadResult<std::string>> MMU::HostTryReadString(const Core::CPUThreadGuard& guard,
|
std::optional<ReadResult<std::string>> MMU::HostTryReadString(const Core::CPUThreadGuard& guard,
|
||||||
u32 address, size_t size,
|
u32 address, size_t size,
|
||||||
RequestedAddressSpace space)
|
RequestedAddressSpace space)
|
||||||
|
|
|
@ -132,6 +132,8 @@ public:
|
||||||
static double HostRead_F64(const Core::CPUThreadGuard& guard, u32 address);
|
static double HostRead_F64(const Core::CPUThreadGuard& guard, u32 address);
|
||||||
static u32 HostRead_Instruction(const Core::CPUThreadGuard& guard, u32 address);
|
static u32 HostRead_Instruction(const Core::CPUThreadGuard& guard, u32 address);
|
||||||
static std::string HostGetString(const Core::CPUThreadGuard& guard, u32 address, size_t size = 0);
|
static std::string HostGetString(const Core::CPUThreadGuard& guard, u32 address, size_t size = 0);
|
||||||
|
static std::u16string HostGetU16String(const Core::CPUThreadGuard& guard, u32 address,
|
||||||
|
size_t size = 0);
|
||||||
|
|
||||||
// Try to read a value from emulated memory at the given address in the given memory space.
|
// Try to read a value from emulated memory at the given address in the given memory space.
|
||||||
// If the read succeeds, the returned value will be present and the ReadResult contains the read
|
// If the read succeeds, the returned value will be present and the ReadResult contains the read
|
||||||
|
|
|
@ -236,9 +236,9 @@ void PowerPCManager::InitializeCPUCore(CPUCore cpu_core)
|
||||||
m_mode = m_cpu_core_base == &interpreter ? CoreMode::Interpreter : CoreMode::JIT;
|
m_mode = m_cpu_core_base == &interpreter ? CoreMode::Interpreter : CoreMode::JIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<CPUCore>& AvailableCPUCores()
|
std::span<const CPUCore> AvailableCPUCores()
|
||||||
{
|
{
|
||||||
static const std::vector<CPUCore> cpu_cores = {
|
static constexpr auto cpu_cores = {
|
||||||
#ifdef _M_X86_64
|
#ifdef _M_X86_64
|
||||||
CPUCore::JIT64,
|
CPUCore::JIT64,
|
||||||
#elif defined(_M_ARM_64)
|
#elif defined(_M_ARM_64)
|
||||||
|
@ -569,7 +569,10 @@ void PowerPCManager::CheckExceptions()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CheckExternalExceptions();
|
CheckExternalExceptions();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_system.GetJitInterface().UpdateMembase();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PowerPCManager::CheckExternalExceptions()
|
void PowerPCManager::CheckExternalExceptions()
|
||||||
|
@ -623,6 +626,8 @@ void PowerPCManager::CheckExternalExceptions()
|
||||||
exceptions);
|
exceptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_system.GetJitInterface().UpdateMembase();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PowerPCManager::CheckBreakPoints()
|
void PowerPCManager::CheckBreakPoints()
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
|
#include <span>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -169,6 +170,7 @@ struct PowerPCState
|
||||||
|
|
||||||
// Storage for the stack pointer of the BLR optimization.
|
// Storage for the stack pointer of the BLR optimization.
|
||||||
u8* stored_stack_pointer = nullptr;
|
u8* stored_stack_pointer = nullptr;
|
||||||
|
u8* mem_ptr = nullptr;
|
||||||
|
|
||||||
std::array<std::array<TLBEntry, TLB_SIZE / TLB_WAYS>, NUM_TLBS> tlb;
|
std::array<std::array<TLBEntry, TLB_SIZE / TLB_WAYS>, NUM_TLBS> tlb;
|
||||||
|
|
||||||
|
@ -238,7 +240,7 @@ static_assert(offsetof(PowerPC::PowerPCState, above_fits_in_first_0x100) <= 0x10
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const std::vector<CPUCore>& AvailableCPUCores();
|
std::span<const CPUCore> AvailableCPUCores();
|
||||||
CPUCore DefaultCPUCore();
|
CPUCore DefaultCPUCore();
|
||||||
|
|
||||||
class PowerPCManager
|
class PowerPCManager
|
||||||
|
|
|
@ -663,15 +663,18 @@
|
||||||
<ClInclude Include="VideoCommon\GeometryShaderGen.h" />
|
<ClInclude Include="VideoCommon\GeometryShaderGen.h" />
|
||||||
<ClInclude Include="VideoCommon\GeometryShaderManager.h" />
|
<ClInclude Include="VideoCommon\GeometryShaderManager.h" />
|
||||||
<ClInclude Include="VideoCommon\GraphicsModSystem\Config\GraphicsMod.h" />
|
<ClInclude Include="VideoCommon\GraphicsModSystem\Config\GraphicsMod.h" />
|
||||||
|
<ClInclude Include="VideoCommon\GraphicsModSystem\Config\GraphicsModAsset.h" />
|
||||||
<ClInclude Include="VideoCommon\GraphicsModSystem\Config\GraphicsModFeature.h" />
|
<ClInclude Include="VideoCommon\GraphicsModSystem\Config\GraphicsModFeature.h" />
|
||||||
<ClInclude Include="VideoCommon\GraphicsModSystem\Config\GraphicsModGroup.h" />
|
<ClInclude Include="VideoCommon\GraphicsModSystem\Config\GraphicsModGroup.h" />
|
||||||
<ClInclude Include="VideoCommon\GraphicsModSystem\Config\GraphicsTarget.h" />
|
<ClInclude Include="VideoCommon\GraphicsModSystem\Config\GraphicsTarget.h" />
|
||||||
<ClInclude Include="VideoCommon\GraphicsModSystem\Config\GraphicsTargetGroup.h" />
|
<ClInclude Include="VideoCommon\GraphicsModSystem\Config\GraphicsTargetGroup.h" />
|
||||||
<ClInclude Include="VideoCommon\GraphicsModSystem\Constants.h" />
|
<ClInclude Include="VideoCommon\GraphicsModSystem\Constants.h" />
|
||||||
|
<ClInclude Include="VideoCommon\GraphicsModSystem\Runtime\Actions\CustomPipelineAction.h" />
|
||||||
<ClInclude Include="VideoCommon\GraphicsModSystem\Runtime\Actions\MoveAction.h" />
|
<ClInclude Include="VideoCommon\GraphicsModSystem\Runtime\Actions\MoveAction.h" />
|
||||||
<ClInclude Include="VideoCommon\GraphicsModSystem\Runtime\Actions\PrintAction.h" />
|
<ClInclude Include="VideoCommon\GraphicsModSystem\Runtime\Actions\PrintAction.h" />
|
||||||
<ClInclude Include="VideoCommon\GraphicsModSystem\Runtime\Actions\ScaleAction.h" />
|
<ClInclude Include="VideoCommon\GraphicsModSystem\Runtime\Actions\ScaleAction.h" />
|
||||||
<ClInclude Include="VideoCommon\GraphicsModSystem\Runtime\Actions\SkipAction.h" />
|
<ClInclude Include="VideoCommon\GraphicsModSystem\Runtime\Actions\SkipAction.h" />
|
||||||
|
<ClInclude Include="VideoCommon\GraphicsModSystem\Runtime\CustomShaderCache.h" />
|
||||||
<ClInclude Include="VideoCommon\GraphicsModSystem\Runtime\FBInfo.h" />
|
<ClInclude Include="VideoCommon\GraphicsModSystem\Runtime\FBInfo.h" />
|
||||||
<ClInclude Include="VideoCommon\GraphicsModSystem\Runtime\GraphicsModAction.h" />
|
<ClInclude Include="VideoCommon\GraphicsModSystem\Runtime\GraphicsModAction.h" />
|
||||||
<ClInclude Include="VideoCommon\GraphicsModSystem\Runtime\GraphicsModActionData.h" />
|
<ClInclude Include="VideoCommon\GraphicsModSystem\Runtime\GraphicsModActionData.h" />
|
||||||
|
@ -1276,14 +1279,17 @@
|
||||||
<ClCompile Include="VideoCommon\GeometryShaderGen.cpp" />
|
<ClCompile Include="VideoCommon\GeometryShaderGen.cpp" />
|
||||||
<ClCompile Include="VideoCommon\GeometryShaderManager.cpp" />
|
<ClCompile Include="VideoCommon\GeometryShaderManager.cpp" />
|
||||||
<ClCompile Include="VideoCommon\GraphicsModSystem\Config\GraphicsMod.cpp" />
|
<ClCompile Include="VideoCommon\GraphicsModSystem\Config\GraphicsMod.cpp" />
|
||||||
|
<ClCompile Include="VideoCommon\GraphicsModSystem\Config\GraphicsModAsset.cpp" />
|
||||||
<ClCompile Include="VideoCommon\GraphicsModSystem\Config\GraphicsModFeature.cpp" />
|
<ClCompile Include="VideoCommon\GraphicsModSystem\Config\GraphicsModFeature.cpp" />
|
||||||
<ClCompile Include="VideoCommon\GraphicsModSystem\Config\GraphicsModGroup.cpp" />
|
<ClCompile Include="VideoCommon\GraphicsModSystem\Config\GraphicsModGroup.cpp" />
|
||||||
<ClCompile Include="VideoCommon\GraphicsModSystem\Config\GraphicsTarget.cpp" />
|
<ClCompile Include="VideoCommon\GraphicsModSystem\Config\GraphicsTarget.cpp" />
|
||||||
<ClCompile Include="VideoCommon\GraphicsModSystem\Config\GraphicsTargetGroup.cpp" />
|
<ClCompile Include="VideoCommon\GraphicsModSystem\Config\GraphicsTargetGroup.cpp" />
|
||||||
|
<ClCompile Include="VideoCommon\GraphicsModSystem\Runtime\Actions\CustomPipelineAction.cpp" />
|
||||||
<ClCompile Include="VideoCommon\GraphicsModSystem\Runtime\Actions\MoveAction.cpp" />
|
<ClCompile Include="VideoCommon\GraphicsModSystem\Runtime\Actions\MoveAction.cpp" />
|
||||||
<ClCompile Include="VideoCommon\GraphicsModSystem\Runtime\Actions\PrintAction.cpp" />
|
<ClCompile Include="VideoCommon\GraphicsModSystem\Runtime\Actions\PrintAction.cpp" />
|
||||||
<ClCompile Include="VideoCommon\GraphicsModSystem\Runtime\Actions\ScaleAction.cpp" />
|
<ClCompile Include="VideoCommon\GraphicsModSystem\Runtime\Actions\ScaleAction.cpp" />
|
||||||
<ClCompile Include="VideoCommon\GraphicsModSystem\Runtime\Actions\SkipAction.cpp" />
|
<ClCompile Include="VideoCommon\GraphicsModSystem\Runtime\Actions\SkipAction.cpp" />
|
||||||
|
<ClCompile Include="VideoCommon\GraphicsModSystem\Runtime\CustomShaderCache.cpp" />
|
||||||
<ClCompile Include="VideoCommon\GraphicsModSystem\Runtime\FBInfo.cpp" />
|
<ClCompile Include="VideoCommon\GraphicsModSystem\Runtime\FBInfo.cpp" />
|
||||||
<ClCompile Include="VideoCommon\GraphicsModSystem\Runtime\GraphicsModActionFactory.cpp" />
|
<ClCompile Include="VideoCommon\GraphicsModSystem\Runtime\GraphicsModActionFactory.cpp" />
|
||||||
<ClCompile Include="VideoCommon\GraphicsModSystem\Runtime\GraphicsModManager.cpp" />
|
<ClCompile Include="VideoCommon\GraphicsModSystem\Runtime\GraphicsModManager.cpp" />
|
||||||
|
|
|
@ -52,8 +52,8 @@ void AchievementSettingsWidget::CreateLayout()
|
||||||
m_common_password_label = new QLabel(tr("Password"));
|
m_common_password_label = new QLabel(tr("Password"));
|
||||||
m_common_password_input = new QLineEdit(QStringLiteral(""));
|
m_common_password_input = new QLineEdit(QStringLiteral(""));
|
||||||
m_common_password_input->setEchoMode(QLineEdit::Password);
|
m_common_password_input->setEchoMode(QLineEdit::Password);
|
||||||
m_common_login_button = new QPushButton(tr("Login"));
|
m_common_login_button = new QPushButton(tr("Log In"));
|
||||||
m_common_logout_button = new QPushButton(tr("Logout"));
|
m_common_logout_button = new QPushButton(tr("Log Out"));
|
||||||
m_common_login_failed = new QLabel(tr("Login Failed"));
|
m_common_login_failed = new QLabel(tr("Login Failed"));
|
||||||
m_common_login_failed->setStyleSheet(QStringLiteral("QLabel { color : red; }"));
|
m_common_login_failed->setStyleSheet(QStringLiteral("QLabel { color : red; }"));
|
||||||
m_common_login_failed->setVisible(false);
|
m_common_login_failed->setVisible(false);
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "DolphinQt/Config/Graphics/ColorCorrectionConfigWindow.h"
|
#include "DolphinQt/Config/Graphics/ColorCorrectionConfigWindow.h"
|
||||||
#include "DolphinQt/Config/Graphics/GraphicsWindow.h"
|
#include "DolphinQt/Config/Graphics/GraphicsWindow.h"
|
||||||
#include "DolphinQt/Config/Graphics/PostProcessingConfigWindow.h"
|
#include "DolphinQt/Config/Graphics/PostProcessingConfigWindow.h"
|
||||||
|
#include "DolphinQt/Config/ToolTipControls/ToolTipPushButton.h"
|
||||||
#include "DolphinQt/QtUtils/NonDefaultQPushButton.h"
|
#include "DolphinQt/QtUtils/NonDefaultQPushButton.h"
|
||||||
#include "DolphinQt/QtUtils/SetWindowDecorations.h"
|
#include "DolphinQt/QtUtils/SetWindowDecorations.h"
|
||||||
#include "DolphinQt/Settings.h"
|
#include "DolphinQt/Settings.h"
|
||||||
|
@ -104,7 +105,23 @@ void EnhancementsWidget::CreateWidgets()
|
||||||
m_texture_filtering_combo->addItem(tr("Force Linear and 16x Anisotropic"),
|
m_texture_filtering_combo->addItem(tr("Force Linear and 16x Anisotropic"),
|
||||||
TEXTURE_FILTERING_FORCE_LINEAR_ANISO_16X);
|
TEXTURE_FILTERING_FORCE_LINEAR_ANISO_16X);
|
||||||
|
|
||||||
m_configure_color_correction = new NonDefaultQPushButton(tr("Configure"));
|
m_output_resampling_combo = new ToolTipComboBox();
|
||||||
|
m_output_resampling_combo->addItem(tr("Default"),
|
||||||
|
static_cast<int>(OutputResamplingMode::Default));
|
||||||
|
m_output_resampling_combo->addItem(tr("Bilinear"),
|
||||||
|
static_cast<int>(OutputResamplingMode::Bilinear));
|
||||||
|
m_output_resampling_combo->addItem(tr("Bicubic: B-Spline"),
|
||||||
|
static_cast<int>(OutputResamplingMode::BSpline));
|
||||||
|
m_output_resampling_combo->addItem(tr("Bicubic: Mitchell-Netravali"),
|
||||||
|
static_cast<int>(OutputResamplingMode::MitchellNetravali));
|
||||||
|
m_output_resampling_combo->addItem(tr("Bicubic: Catmull-Rom"),
|
||||||
|
static_cast<int>(OutputResamplingMode::CatmullRom));
|
||||||
|
m_output_resampling_combo->addItem(tr("Sharp Bilinear"),
|
||||||
|
static_cast<int>(OutputResamplingMode::SharpBilinear));
|
||||||
|
m_output_resampling_combo->addItem(tr("Area Sampling"),
|
||||||
|
static_cast<int>(OutputResamplingMode::AreaSampling));
|
||||||
|
|
||||||
|
m_configure_color_correction = new ToolTipPushButton(tr("Configure"));
|
||||||
|
|
||||||
m_pp_effect = new ToolTipComboBox();
|
m_pp_effect = new ToolTipComboBox();
|
||||||
m_configure_pp_effect = new NonDefaultQPushButton(tr("Configure"));
|
m_configure_pp_effect = new NonDefaultQPushButton(tr("Configure"));
|
||||||
|
@ -135,6 +152,10 @@ void EnhancementsWidget::CreateWidgets()
|
||||||
enhancements_layout->addWidget(m_texture_filtering_combo, row, 1, 1, -1);
|
enhancements_layout->addWidget(m_texture_filtering_combo, row, 1, 1, -1);
|
||||||
++row;
|
++row;
|
||||||
|
|
||||||
|
enhancements_layout->addWidget(new QLabel(tr("Output Resampling:")), row, 0);
|
||||||
|
enhancements_layout->addWidget(m_output_resampling_combo, row, 1, 1, -1);
|
||||||
|
++row;
|
||||||
|
|
||||||
enhancements_layout->addWidget(new QLabel(tr("Color Correction:")), row, 0);
|
enhancements_layout->addWidget(new QLabel(tr("Color Correction:")), row, 0);
|
||||||
enhancements_layout->addWidget(m_configure_color_correction, row, 1, 1, -1);
|
enhancements_layout->addWidget(m_configure_color_correction, row, 1, 1, -1);
|
||||||
++row;
|
++row;
|
||||||
|
@ -194,6 +215,8 @@ void EnhancementsWidget::ConnectWidgets()
|
||||||
[this](int) { SaveSettings(); });
|
[this](int) { SaveSettings(); });
|
||||||
connect(m_texture_filtering_combo, qOverload<int>(&QComboBox::currentIndexChanged),
|
connect(m_texture_filtering_combo, qOverload<int>(&QComboBox::currentIndexChanged),
|
||||||
[this](int) { SaveSettings(); });
|
[this](int) { SaveSettings(); });
|
||||||
|
connect(m_output_resampling_combo, qOverload<int>(&QComboBox::currentIndexChanged),
|
||||||
|
[this](int) { SaveSettings(); });
|
||||||
connect(m_pp_effect, qOverload<int>(&QComboBox::currentIndexChanged),
|
connect(m_pp_effect, qOverload<int>(&QComboBox::currentIndexChanged),
|
||||||
[this](int) { SaveSettings(); });
|
[this](int) { SaveSettings(); });
|
||||||
connect(m_3d_mode, qOverload<int>(&QComboBox::currentIndexChanged), [this] {
|
connect(m_3d_mode, qOverload<int>(&QComboBox::currentIndexChanged), [this] {
|
||||||
|
@ -324,6 +347,14 @@ void EnhancementsWidget::LoadSettings()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resampling
|
||||||
|
const OutputResamplingMode output_resampling_mode =
|
||||||
|
Config::Get(Config::GFX_ENHANCE_OUTPUT_RESAMPLING);
|
||||||
|
m_output_resampling_combo->setCurrentIndex(static_cast<int>(output_resampling_mode));
|
||||||
|
|
||||||
|
m_output_resampling_combo->setEnabled(g_Config.backend_info.bSupportsPostProcessing);
|
||||||
|
|
||||||
|
// Color Correction
|
||||||
m_configure_color_correction->setEnabled(g_Config.backend_info.bSupportsPostProcessing);
|
m_configure_color_correction->setEnabled(g_Config.backend_info.bSupportsPostProcessing);
|
||||||
|
|
||||||
// Post Processing Shader
|
// Post Processing Shader
|
||||||
|
@ -412,6 +443,10 @@ void EnhancementsWidget::SaveSettings()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const int output_resampling_selection = m_output_resampling_combo->currentData().toInt();
|
||||||
|
Config::SetBaseOrCurrent(Config::GFX_ENHANCE_OUTPUT_RESAMPLING,
|
||||||
|
static_cast<OutputResamplingMode>(output_resampling_selection));
|
||||||
|
|
||||||
const bool anaglyph = g_Config.stereo_mode == StereoMode::Anaglyph;
|
const bool anaglyph = g_Config.stereo_mode == StereoMode::Anaglyph;
|
||||||
const bool passive = g_Config.stereo_mode == StereoMode::Passive;
|
const bool passive = g_Config.stereo_mode == StereoMode::Passive;
|
||||||
Config::SetBaseOrCurrent(Config::GFX_ENHANCE_POST_SHADER,
|
Config::SetBaseOrCurrent(Config::GFX_ENHANCE_POST_SHADER,
|
||||||
|
@ -454,9 +489,40 @@ void EnhancementsWidget::AddDescriptions()
|
||||||
"scaling filter selected by the game.<br><br>Any option except 'Default' will alter the look "
|
"scaling filter selected by the game.<br><br>Any option except 'Default' will alter the look "
|
||||||
"of the game's textures and might cause issues in a small number of "
|
"of the game's textures and might cause issues in a small number of "
|
||||||
"games.<br><br><dolphin_emphasis>If unsure, select 'Default'.</dolphin_emphasis>");
|
"games.<br><br><dolphin_emphasis>If unsure, select 'Default'.</dolphin_emphasis>");
|
||||||
|
static const char TR_OUTPUT_RESAMPLING_DESCRIPTION[] =
|
||||||
|
QT_TR_NOOP("Affects how the game output is scaled to the window resolution."
|
||||||
|
"<br>The performance mostly depends on the number of samples each method uses."
|
||||||
|
"<br>Compared to SSAA, resampling is useful in case the output window"
|
||||||
|
"<br>resolution isn't a multiplier of the native emulation resolution."
|
||||||
|
|
||||||
|
"<br><br><b>Default</b> - [fastest]"
|
||||||
|
"<br>Internal GPU bilinear sampler which is not gamma corrected."
|
||||||
|
"<br>This setting might be ignored if gamma correction is forced on."
|
||||||
|
|
||||||
|
"<br><br><b>Bilinear</b> - [4 samples]"
|
||||||
|
"<br>Gamma corrected linear interpolation between pixels."
|
||||||
|
|
||||||
|
"<br><br><b>Bicubic</b> - [16 samples]"
|
||||||
|
"<br>Gamma corrected cubic interpolation between pixels."
|
||||||
|
"<br>Good when rescaling between close resolutions. i.e 1080p and 1440p."
|
||||||
|
"<br>Comes in various flavors:"
|
||||||
|
"<br><b>B-Spline</b>: Blurry, but avoids all lobing artifacts"
|
||||||
|
"<br><b>Mitchell-Netravali</b>: Good middle ground between blurry and lobing"
|
||||||
|
"<br><b>Catmull-Rom</b>: Sharper, but can cause lobing artifacts"
|
||||||
|
|
||||||
|
"<br><br><b>Sharp Bilinear</b> - [1-4 samples]"
|
||||||
|
"<br>Similarly to \"Nearest Neighbor\", it maintains a sharp look,"
|
||||||
|
"<br>but also does some blending to avoid shimmering."
|
||||||
|
"<br>Works best with 2D games at low resolutions."
|
||||||
|
|
||||||
|
"<br><br><b>Area Sampling</b> - [up to 324 samples]"
|
||||||
|
"<br>Weights pixels by the percentage of area they occupy. Gamma corrected."
|
||||||
|
"<br>Best for down scaling by more than 2x."
|
||||||
|
|
||||||
|
"<br><br><dolphin_emphasis>If unsure, select 'Default'.</dolphin_emphasis>");
|
||||||
static const char TR_COLOR_CORRECTION_DESCRIPTION[] =
|
static const char TR_COLOR_CORRECTION_DESCRIPTION[] =
|
||||||
QT_TR_NOOP("A group of features to make the colors more accurate,"
|
QT_TR_NOOP("A group of features to make the colors more accurate, matching the color space "
|
||||||
" matching the color space Wii and GC games were meant for.");
|
"Wii and GC games were meant for.");
|
||||||
static const char TR_POSTPROCESSING_DESCRIPTION[] =
|
static const char TR_POSTPROCESSING_DESCRIPTION[] =
|
||||||
QT_TR_NOOP("Applies a post-processing effect after rendering a frame.<br><br "
|
QT_TR_NOOP("Applies a post-processing effect after rendering a frame.<br><br "
|
||||||
"/><dolphin_emphasis>If unsure, select (off).</dolphin_emphasis>");
|
"/><dolphin_emphasis>If unsure, select (off).</dolphin_emphasis>");
|
||||||
|
@ -536,7 +602,11 @@ void EnhancementsWidget::AddDescriptions()
|
||||||
m_texture_filtering_combo->SetTitle(tr("Texture Filtering"));
|
m_texture_filtering_combo->SetTitle(tr("Texture Filtering"));
|
||||||
m_texture_filtering_combo->SetDescription(tr(TR_FORCE_TEXTURE_FILTERING_DESCRIPTION));
|
m_texture_filtering_combo->SetDescription(tr(TR_FORCE_TEXTURE_FILTERING_DESCRIPTION));
|
||||||
|
|
||||||
m_configure_color_correction->setToolTip(tr(TR_COLOR_CORRECTION_DESCRIPTION));
|
m_output_resampling_combo->SetTitle(tr("Output Resampling"));
|
||||||
|
m_output_resampling_combo->SetDescription(tr(TR_OUTPUT_RESAMPLING_DESCRIPTION));
|
||||||
|
|
||||||
|
m_configure_color_correction->SetTitle(tr("Color Correction"));
|
||||||
|
m_configure_color_correction->SetDescription(tr(TR_COLOR_CORRECTION_DESCRIPTION));
|
||||||
|
|
||||||
m_pp_effect->SetTitle(tr("Post-Processing Effect"));
|
m_pp_effect->SetTitle(tr("Post-Processing Effect"));
|
||||||
m_pp_effect->SetDescription(tr(TR_POSTPROCESSING_DESCRIPTION));
|
m_pp_effect->SetDescription(tr(TR_POSTPROCESSING_DESCRIPTION));
|
||||||
|
|
|
@ -16,6 +16,7 @@ class QComboBox;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
class QSlider;
|
class QSlider;
|
||||||
class ToolTipComboBox;
|
class ToolTipComboBox;
|
||||||
|
class ToolTipPushButton;
|
||||||
|
|
||||||
class EnhancementsWidget final : public QWidget
|
class EnhancementsWidget final : public QWidget
|
||||||
{
|
{
|
||||||
|
@ -38,8 +39,9 @@ private:
|
||||||
ConfigChoice* m_ir_combo;
|
ConfigChoice* m_ir_combo;
|
||||||
ToolTipComboBox* m_aa_combo;
|
ToolTipComboBox* m_aa_combo;
|
||||||
ToolTipComboBox* m_texture_filtering_combo;
|
ToolTipComboBox* m_texture_filtering_combo;
|
||||||
|
ToolTipComboBox* m_output_resampling_combo;
|
||||||
ToolTipComboBox* m_pp_effect;
|
ToolTipComboBox* m_pp_effect;
|
||||||
QPushButton* m_configure_color_correction;
|
ToolTipPushButton* m_configure_color_correction;
|
||||||
QPushButton* m_configure_pp_effect;
|
QPushButton* m_configure_pp_effect;
|
||||||
ConfigBool* m_scaled_efb_copy;
|
ConfigBool* m_scaled_efb_copy;
|
||||||
ConfigBool* m_per_pixel_lighting;
|
ConfigBool* m_per_pixel_lighting;
|
||||||
|
|
|
@ -192,7 +192,7 @@ void GraphicsModListWidget::OnModChanged(std::optional<std::string> absolute_pat
|
||||||
|
|
||||||
if (!absolute_path)
|
if (!absolute_path)
|
||||||
{
|
{
|
||||||
m_selected_mod_name->setText(QStringLiteral("No graphics mod selected"));
|
m_selected_mod_name->setText(tr("No graphics mod selected"));
|
||||||
m_selected_mod_name->setAlignment(Qt::AlignCenter);
|
m_selected_mod_name->setAlignment(Qt::AlignCenter);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,10 +152,8 @@ void LogWidget::CreateWidgets()
|
||||||
m_log_text->setUndoRedoEnabled(false);
|
m_log_text->setUndoRedoEnabled(false);
|
||||||
m_log_text->setMaximumBlockCount(MAX_LOG_LINES);
|
m_log_text->setMaximumBlockCount(MAX_LOG_LINES);
|
||||||
|
|
||||||
QPalette palette = m_log_text->palette();
|
m_log_text->setStyleSheet(
|
||||||
palette.setColor(QPalette::Base, Qt::black);
|
QStringLiteral("QPlainTextEdit { background-color: black; color: white; }"));
|
||||||
palette.setColor(QPalette::Text, Qt::white);
|
|
||||||
m_log_text->setPalette(palette);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogWidget::ConnectWidgets()
|
void LogWidget::ConnectWidgets()
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#include "Core/HW/SystemTimers.h"
|
#include "Core/HW/SystemTimers.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
|
|
||||||
|
#include "DolphinQt/Config/ConfigControls/ConfigBool.h"
|
||||||
|
#include "DolphinQt/QtUtils/SignalBlocking.h"
|
||||||
#include "DolphinQt/Settings.h"
|
#include "DolphinQt/Settings.h"
|
||||||
|
|
||||||
static const std::map<PowerPC::CPUCore, const char*> CPU_CORE_NAMES = {
|
static const std::map<PowerPC::CPUCore, const char*> CPU_CORE_NAMES = {
|
||||||
|
@ -63,21 +65,25 @@ void AdvancedPane::CreateLayout()
|
||||||
m_cpu_emulation_engine_combobox->addItem(tr(CPU_CORE_NAMES.at(cpu_core)));
|
m_cpu_emulation_engine_combobox->addItem(tr(CPU_CORE_NAMES.at(cpu_core)));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_enable_mmu_checkbox = new QCheckBox(tr("Enable MMU"));
|
m_enable_mmu_checkbox = new ConfigBool(tr("Enable MMU"), Config::MAIN_MMU);
|
||||||
m_enable_mmu_checkbox->setToolTip(tr(
|
m_enable_mmu_checkbox->SetDescription(
|
||||||
"Enables the Memory Management Unit, needed for some games. (ON = Compatible, OFF = Fast)"));
|
tr("Enables the Memory Management Unit, needed for some games. (ON = Compatible, OFF = "
|
||||||
|
"Fast)<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>"));
|
||||||
cpu_options_group_layout->addWidget(m_enable_mmu_checkbox);
|
cpu_options_group_layout->addWidget(m_enable_mmu_checkbox);
|
||||||
|
|
||||||
m_pause_on_panic_checkbox = new QCheckBox(tr("Pause on Panic"));
|
m_pause_on_panic_checkbox = new ConfigBool(tr("Pause on Panic"), Config::MAIN_PAUSE_ON_PANIC);
|
||||||
m_pause_on_panic_checkbox->setToolTip(
|
m_pause_on_panic_checkbox->SetDescription(
|
||||||
tr("Pauses the emulation if a Read/Write or Unknown Instruction panic occurs.\nEnabling will "
|
tr("Pauses the emulation if a Read/Write or Unknown Instruction panic occurs.<br>Enabling "
|
||||||
"affect performance.\nThe performance impact is the same as having Enable MMU on."));
|
"will affect performance.<br>The performance impact is the same as having Enable MMU "
|
||||||
|
"on.<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>"));
|
||||||
cpu_options_group_layout->addWidget(m_pause_on_panic_checkbox);
|
cpu_options_group_layout->addWidget(m_pause_on_panic_checkbox);
|
||||||
|
|
||||||
m_accurate_cpu_cache_checkbox = new QCheckBox(tr("Enable Write-Back Cache (slow)"));
|
m_accurate_cpu_cache_checkbox =
|
||||||
m_accurate_cpu_cache_checkbox->setToolTip(
|
new ConfigBool(tr("Enable Write-Back Cache (slow)"), Config::MAIN_ACCURATE_CPU_CACHE);
|
||||||
tr("Enables emulation of the CPU write-back cache.\nEnabling will have a significant impact "
|
m_accurate_cpu_cache_checkbox->SetDescription(
|
||||||
"on performance.\nThis should be left disabled unless absolutely needed."));
|
tr("Enables emulation of the CPU write-back cache.<br>Enabling will have a significant "
|
||||||
|
"impact on performance.<br>This should be left disabled unless absolutely "
|
||||||
|
"needed.<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>"));
|
||||||
cpu_options_group_layout->addWidget(m_accurate_cpu_cache_checkbox);
|
cpu_options_group_layout->addWidget(m_accurate_cpu_cache_checkbox);
|
||||||
|
|
||||||
auto* clock_override = new QGroupBox(tr("Clock Override"));
|
auto* clock_override = new QGroupBox(tr("Clock Override"));
|
||||||
|
@ -184,21 +190,13 @@ void AdvancedPane::CreateLayout()
|
||||||
|
|
||||||
void AdvancedPane::ConnectLayout()
|
void AdvancedPane::ConnectLayout()
|
||||||
{
|
{
|
||||||
connect(m_cpu_emulation_engine_combobox,
|
connect(m_cpu_emulation_engine_combobox, qOverload<int>(&QComboBox::currentIndexChanged),
|
||||||
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [](int index) {
|
[](int index) {
|
||||||
Config::SetBaseOrCurrent(Config::MAIN_CPU_CORE, PowerPC::AvailableCPUCores()[index]);
|
const auto cpu_cores = PowerPC::AvailableCPUCores();
|
||||||
|
if (index >= 0 && static_cast<size_t>(index) < cpu_cores.size())
|
||||||
|
Config::SetBaseOrCurrent(Config::MAIN_CPU_CORE, cpu_cores[index]);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_enable_mmu_checkbox, &QCheckBox::toggled, this,
|
|
||||||
[](bool checked) { Config::SetBaseOrCurrent(Config::MAIN_MMU, checked); });
|
|
||||||
|
|
||||||
connect(m_pause_on_panic_checkbox, &QCheckBox::toggled, this,
|
|
||||||
[](bool checked) { Config::SetBaseOrCurrent(Config::MAIN_PAUSE_ON_PANIC, checked); });
|
|
||||||
|
|
||||||
connect(m_accurate_cpu_cache_checkbox, &QCheckBox::toggled, this,
|
|
||||||
[](bool checked) { Config::SetBaseOrCurrent(Config::MAIN_ACCURATE_CPU_CACHE, checked); });
|
|
||||||
|
|
||||||
m_cpu_clock_override_checkbox->setChecked(Config::Get(Config::MAIN_OVERCLOCK_ENABLE));
|
|
||||||
connect(m_cpu_clock_override_checkbox, &QCheckBox::toggled, [this](bool enable_clock_override) {
|
connect(m_cpu_clock_override_checkbox, &QCheckBox::toggled, [this](bool enable_clock_override) {
|
||||||
Config::SetBaseOrCurrent(Config::MAIN_OVERCLOCK_ENABLE, enable_clock_override);
|
Config::SetBaseOrCurrent(Config::MAIN_OVERCLOCK_ENABLE, enable_clock_override);
|
||||||
Update();
|
Update();
|
||||||
|
@ -211,7 +209,6 @@ void AdvancedPane::ConnectLayout()
|
||||||
Update();
|
Update();
|
||||||
});
|
});
|
||||||
|
|
||||||
m_ram_override_checkbox->setChecked(Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE));
|
|
||||||
connect(m_ram_override_checkbox, &QCheckBox::toggled, [this](bool enable_ram_override) {
|
connect(m_ram_override_checkbox, &QCheckBox::toggled, [this](bool enable_ram_override) {
|
||||||
Config::SetBaseOrCurrent(Config::MAIN_RAM_OVERRIDE_ENABLE, enable_ram_override);
|
Config::SetBaseOrCurrent(Config::MAIN_RAM_OVERRIDE_ENABLE, enable_ram_override);
|
||||||
Update();
|
Update();
|
||||||
|
@ -229,15 +226,11 @@ void AdvancedPane::ConnectLayout()
|
||||||
Update();
|
Update();
|
||||||
});
|
});
|
||||||
|
|
||||||
m_custom_rtc_checkbox->setChecked(Config::Get(Config::MAIN_CUSTOM_RTC_ENABLE));
|
|
||||||
connect(m_custom_rtc_checkbox, &QCheckBox::toggled, [this](bool enable_custom_rtc) {
|
connect(m_custom_rtc_checkbox, &QCheckBox::toggled, [this](bool enable_custom_rtc) {
|
||||||
Config::SetBaseOrCurrent(Config::MAIN_CUSTOM_RTC_ENABLE, enable_custom_rtc);
|
Config::SetBaseOrCurrent(Config::MAIN_CUSTOM_RTC_ENABLE, enable_custom_rtc);
|
||||||
Update();
|
Update();
|
||||||
});
|
});
|
||||||
|
|
||||||
QDateTime initial_date_time;
|
|
||||||
initial_date_time.setSecsSinceEpoch(Config::Get(Config::MAIN_CUSTOM_RTC_VALUE));
|
|
||||||
m_custom_rtc_datetime->setDateTime(initial_date_time);
|
|
||||||
connect(m_custom_rtc_datetime, &QDateTimeEdit::dateTimeChanged, [this](QDateTime date_time) {
|
connect(m_custom_rtc_datetime, &QDateTimeEdit::dateTimeChanged, [this](QDateTime date_time) {
|
||||||
Config::SetBaseOrCurrent(Config::MAIN_CUSTOM_RTC_VALUE,
|
Config::SetBaseOrCurrent(Config::MAIN_CUSTOM_RTC_VALUE,
|
||||||
static_cast<u32>(date_time.toSecsSinceEpoch()));
|
static_cast<u32>(date_time.toSecsSinceEpoch()));
|
||||||
|
@ -252,7 +245,7 @@ void AdvancedPane::Update()
|
||||||
const bool enable_ram_override_widgets = Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE);
|
const bool enable_ram_override_widgets = Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE);
|
||||||
const bool enable_custom_rtc_widgets = Config::Get(Config::MAIN_CUSTOM_RTC_ENABLE) && !running;
|
const bool enable_custom_rtc_widgets = Config::Get(Config::MAIN_CUSTOM_RTC_ENABLE) && !running;
|
||||||
|
|
||||||
const std::vector<PowerPC::CPUCore>& available_cpu_cores = PowerPC::AvailableCPUCores();
|
const auto available_cpu_cores = PowerPC::AvailableCPUCores();
|
||||||
const auto cpu_core = Config::Get(Config::MAIN_CPU_CORE);
|
const auto cpu_core = Config::Get(Config::MAIN_CPU_CORE);
|
||||||
for (size_t i = 0; i < available_cpu_cores.size(); ++i)
|
for (size_t i = 0; i < available_cpu_cores.size(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -260,21 +253,19 @@ void AdvancedPane::Update()
|
||||||
m_cpu_emulation_engine_combobox->setCurrentIndex(int(i));
|
m_cpu_emulation_engine_combobox->setCurrentIndex(int(i));
|
||||||
}
|
}
|
||||||
m_cpu_emulation_engine_combobox->setEnabled(!running);
|
m_cpu_emulation_engine_combobox->setEnabled(!running);
|
||||||
|
|
||||||
m_enable_mmu_checkbox->setChecked(Config::Get(Config::MAIN_MMU));
|
|
||||||
m_enable_mmu_checkbox->setEnabled(!running);
|
m_enable_mmu_checkbox->setEnabled(!running);
|
||||||
|
|
||||||
m_pause_on_panic_checkbox->setChecked(Config::Get(Config::MAIN_PAUSE_ON_PANIC));
|
|
||||||
m_pause_on_panic_checkbox->setEnabled(!running);
|
m_pause_on_panic_checkbox->setEnabled(!running);
|
||||||
|
|
||||||
m_accurate_cpu_cache_checkbox->setChecked(Config::Get(Config::MAIN_ACCURATE_CPU_CACHE));
|
|
||||||
m_accurate_cpu_cache_checkbox->setEnabled(!running);
|
m_accurate_cpu_cache_checkbox->setEnabled(!running);
|
||||||
|
|
||||||
|
{
|
||||||
QFont bf = font();
|
QFont bf = font();
|
||||||
bf.setBold(Config::GetActiveLayerForConfig(Config::MAIN_OVERCLOCK_ENABLE) !=
|
bf.setBold(Config::GetActiveLayerForConfig(Config::MAIN_OVERCLOCK_ENABLE) !=
|
||||||
Config::LayerType::Base);
|
Config::LayerType::Base);
|
||||||
|
|
||||||
|
const QSignalBlocker blocker(m_cpu_clock_override_checkbox);
|
||||||
m_cpu_clock_override_checkbox->setFont(bf);
|
m_cpu_clock_override_checkbox->setFont(bf);
|
||||||
m_cpu_clock_override_checkbox->setChecked(enable_cpu_clock_override_widgets);
|
m_cpu_clock_override_checkbox->setChecked(enable_cpu_clock_override_widgets);
|
||||||
|
}
|
||||||
|
|
||||||
m_cpu_clock_override_slider->setEnabled(enable_cpu_clock_override_widgets);
|
m_cpu_clock_override_slider->setEnabled(enable_cpu_clock_override_widgets);
|
||||||
m_cpu_clock_override_slider_label->setEnabled(enable_cpu_clock_override_widgets);
|
m_cpu_clock_override_slider_label->setEnabled(enable_cpu_clock_override_widgets);
|
||||||
|
@ -293,6 +284,7 @@ void AdvancedPane::Update()
|
||||||
}());
|
}());
|
||||||
|
|
||||||
m_ram_override_checkbox->setEnabled(!running);
|
m_ram_override_checkbox->setEnabled(!running);
|
||||||
|
SignalBlocking(m_ram_override_checkbox)->setChecked(enable_ram_override_widgets);
|
||||||
|
|
||||||
m_mem1_override_slider->setEnabled(enable_ram_override_widgets && !running);
|
m_mem1_override_slider->setEnabled(enable_ram_override_widgets && !running);
|
||||||
m_mem1_override_slider_label->setEnabled(enable_ram_override_widgets && !running);
|
m_mem1_override_slider_label->setEnabled(enable_ram_override_widgets && !running);
|
||||||
|
@ -323,5 +315,10 @@ void AdvancedPane::Update()
|
||||||
}());
|
}());
|
||||||
|
|
||||||
m_custom_rtc_checkbox->setEnabled(!running);
|
m_custom_rtc_checkbox->setEnabled(!running);
|
||||||
|
SignalBlocking(m_custom_rtc_checkbox)->setChecked(Config::Get(Config::MAIN_CUSTOM_RTC_ENABLE));
|
||||||
|
|
||||||
|
QDateTime initial_date_time;
|
||||||
|
initial_date_time.setSecsSinceEpoch(Config::Get(Config::MAIN_CUSTOM_RTC_VALUE));
|
||||||
m_custom_rtc_datetime->setEnabled(enable_custom_rtc_widgets);
|
m_custom_rtc_datetime->setEnabled(enable_custom_rtc_widgets);
|
||||||
|
SignalBlocking(m_custom_rtc_datetime)->setDateTime(initial_date_time);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
class ConfigBool;
|
||||||
class QCheckBox;
|
class QCheckBox;
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
|
@ -31,9 +32,9 @@ private:
|
||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
QComboBox* m_cpu_emulation_engine_combobox;
|
QComboBox* m_cpu_emulation_engine_combobox;
|
||||||
QCheckBox* m_enable_mmu_checkbox;
|
ConfigBool* m_enable_mmu_checkbox;
|
||||||
QCheckBox* m_pause_on_panic_checkbox;
|
ConfigBool* m_pause_on_panic_checkbox;
|
||||||
QCheckBox* m_accurate_cpu_cache_checkbox;
|
ConfigBool* m_accurate_cpu_cache_checkbox;
|
||||||
QCheckBox* m_cpu_clock_override_checkbox;
|
QCheckBox* m_cpu_clock_override_checkbox;
|
||||||
QSlider* m_cpu_clock_override_slider;
|
QSlider* m_cpu_clock_override_slider;
|
||||||
QLabel* m_cpu_clock_override_slider_label;
|
QLabel* m_cpu_clock_override_slider_label;
|
||||||
|
|
|
@ -128,14 +128,16 @@ void USBDeviceAddToWhitelistDialog::AddUSBDeviceToWhitelist()
|
||||||
const std::string pid_string(StripWhitespace(device_pid_textbox->text().toStdString()));
|
const std::string pid_string(StripWhitespace(device_pid_textbox->text().toStdString()));
|
||||||
if (!IsValidUSBIDString(vid_string))
|
if (!IsValidUSBIDString(vid_string))
|
||||||
{
|
{
|
||||||
|
ModalMessageBox::critical(this, tr("USB Whitelist Error"),
|
||||||
// i18n: Here, VID means Vendor ID (for a USB device).
|
// i18n: Here, VID means Vendor ID (for a USB device).
|
||||||
ModalMessageBox::critical(this, tr("USB Whitelist Error"), tr("The entered VID is invalid."));
|
tr("The entered VID is invalid."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!IsValidUSBIDString(pid_string))
|
if (!IsValidUSBIDString(pid_string))
|
||||||
{
|
{
|
||||||
|
ModalMessageBox::critical(this, tr("USB Whitelist Error"),
|
||||||
// i18n: Here, PID means Product ID (for a USB device).
|
// i18n: Here, PID means Product ID (for a USB device).
|
||||||
ModalMessageBox::critical(this, tr("USB Whitelist Error"), tr("The entered PID is invalid."));
|
tr("The entered PID is invalid."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ TASInputWindow::TASInputWindow(QWidget* parent) : QDialog(parent)
|
||||||
|
|
||||||
QGridLayout* settings_layout = new QGridLayout;
|
QGridLayout* settings_layout = new QGridLayout;
|
||||||
|
|
||||||
m_use_controller = new QCheckBox(QStringLiteral("Enable Controller Inpu&t"));
|
m_use_controller = new QCheckBox(tr("Enable Controller Inpu&t"));
|
||||||
m_use_controller->setToolTip(tr("Warning: Analog inputs may reset to controller values at "
|
m_use_controller->setToolTip(tr("Warning: Analog inputs may reset to controller values at "
|
||||||
"random. In some cases this can be fixed by adding a deadzone."));
|
"random. In some cases this can be fixed by adding a deadzone."));
|
||||||
settings_layout->addWidget(m_use_controller, 0, 0, 1, 2);
|
settings_layout->addWidget(m_use_controller, 0, 0, 1, 2);
|
||||||
|
|
|
@ -203,11 +203,14 @@ bool InputConfig::IsControllerControlledByGamepadDevice(int index) const
|
||||||
|
|
||||||
const auto& controller = m_controllers.at(index).get()->GetDefaultDevice();
|
const auto& controller = m_controllers.at(index).get()->GetDefaultDevice();
|
||||||
|
|
||||||
|
// By default on Android, no device is selected
|
||||||
|
if (controller.source == "")
|
||||||
|
return false;
|
||||||
|
|
||||||
// Filter out anything which obviously not a gamepad
|
// Filter out anything which obviously not a gamepad
|
||||||
return !((controller.source == "Quartz") // OSX Quartz Keyboard/Mouse
|
return !((controller.source == "Quartz") // OSX Quartz Keyboard/Mouse
|
||||||
|| (controller.source == "XInput2") // Linux and BSD Keyboard/Mouse
|
|| (controller.source == "XInput2") // Linux and BSD Keyboard/Mouse
|
||||||
|| (controller.source == "Android" &&
|
|| (controller.source == "Android" && controller.cid <= 0) // Android non-gamepad device
|
||||||
controller.name == "Touchscreen") // Android Touchscreen
|
|
||||||
|| (controller.source == "DInput" &&
|
|| (controller.source == "DInput" &&
|
||||||
controller.name == "Keyboard Mouse")); // Windows Keyboard/Mouse
|
controller.name == "Keyboard Mouse")); // Windows Keyboard/Mouse
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,14 +20,7 @@ struct PixelShaderData;
|
||||||
class CustomAssetLibrary
|
class CustomAssetLibrary
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// TODO: this should be std::chrono::system_clock::time_point to
|
using TimeType = std::chrono::system_clock::time_point;
|
||||||
// support any type of loader where the time isn't from the filesystem
|
|
||||||
// but there's no way to convert filesystem times to system times
|
|
||||||
// without 'clock_cast', once our builders catch up
|
|
||||||
// to support 'clock_cast' we should update this
|
|
||||||
// For now, it's fine as a filesystem library is all that is
|
|
||||||
// available
|
|
||||||
using TimeType = std::filesystem::file_time_type;
|
|
||||||
|
|
||||||
// The AssetID is a unique identifier for a particular asset
|
// The AssetID is a unique identifier for a particular asset
|
||||||
using AssetID = std::string;
|
using AssetID = std::string;
|
||||||
|
|
|
@ -17,6 +17,20 @@ namespace VideoCommon
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
std::chrono::system_clock::time_point FileTimeToSysTime(std::filesystem::file_time_type file_time)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
return std::chrono::clock_cast<std::chrono::system_clock>(file_time);
|
||||||
|
#else
|
||||||
|
// Note: all compilers should switch to chrono::clock_cast
|
||||||
|
// once it is available for use
|
||||||
|
const auto system_time_now = std::chrono::system_clock::now();
|
||||||
|
const auto file_time_now = decltype(file_time)::clock::now();
|
||||||
|
return std::chrono::time_point_cast<std::chrono::system_clock::duration>(
|
||||||
|
file_time - file_time_now + system_time_now);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t GetAssetSize(const CustomTextureData& data)
|
std::size_t GetAssetSize(const CustomTextureData& data)
|
||||||
{
|
{
|
||||||
std::size_t total = 0;
|
std::size_t total = 0;
|
||||||
|
@ -42,8 +56,9 @@ DirectFilesystemAssetLibrary::GetLastAssetWriteTime(const AssetID& asset_id) con
|
||||||
const auto tp = std::filesystem::last_write_time(value, ec);
|
const auto tp = std::filesystem::last_write_time(value, ec);
|
||||||
if (ec)
|
if (ec)
|
||||||
continue;
|
continue;
|
||||||
if (tp > max_entry)
|
auto tp_sys = FileTimeToSysTime(tp);
|
||||||
max_entry = tp;
|
if (tp_sys > max_entry)
|
||||||
|
max_entry = tp_sys;
|
||||||
}
|
}
|
||||||
return max_entry;
|
return max_entry;
|
||||||
}
|
}
|
||||||
|
@ -235,7 +250,7 @@ CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadTexture(const Ass
|
||||||
if (!LoadMips(asset_path, data))
|
if (!LoadMips(asset_path, data))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
return LoadInfo{GetAssetSize(*data), last_loaded_time};
|
return LoadInfo{GetAssetSize(*data), FileTimeToSysTime(last_loaded_time)};
|
||||||
}
|
}
|
||||||
else if (ext == ".png")
|
else if (ext == ".png")
|
||||||
{
|
{
|
||||||
|
@ -252,7 +267,7 @@ CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadTexture(const Ass
|
||||||
if (!LoadMips(asset_path, data))
|
if (!LoadMips(asset_path, data))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
return LoadInfo{GetAssetSize(*data), last_loaded_time};
|
return LoadInfo{GetAssetSize(*data), FileTimeToSysTime(last_loaded_time)};
|
||||||
}
|
}
|
||||||
|
|
||||||
ERROR_LOG_FMT(VIDEO, "Asset '{}' error - extension '{}' unknown!", asset_id, ext);
|
ERROR_LOG_FMT(VIDEO, "Asset '{}' error - extension '{}' unknown!", asset_id, ext);
|
||||||
|
|
|
@ -64,6 +64,8 @@ add_library(videocommon
|
||||||
GeometryShaderManager.h
|
GeometryShaderManager.h
|
||||||
GraphicsModSystem/Config/GraphicsMod.cpp
|
GraphicsModSystem/Config/GraphicsMod.cpp
|
||||||
GraphicsModSystem/Config/GraphicsMod.h
|
GraphicsModSystem/Config/GraphicsMod.h
|
||||||
|
GraphicsModSystem/Config/GraphicsModAsset.cpp
|
||||||
|
GraphicsModSystem/Config/GraphicsModAsset.h
|
||||||
GraphicsModSystem/Config/GraphicsModFeature.cpp
|
GraphicsModSystem/Config/GraphicsModFeature.cpp
|
||||||
GraphicsModSystem/Config/GraphicsModFeature.h
|
GraphicsModSystem/Config/GraphicsModFeature.h
|
||||||
GraphicsModSystem/Config/GraphicsModGroup.cpp
|
GraphicsModSystem/Config/GraphicsModGroup.cpp
|
||||||
|
@ -73,6 +75,8 @@ add_library(videocommon
|
||||||
GraphicsModSystem/Config/GraphicsTargetGroup.cpp
|
GraphicsModSystem/Config/GraphicsTargetGroup.cpp
|
||||||
GraphicsModSystem/Config/GraphicsTargetGroup.h
|
GraphicsModSystem/Config/GraphicsTargetGroup.h
|
||||||
GraphicsModSystem/Constants.h
|
GraphicsModSystem/Constants.h
|
||||||
|
GraphicsModSystem/Runtime/Actions/CustomPipelineAction.cpp
|
||||||
|
GraphicsModSystem/Runtime/Actions/CustomPipelineAction.h
|
||||||
GraphicsModSystem/Runtime/Actions/MoveAction.cpp
|
GraphicsModSystem/Runtime/Actions/MoveAction.cpp
|
||||||
GraphicsModSystem/Runtime/Actions/MoveAction.h
|
GraphicsModSystem/Runtime/Actions/MoveAction.h
|
||||||
GraphicsModSystem/Runtime/Actions/PrintAction.cpp
|
GraphicsModSystem/Runtime/Actions/PrintAction.cpp
|
||||||
|
@ -81,6 +85,8 @@ add_library(videocommon
|
||||||
GraphicsModSystem/Runtime/Actions/ScaleAction.h
|
GraphicsModSystem/Runtime/Actions/ScaleAction.h
|
||||||
GraphicsModSystem/Runtime/Actions/SkipAction.cpp
|
GraphicsModSystem/Runtime/Actions/SkipAction.cpp
|
||||||
GraphicsModSystem/Runtime/Actions/SkipAction.h
|
GraphicsModSystem/Runtime/Actions/SkipAction.h
|
||||||
|
GraphicsModSystem/Runtime/CustomShaderCache.cpp
|
||||||
|
GraphicsModSystem/Runtime/CustomShaderCache.h
|
||||||
GraphicsModSystem/Runtime/FBInfo.cpp
|
GraphicsModSystem/Runtime/FBInfo.cpp
|
||||||
GraphicsModSystem/Runtime/FBInfo.h
|
GraphicsModSystem/Runtime/FBInfo.h
|
||||||
GraphicsModSystem/Runtime/GraphicsModAction.h
|
GraphicsModSystem/Runtime/GraphicsModAction.h
|
||||||
|
|
|
@ -58,6 +58,8 @@ struct alignas(16) PixelShaderConstants
|
||||||
// For shader_framebuffer_fetch logic ops:
|
// For shader_framebuffer_fetch logic ops:
|
||||||
u32 logic_op_enable; // bool
|
u32 logic_op_enable; // bool
|
||||||
LogicOp logic_op_mode;
|
LogicOp logic_op_mode;
|
||||||
|
// For custom shaders...
|
||||||
|
u32 time_ms;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct alignas(16) VertexShaderConstants
|
struct alignas(16) VertexShaderConstants
|
||||||
|
|
|
@ -178,6 +178,27 @@ bool GraphicsModConfig::DeserializeFromConfig(const picojson::value& value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto& assets = value.get("assets");
|
||||||
|
if (assets.is<picojson::array>())
|
||||||
|
{
|
||||||
|
for (const auto& asset_val : assets.get<picojson::array>())
|
||||||
|
{
|
||||||
|
if (!asset_val.is<picojson::object>())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(
|
||||||
|
VIDEO, "Failed to load mod configuration file, specified asset is not a json object");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
GraphicsModAssetConfig asset;
|
||||||
|
if (!asset.DeserializeFromConfig(asset_val.get<picojson::object>()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_assets.push_back(std::move(asset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include <picojson.h>
|
#include <picojson.h>
|
||||||
|
|
||||||
|
#include "VideoCommon/GraphicsModSystem/Config/GraphicsModAsset.h"
|
||||||
#include "VideoCommon/GraphicsModSystem/Config/GraphicsModFeature.h"
|
#include "VideoCommon/GraphicsModSystem/Config/GraphicsModFeature.h"
|
||||||
#include "VideoCommon/GraphicsModSystem/Config/GraphicsTargetGroup.h"
|
#include "VideoCommon/GraphicsModSystem/Config/GraphicsTargetGroup.h"
|
||||||
|
|
||||||
|
@ -30,6 +31,7 @@ struct GraphicsModConfig
|
||||||
|
|
||||||
std::vector<GraphicsTargetGroupConfig> m_groups;
|
std::vector<GraphicsTargetGroupConfig> m_groups;
|
||||||
std::vector<GraphicsModFeatureConfig> m_features;
|
std::vector<GraphicsModFeatureConfig> m_features;
|
||||||
|
std::vector<GraphicsModAssetConfig> m_assets;
|
||||||
|
|
||||||
static std::optional<GraphicsModConfig> Create(const std::string& file, Source source);
|
static std::optional<GraphicsModConfig> Create(const std::string& file, Source source);
|
||||||
static std::optional<GraphicsModConfig> Create(const picojson::object* obj);
|
static std::optional<GraphicsModConfig> Create(const picojson::object* obj);
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright 2023 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "VideoCommon/GraphicsModSystem/Config/GraphicsModAsset.h"
|
||||||
|
|
||||||
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
|
bool GraphicsModAssetConfig::DeserializeFromConfig(const picojson::object& obj)
|
||||||
|
{
|
||||||
|
auto name_iter = obj.find("name");
|
||||||
|
if (name_iter == obj.end())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO, "Failed to load mod configuration file, specified asset has no name");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!name_iter->second.is<std::string>())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO, "Failed to load mod configuration file, specified asset has a name "
|
||||||
|
"that is not a string");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_name = name_iter->second.to_str();
|
||||||
|
|
||||||
|
auto data_iter = obj.find("data");
|
||||||
|
if (data_iter == obj.end())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO, "Failed to load mod configuration file, specified asset '{}' has no data",
|
||||||
|
m_name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!data_iter->second.is<picojson::object>())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO,
|
||||||
|
"Failed to load mod configuration file, specified asset '{}' has data "
|
||||||
|
"that is not an object",
|
||||||
|
m_name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const auto& [key, value] : data_iter->second.get<picojson::object>())
|
||||||
|
{
|
||||||
|
if (!value.is<std::string>())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO,
|
||||||
|
"Failed to load mod configuration file, specified asset '{}' has data "
|
||||||
|
"with a value for key '{}' that is not a string",
|
||||||
|
m_name, key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_map[key] = value.to_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright 2023 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <picojson.h>
|
||||||
|
|
||||||
|
#include "VideoCommon/Assets/DirectFilesystemAssetLibrary.h"
|
||||||
|
|
||||||
|
struct GraphicsModAssetConfig
|
||||||
|
{
|
||||||
|
std::string m_name;
|
||||||
|
VideoCommon::DirectFilesystemAssetLibrary::AssetMap m_map;
|
||||||
|
|
||||||
|
bool DeserializeFromConfig(const picojson::object& obj);
|
||||||
|
};
|
|
@ -0,0 +1,449 @@
|
||||||
|
// Copyright 2022 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include "Common/FileUtil.h"
|
||||||
|
#include "Common/Logging/Log.h"
|
||||||
|
#include "Common/StringUtil.h"
|
||||||
|
#include "Core/System.h"
|
||||||
|
|
||||||
|
#include "VideoCommon/AbstractGfx.h"
|
||||||
|
#include "VideoCommon/Assets/CustomAssetLoader.h"
|
||||||
|
#include "VideoCommon/Assets/DirectFilesystemAssetLibrary.h"
|
||||||
|
#include "VideoCommon/ShaderGenCommon.h"
|
||||||
|
#include "VideoCommon/TextureCacheBase.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool IsQualifier(std::string_view value)
|
||||||
|
{
|
||||||
|
static std::array<std::string_view, 7> qualifiers = {"attribute", "const", "highp", "lowp",
|
||||||
|
"mediump", "uniform", "varying"};
|
||||||
|
return std::find(qualifiers.begin(), qualifiers.end(), value) != qualifiers.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsBuiltInMacro(std::string_view value)
|
||||||
|
{
|
||||||
|
static std::array<std::string_view, 5> built_in = {"__LINE__", "__FILE__", "__VERSION__",
|
||||||
|
"GL_core_profile", "GL_compatibility_profile"};
|
||||||
|
return std::find(built_in.begin(), built_in.end(), value) != built_in.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> GlobalConflicts(std::string_view source)
|
||||||
|
{
|
||||||
|
std::string_view last_identifier = "";
|
||||||
|
std::vector<std::string> global_result;
|
||||||
|
u32 scope = 0;
|
||||||
|
for (u32 i = 0; i < source.size(); i++)
|
||||||
|
{
|
||||||
|
// If we're out of global scope, we don't care
|
||||||
|
// about any of the details
|
||||||
|
if (scope > 0)
|
||||||
|
{
|
||||||
|
if (source[i] == '{')
|
||||||
|
{
|
||||||
|
scope++;
|
||||||
|
}
|
||||||
|
else if (source[i] == '}')
|
||||||
|
{
|
||||||
|
scope--;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto parse_identifier = [&]() {
|
||||||
|
const u32 start = i;
|
||||||
|
for (; i < source.size(); i++)
|
||||||
|
{
|
||||||
|
if (!Common::IsAlpha(source[i]) && source[i] != '_' && !std::isdigit(source[i]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
u32 end = i;
|
||||||
|
i--; // unwind
|
||||||
|
return source.substr(start, end - start);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Common::IsAlpha(source[i]) || source[i] == '_')
|
||||||
|
{
|
||||||
|
const std::string_view identifier = parse_identifier();
|
||||||
|
if (IsQualifier(identifier))
|
||||||
|
continue;
|
||||||
|
if (IsBuiltInMacro(identifier))
|
||||||
|
continue;
|
||||||
|
last_identifier = identifier;
|
||||||
|
}
|
||||||
|
else if (source[i] == '#')
|
||||||
|
{
|
||||||
|
const auto parse_until_end_of_preprocessor = [&]() {
|
||||||
|
bool continue_until_next_newline = false;
|
||||||
|
for (; i < source.size(); i++)
|
||||||
|
{
|
||||||
|
if (source[i] == '\n')
|
||||||
|
{
|
||||||
|
if (continue_until_next_newline)
|
||||||
|
continue_until_next_newline = false;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (source[i] == '\\')
|
||||||
|
{
|
||||||
|
continue_until_next_newline = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
i++;
|
||||||
|
const std::string_view identifier = parse_identifier();
|
||||||
|
if (identifier == "define")
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
// skip whitespace
|
||||||
|
while (source[i] == ' ')
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
global_result.push_back(std::string{parse_identifier()});
|
||||||
|
parse_until_end_of_preprocessor();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parse_until_end_of_preprocessor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (source[i] == '{')
|
||||||
|
{
|
||||||
|
scope++;
|
||||||
|
}
|
||||||
|
else if (source[i] == '(')
|
||||||
|
{
|
||||||
|
// Unlikely the user will be using layouts but...
|
||||||
|
if (last_identifier == "layout")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Since we handle equality, we can assume the identifier
|
||||||
|
// before '(' is a function definition
|
||||||
|
global_result.push_back(std::string{last_identifier});
|
||||||
|
}
|
||||||
|
else if (source[i] == '=')
|
||||||
|
{
|
||||||
|
global_result.push_back(std::string{last_identifier});
|
||||||
|
i++;
|
||||||
|
for (; i < source.size(); i++)
|
||||||
|
{
|
||||||
|
if (source[i] == ';')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (source[i] == '/')
|
||||||
|
{
|
||||||
|
if ((i + 1) >= source.size())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (source[i + 1] == '/')
|
||||||
|
{
|
||||||
|
// Go to end of line...
|
||||||
|
for (; i < source.size(); i++)
|
||||||
|
{
|
||||||
|
if (source[i] == '\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (source[i + 1] == '*')
|
||||||
|
{
|
||||||
|
// Multiline, look for first '*/'
|
||||||
|
for (; i < source.size(); i++)
|
||||||
|
{
|
||||||
|
if (source[i] == '/' && source[i - 1] == '*')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort the conflicts from largest to smallest string
|
||||||
|
// this way we can ensure smaller strings that are a substring
|
||||||
|
// of the larger string are able to be replaced appropriately
|
||||||
|
std::sort(global_result.begin(), global_result.end(),
|
||||||
|
[](const std::string& first, const std::string& second) {
|
||||||
|
return first.size() > second.size();
|
||||||
|
});
|
||||||
|
return global_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteDefines(ShaderCode* out, const std::vector<std::string>& texture_code_names,
|
||||||
|
u32 texture_unit)
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < texture_code_names.size(); i++)
|
||||||
|
{
|
||||||
|
const auto& code_name = texture_code_names[i];
|
||||||
|
out->Write("#define {}_UNIT_{{0}} {}\n", code_name, texture_unit);
|
||||||
|
out->Write(
|
||||||
|
"#define {0}_COORD_{{0}} float3(data.texcoord[data.texmap_to_texcoord_index[{1}]].xy, "
|
||||||
|
"{2})\n",
|
||||||
|
code_name, texture_unit, i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::unique_ptr<CustomPipelineAction>
|
||||||
|
CustomPipelineAction::Create(const picojson::value& json_data,
|
||||||
|
std::shared_ptr<VideoCommon::CustomAssetLibrary> library)
|
||||||
|
{
|
||||||
|
std::vector<CustomPipelineAction::PipelinePassPassDescription> pipeline_passes;
|
||||||
|
|
||||||
|
const auto& passes_json = json_data.get("passes");
|
||||||
|
if (passes_json.is<picojson::array>())
|
||||||
|
{
|
||||||
|
for (const auto& passes_json_val : passes_json.get<picojson::array>())
|
||||||
|
{
|
||||||
|
CustomPipelineAction::PipelinePassPassDescription pipeline_pass;
|
||||||
|
if (!passes_json_val.is<picojson::object>())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO,
|
||||||
|
"Failed to load custom pipeline action, 'passes' has an array value that "
|
||||||
|
"is not an object!");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pass = passes_json_val.get<picojson::object>();
|
||||||
|
if (!pass.contains("pixel_material_asset"))
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO,
|
||||||
|
"Failed to load custom pipeline action, 'passes' value missing required "
|
||||||
|
"field 'pixel_material_asset'");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pixel_material_asset_json = pass["pixel_material_asset"];
|
||||||
|
if (!pixel_material_asset_json.is<std::string>())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO, "Failed to load custom pipeline action, 'passes' field "
|
||||||
|
"'pixel_material_asset' is not a string!");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
pipeline_pass.m_pixel_material_asset = pixel_material_asset_json.to_str();
|
||||||
|
pipeline_passes.push_back(std::move(pipeline_pass));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pipeline_passes.empty())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO, "Failed to load custom pipeline action, must specify at least one pass");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pipeline_passes.size() > 1)
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(
|
||||||
|
VIDEO,
|
||||||
|
"Failed to load custom pipeline action, multiple passes are not currently supported");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_unique<CustomPipelineAction>(std::move(library), std::move(pipeline_passes));
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomPipelineAction::CustomPipelineAction(
|
||||||
|
std::shared_ptr<VideoCommon::CustomAssetLibrary> library,
|
||||||
|
std::vector<PipelinePassPassDescription> pass_descriptions)
|
||||||
|
: m_library(std::move(library)), m_passes_config(std::move(pass_descriptions))
|
||||||
|
{
|
||||||
|
m_passes.resize(m_passes_config.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomPipelineAction::~CustomPipelineAction() = default;
|
||||||
|
|
||||||
|
void CustomPipelineAction::OnDrawStarted(GraphicsModActionData::DrawStarted* draw_started)
|
||||||
|
{
|
||||||
|
if (!draw_started) [[unlikely]]
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!draw_started->custom_pixel_shader) [[unlikely]]
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!m_valid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_passes.empty()) [[unlikely]]
|
||||||
|
return;
|
||||||
|
|
||||||
|
// For now assume a single pass
|
||||||
|
auto& pass = m_passes[0];
|
||||||
|
|
||||||
|
if (!pass.m_pixel_shader.m_asset) [[unlikely]]
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto shader_data = pass.m_pixel_shader.m_asset->GetData();
|
||||||
|
if (shader_data)
|
||||||
|
{
|
||||||
|
if (pass.m_pixel_shader.m_asset->GetLastLoadedTime() > pass.m_pixel_shader.m_cached_write_time)
|
||||||
|
{
|
||||||
|
const auto material = pass.m_pixel_material.m_asset->GetData();
|
||||||
|
if (!material)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pass.m_pixel_shader.m_cached_write_time = pass.m_pixel_shader.m_asset->GetLastLoadedTime();
|
||||||
|
|
||||||
|
for (const auto& prop : material->properties)
|
||||||
|
{
|
||||||
|
if (!shader_data->m_properties.contains(prop.m_code_name))
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO,
|
||||||
|
"Custom pipeline has material asset '{}' that has property '{}'"
|
||||||
|
"that is not on shader asset '{}'",
|
||||||
|
pass.m_pixel_material.m_asset->GetAssetId(), prop.m_code_name,
|
||||||
|
pass.m_pixel_shader.m_asset->GetAssetId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate shader details
|
||||||
|
std::string color_shader_data =
|
||||||
|
ReplaceAll(shader_data->m_shader_source, "custom_main", CUSTOM_PIXELSHADER_COLOR_FUNC);
|
||||||
|
const auto global_conflicts = GlobalConflicts(color_shader_data);
|
||||||
|
color_shader_data = ReplaceAll(color_shader_data, "\r\n", "\n");
|
||||||
|
color_shader_data = ReplaceAll(color_shader_data, "{", "{{");
|
||||||
|
color_shader_data = ReplaceAll(color_shader_data, "}", "}}");
|
||||||
|
// First replace global conflicts with dummy strings
|
||||||
|
// This avoids the problem where a shorter word
|
||||||
|
// is in a longer word, ex two functions: 'execute' and 'execute_fast'
|
||||||
|
for (std::size_t i = 0; i < global_conflicts.size(); i++)
|
||||||
|
{
|
||||||
|
const std::string& identifier = global_conflicts[i];
|
||||||
|
color_shader_data =
|
||||||
|
ReplaceAll(color_shader_data, identifier, fmt::format("_{0}_DOLPHIN_TEMP_{0}_", i));
|
||||||
|
}
|
||||||
|
// Now replace the temporaries with the actual value
|
||||||
|
for (std::size_t i = 0; i < global_conflicts.size(); i++)
|
||||||
|
{
|
||||||
|
const std::string& identifier = global_conflicts[i];
|
||||||
|
color_shader_data = ReplaceAll(color_shader_data, fmt::format("_{0}_DOLPHIN_TEMP_{0}_", i),
|
||||||
|
fmt::format("{}_{{0}}", identifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& texture_code_name : m_texture_code_names)
|
||||||
|
{
|
||||||
|
color_shader_data =
|
||||||
|
ReplaceAll(color_shader_data, fmt::format("{}_COORD", texture_code_name),
|
||||||
|
fmt::format("{}_COORD_{{0}}", texture_code_name));
|
||||||
|
color_shader_data = ReplaceAll(color_shader_data, fmt::format("{}_UNIT", texture_code_name),
|
||||||
|
fmt::format("{}_UNIT_{{0}}", texture_code_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_last_generated_shader_code = ShaderCode{};
|
||||||
|
WriteDefines(&m_last_generated_shader_code, m_texture_code_names, draw_started->texture_unit);
|
||||||
|
m_last_generated_shader_code.Write("{}", color_shader_data);
|
||||||
|
}
|
||||||
|
CustomPixelShader custom_pixel_shader;
|
||||||
|
custom_pixel_shader.custom_shader = m_last_generated_shader_code.GetBuffer();
|
||||||
|
*draw_started->custom_pixel_shader = custom_pixel_shader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomPipelineAction::OnTextureCreate(GraphicsModActionData::TextureCreate* create)
|
||||||
|
{
|
||||||
|
if (!create->custom_textures) [[unlikely]]
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!create->additional_dependencies) [[unlikely]]
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_passes_config.empty()) [[unlikely]]
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_passes.empty()) [[unlikely]]
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_valid = true;
|
||||||
|
auto& loader = Core::System::GetInstance().GetCustomAssetLoader();
|
||||||
|
|
||||||
|
// For now assume a single pass
|
||||||
|
const auto& pass_config = m_passes_config[0];
|
||||||
|
auto& pass = m_passes[0];
|
||||||
|
|
||||||
|
if (!pass.m_pixel_material.m_asset)
|
||||||
|
{
|
||||||
|
pass.m_pixel_material.m_asset =
|
||||||
|
loader.LoadMaterial(pass_config.m_pixel_material_asset, m_library);
|
||||||
|
pass.m_pixel_material.m_cached_write_time = pass.m_pixel_material.m_asset->GetLastLoadedTime();
|
||||||
|
}
|
||||||
|
create->additional_dependencies->push_back(VideoCommon::CachedAsset<VideoCommon::CustomAsset>{
|
||||||
|
pass.m_pixel_material.m_asset, pass.m_pixel_material.m_asset->GetLastLoadedTime()});
|
||||||
|
|
||||||
|
const auto material_data = pass.m_pixel_material.m_asset->GetData();
|
||||||
|
if (!material_data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!pass.m_pixel_shader.m_asset || pass.m_pixel_material.m_asset->GetLastLoadedTime() >
|
||||||
|
pass.m_pixel_material.m_cached_write_time)
|
||||||
|
{
|
||||||
|
pass.m_pixel_shader.m_asset = loader.LoadPixelShader(material_data->shader_asset, m_library);
|
||||||
|
// Note: the asset timestamp will be updated in the draw command
|
||||||
|
}
|
||||||
|
create->additional_dependencies->push_back(VideoCommon::CachedAsset<VideoCommon::CustomAsset>{
|
||||||
|
pass.m_pixel_shader.m_asset, pass.m_pixel_shader.m_asset->GetLastLoadedTime()});
|
||||||
|
|
||||||
|
m_texture_code_names.clear();
|
||||||
|
std::vector<VideoCommon::CachedAsset<VideoCommon::GameTextureAsset>> game_assets;
|
||||||
|
for (const auto& property : material_data->properties)
|
||||||
|
{
|
||||||
|
if (property.m_type == VideoCommon::MaterialProperty::Type::Type_TextureAsset)
|
||||||
|
{
|
||||||
|
if (property.m_value)
|
||||||
|
{
|
||||||
|
if (auto* value = std::get_if<std::string>(&*property.m_value))
|
||||||
|
{
|
||||||
|
auto asset = loader.LoadGameTexture(*value, m_library);
|
||||||
|
if (asset)
|
||||||
|
{
|
||||||
|
const auto loaded_time = asset->GetLastLoadedTime();
|
||||||
|
game_assets.push_back(VideoCommon::CachedAsset<VideoCommon::GameTextureAsset>{
|
||||||
|
std::move(asset), loaded_time});
|
||||||
|
m_texture_code_names.push_back(property.m_code_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Note: we swap here instead of doing a clear + append of the member
|
||||||
|
// variable so that any loaded assets from previous iterations
|
||||||
|
// won't be let go
|
||||||
|
std::swap(pass.m_game_textures, game_assets);
|
||||||
|
|
||||||
|
for (auto& game_texture : pass.m_game_textures)
|
||||||
|
{
|
||||||
|
if (game_texture.m_asset)
|
||||||
|
{
|
||||||
|
auto data = game_texture.m_asset->GetData();
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
if (create->texture_width != data->m_levels[0].width ||
|
||||||
|
create->texture_height != data->m_levels[0].height)
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO,
|
||||||
|
"Custom pipeline for texture '{}' has asset '{}' that does not match "
|
||||||
|
"the width/height of the texture loaded. Texture {}x{} vs asset {}x{}",
|
||||||
|
create->texture_name, game_texture.m_asset->GetAssetId(),
|
||||||
|
create->texture_width, create->texture_height, data->m_levels[0].width,
|
||||||
|
data->m_levels[0].height);
|
||||||
|
m_valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: compare game textures and shader requirements
|
||||||
|
|
||||||
|
create->custom_textures->insert(create->custom_textures->end(), pass.m_game_textures.begin(),
|
||||||
|
pass.m_game_textures.end());
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
// Copyright 2022 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <picojson.h>
|
||||||
|
|
||||||
|
#include "VideoCommon/AbstractTexture.h"
|
||||||
|
#include "VideoCommon/Assets/CustomAssetLibrary.h"
|
||||||
|
#include "VideoCommon/Assets/MaterialAsset.h"
|
||||||
|
#include "VideoCommon/Assets/ShaderAsset.h"
|
||||||
|
#include "VideoCommon/Assets/TextureAsset.h"
|
||||||
|
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h"
|
||||||
|
#include "VideoCommon/ShaderGenCommon.h"
|
||||||
|
|
||||||
|
class CustomPipelineAction final : public GraphicsModAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct PipelinePassPassDescription
|
||||||
|
{
|
||||||
|
std::string m_pixel_material_asset;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::unique_ptr<CustomPipelineAction>
|
||||||
|
Create(const picojson::value& json_data,
|
||||||
|
std::shared_ptr<VideoCommon::CustomAssetLibrary> library);
|
||||||
|
CustomPipelineAction(std::shared_ptr<VideoCommon::CustomAssetLibrary> library,
|
||||||
|
std::vector<PipelinePassPassDescription> pass_descriptions);
|
||||||
|
~CustomPipelineAction();
|
||||||
|
void OnDrawStarted(GraphicsModActionData::DrawStarted*) override;
|
||||||
|
void OnTextureCreate(GraphicsModActionData::TextureCreate*) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<VideoCommon::CustomAssetLibrary> m_library;
|
||||||
|
std::vector<PipelinePassPassDescription> m_passes_config;
|
||||||
|
struct PipelinePass
|
||||||
|
{
|
||||||
|
VideoCommon::CachedAsset<VideoCommon::MaterialAsset> m_pixel_material;
|
||||||
|
VideoCommon::CachedAsset<VideoCommon::PixelShaderAsset> m_pixel_shader;
|
||||||
|
std::vector<VideoCommon::CachedAsset<VideoCommon::GameTextureAsset>> m_game_textures;
|
||||||
|
};
|
||||||
|
std::vector<PipelinePass> m_passes;
|
||||||
|
|
||||||
|
ShaderCode m_last_generated_shader_code;
|
||||||
|
|
||||||
|
bool m_valid = true;
|
||||||
|
|
||||||
|
std::vector<std::string> m_texture_code_names;
|
||||||
|
};
|
|
@ -0,0 +1,376 @@
|
||||||
|
// Copyright 2022 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.h"
|
||||||
|
#include "VideoCommon/AbstractGfx.h"
|
||||||
|
#include "VideoCommon/VideoConfig.h"
|
||||||
|
|
||||||
|
CustomShaderCache::CustomShaderCache()
|
||||||
|
{
|
||||||
|
m_api_type = g_ActiveConfig.backend_info.api_type;
|
||||||
|
m_host_config.bits = ShaderHostConfig::GetCurrent().bits;
|
||||||
|
|
||||||
|
m_async_shader_compiler = g_gfx->CreateAsyncShaderCompiler();
|
||||||
|
m_async_shader_compiler->StartWorkerThreads(1); // TODO
|
||||||
|
|
||||||
|
m_async_uber_shader_compiler = g_gfx->CreateAsyncShaderCompiler();
|
||||||
|
m_async_uber_shader_compiler->StartWorkerThreads(1); // TODO
|
||||||
|
|
||||||
|
m_frame_end_handler =
|
||||||
|
AfterFrameEvent::Register([this] { RetrieveAsyncShaders(); }, "RetreiveAsyncShaders");
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomShaderCache::~CustomShaderCache()
|
||||||
|
{
|
||||||
|
if (m_async_shader_compiler)
|
||||||
|
m_async_shader_compiler->StopWorkerThreads();
|
||||||
|
|
||||||
|
if (m_async_uber_shader_compiler)
|
||||||
|
m_async_uber_shader_compiler->StopWorkerThreads();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomShaderCache::RetrieveAsyncShaders()
|
||||||
|
{
|
||||||
|
m_async_shader_compiler->RetrieveWorkItems();
|
||||||
|
m_async_uber_shader_compiler->RetrieveWorkItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomShaderCache::Reload()
|
||||||
|
{
|
||||||
|
while (m_async_shader_compiler->HasPendingWork() || m_async_shader_compiler->HasCompletedWork())
|
||||||
|
{
|
||||||
|
m_async_shader_compiler->RetrieveWorkItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (m_async_uber_shader_compiler->HasPendingWork() ||
|
||||||
|
m_async_uber_shader_compiler->HasCompletedWork())
|
||||||
|
{
|
||||||
|
m_async_uber_shader_compiler->RetrieveWorkItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ps_cache = {};
|
||||||
|
m_uber_ps_cache = {};
|
||||||
|
m_pipeline_cache = {};
|
||||||
|
m_uber_pipeline_cache = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<const AbstractPipeline*>
|
||||||
|
CustomShaderCache::GetPipelineAsync(const VideoCommon::GXPipelineUid& uid,
|
||||||
|
const CustomShaderInstance& custom_shaders,
|
||||||
|
const AbstractPipelineConfig& pipeline_config)
|
||||||
|
{
|
||||||
|
if (auto holder = m_pipeline_cache.GetHolder(uid, custom_shaders))
|
||||||
|
{
|
||||||
|
if (holder->pending)
|
||||||
|
return std::nullopt;
|
||||||
|
return holder->value.get();
|
||||||
|
}
|
||||||
|
AsyncCreatePipeline(uid, custom_shaders, pipeline_config);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<const AbstractPipeline*>
|
||||||
|
CustomShaderCache::GetPipelineAsync(const VideoCommon::GXUberPipelineUid& uid,
|
||||||
|
const CustomShaderInstance& custom_shaders,
|
||||||
|
const AbstractPipelineConfig& pipeline_config)
|
||||||
|
{
|
||||||
|
if (auto holder = m_uber_pipeline_cache.GetHolder(uid, custom_shaders))
|
||||||
|
{
|
||||||
|
if (holder->pending)
|
||||||
|
return std::nullopt;
|
||||||
|
return holder->value.get();
|
||||||
|
}
|
||||||
|
AsyncCreatePipeline(uid, custom_shaders, pipeline_config);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomShaderCache::AsyncCreatePipeline(const VideoCommon::GXPipelineUid& uid,
|
||||||
|
|
||||||
|
const CustomShaderInstance& custom_shaders,
|
||||||
|
const AbstractPipelineConfig& pipeline_config)
|
||||||
|
{
|
||||||
|
class PipelineWorkItem final : public VideoCommon::AsyncShaderCompiler::WorkItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PipelineWorkItem(CustomShaderCache* shader_cache, const VideoCommon::GXPipelineUid& uid,
|
||||||
|
const CustomShaderInstance& custom_shaders, PipelineIterator iterator,
|
||||||
|
const AbstractPipelineConfig& pipeline_config)
|
||||||
|
: m_shader_cache(shader_cache), m_uid(uid), m_iterator(iterator),
|
||||||
|
m_custom_shaders(custom_shaders), m_config(pipeline_config)
|
||||||
|
{
|
||||||
|
SetStagesReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetStagesReady()
|
||||||
|
{
|
||||||
|
m_stages_ready = true;
|
||||||
|
|
||||||
|
PixelShaderUid ps_uid = m_uid.ps_uid;
|
||||||
|
ClearUnusedPixelShaderUidBits(m_shader_cache->m_api_type, m_shader_cache->m_host_config,
|
||||||
|
&ps_uid);
|
||||||
|
|
||||||
|
if (auto holder = m_shader_cache->m_ps_cache.GetHolder(ps_uid, m_custom_shaders))
|
||||||
|
{
|
||||||
|
// If the pixel shader is no longer pending compilation
|
||||||
|
// and the shader compilation succeeded, set
|
||||||
|
// the pipeline to use the new pixel shader.
|
||||||
|
// Otherwise, use the existing shader.
|
||||||
|
if (!holder->pending && holder->value.get())
|
||||||
|
{
|
||||||
|
m_config.pixel_shader = holder->value.get();
|
||||||
|
}
|
||||||
|
m_stages_ready &= !holder->pending;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_stages_ready &= false;
|
||||||
|
m_shader_cache->QueuePixelShaderCompile(ps_uid, m_custom_shaders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compile() override
|
||||||
|
{
|
||||||
|
if (m_stages_ready)
|
||||||
|
{
|
||||||
|
m_pipeline = g_gfx->CreatePipeline(m_config);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Retrieve() override
|
||||||
|
{
|
||||||
|
if (m_stages_ready)
|
||||||
|
{
|
||||||
|
m_shader_cache->NotifyPipelineFinished(m_iterator, std::move(m_pipeline));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Re-queue for next frame.
|
||||||
|
auto wi = m_shader_cache->m_async_shader_compiler->CreateWorkItem<PipelineWorkItem>(
|
||||||
|
m_shader_cache, m_uid, m_custom_shaders, m_iterator, m_config);
|
||||||
|
m_shader_cache->m_async_shader_compiler->QueueWorkItem(std::move(wi), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CustomShaderCache* m_shader_cache;
|
||||||
|
std::unique_ptr<AbstractPipeline> m_pipeline;
|
||||||
|
VideoCommon::GXPipelineUid m_uid;
|
||||||
|
PipelineIterator m_iterator;
|
||||||
|
AbstractPipelineConfig m_config;
|
||||||
|
CustomShaderInstance m_custom_shaders;
|
||||||
|
bool m_stages_ready;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto list_iter = m_pipeline_cache.InsertElement(uid, custom_shaders);
|
||||||
|
auto work_item = m_async_shader_compiler->CreateWorkItem<PipelineWorkItem>(
|
||||||
|
this, uid, custom_shaders, list_iter, pipeline_config);
|
||||||
|
m_async_shader_compiler->QueueWorkItem(std::move(work_item), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomShaderCache::AsyncCreatePipeline(const VideoCommon::GXUberPipelineUid& uid,
|
||||||
|
|
||||||
|
const CustomShaderInstance& custom_shaders,
|
||||||
|
const AbstractPipelineConfig& pipeline_config)
|
||||||
|
{
|
||||||
|
class PipelineWorkItem final : public VideoCommon::AsyncShaderCompiler::WorkItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PipelineWorkItem(CustomShaderCache* shader_cache, const VideoCommon::GXUberPipelineUid& uid,
|
||||||
|
const CustomShaderInstance& custom_shaders, UberPipelineIterator iterator,
|
||||||
|
const AbstractPipelineConfig& pipeline_config)
|
||||||
|
: m_shader_cache(shader_cache), m_uid(uid), m_iterator(iterator),
|
||||||
|
m_custom_shaders(custom_shaders), m_config(pipeline_config)
|
||||||
|
{
|
||||||
|
SetStagesReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetStagesReady()
|
||||||
|
{
|
||||||
|
m_stages_ready = true;
|
||||||
|
|
||||||
|
UberShader::PixelShaderUid ps_uid = m_uid.ps_uid;
|
||||||
|
ClearUnusedPixelShaderUidBits(m_shader_cache->m_api_type, m_shader_cache->m_host_config,
|
||||||
|
&ps_uid);
|
||||||
|
|
||||||
|
if (auto holder = m_shader_cache->m_uber_ps_cache.GetHolder(ps_uid, m_custom_shaders))
|
||||||
|
{
|
||||||
|
if (!holder->pending && holder->value.get())
|
||||||
|
{
|
||||||
|
m_config.pixel_shader = holder->value.get();
|
||||||
|
}
|
||||||
|
m_stages_ready &= !holder->pending;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_stages_ready &= false;
|
||||||
|
m_shader_cache->QueuePixelShaderCompile(ps_uid, m_custom_shaders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compile() override
|
||||||
|
{
|
||||||
|
if (m_stages_ready)
|
||||||
|
{
|
||||||
|
if (m_config.pixel_shader == nullptr || m_config.vertex_shader == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_pipeline = g_gfx->CreatePipeline(m_config);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Retrieve() override
|
||||||
|
{
|
||||||
|
if (m_stages_ready)
|
||||||
|
{
|
||||||
|
m_shader_cache->NotifyPipelineFinished(m_iterator, std::move(m_pipeline));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Re-queue for next frame.
|
||||||
|
auto wi = m_shader_cache->m_async_uber_shader_compiler->CreateWorkItem<PipelineWorkItem>(
|
||||||
|
m_shader_cache, m_uid, m_custom_shaders, m_iterator, m_config);
|
||||||
|
m_shader_cache->m_async_uber_shader_compiler->QueueWorkItem(std::move(wi), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CustomShaderCache* m_shader_cache;
|
||||||
|
std::unique_ptr<AbstractPipeline> m_pipeline;
|
||||||
|
VideoCommon::GXUberPipelineUid m_uid;
|
||||||
|
UberPipelineIterator m_iterator;
|
||||||
|
AbstractPipelineConfig m_config;
|
||||||
|
CustomShaderInstance m_custom_shaders;
|
||||||
|
bool m_stages_ready;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto list_iter = m_uber_pipeline_cache.InsertElement(uid, custom_shaders);
|
||||||
|
auto work_item = m_async_uber_shader_compiler->CreateWorkItem<PipelineWorkItem>(
|
||||||
|
this, uid, custom_shaders, list_iter, pipeline_config);
|
||||||
|
m_async_uber_shader_compiler->QueueWorkItem(std::move(work_item), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomShaderCache::NotifyPipelineFinished(PipelineIterator iterator,
|
||||||
|
std::unique_ptr<AbstractPipeline> pipeline)
|
||||||
|
{
|
||||||
|
iterator->second.pending = false;
|
||||||
|
iterator->second.value = std::move(pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomShaderCache::NotifyPipelineFinished(UberPipelineIterator iterator,
|
||||||
|
std::unique_ptr<AbstractPipeline> pipeline)
|
||||||
|
{
|
||||||
|
iterator->second.pending = false;
|
||||||
|
iterator->second.value = std::move(pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomShaderCache::QueuePixelShaderCompile(const PixelShaderUid& uid,
|
||||||
|
|
||||||
|
const CustomShaderInstance& custom_shaders)
|
||||||
|
{
|
||||||
|
class PixelShaderWorkItem final : public VideoCommon::AsyncShaderCompiler::WorkItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PixelShaderWorkItem(CustomShaderCache* shader_cache, const PixelShaderUid& uid,
|
||||||
|
const CustomShaderInstance& custom_shaders, PixelShaderIterator iter)
|
||||||
|
: m_shader_cache(shader_cache), m_uid(uid), m_custom_shaders(custom_shaders), m_iter(iter)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compile() override
|
||||||
|
{
|
||||||
|
m_shader = m_shader_cache->CompilePixelShader(m_uid, m_custom_shaders);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Retrieve() override
|
||||||
|
{
|
||||||
|
m_shader_cache->NotifyPixelShaderFinished(m_iter, std::move(m_shader));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CustomShaderCache* m_shader_cache;
|
||||||
|
std::unique_ptr<AbstractShader> m_shader;
|
||||||
|
PixelShaderUid m_uid;
|
||||||
|
CustomShaderInstance m_custom_shaders;
|
||||||
|
PixelShaderIterator m_iter;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto list_iter = m_ps_cache.InsertElement(uid, custom_shaders);
|
||||||
|
auto work_item = m_async_shader_compiler->CreateWorkItem<PixelShaderWorkItem>(
|
||||||
|
this, uid, custom_shaders, list_iter);
|
||||||
|
m_async_shader_compiler->QueueWorkItem(std::move(work_item), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomShaderCache::QueuePixelShaderCompile(const UberShader::PixelShaderUid& uid,
|
||||||
|
|
||||||
|
const CustomShaderInstance& custom_shaders)
|
||||||
|
{
|
||||||
|
class PixelShaderWorkItem final : public VideoCommon::AsyncShaderCompiler::WorkItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PixelShaderWorkItem(CustomShaderCache* shader_cache, const UberShader::PixelShaderUid& uid,
|
||||||
|
const CustomShaderInstance& custom_shaders, UberPixelShaderIterator iter)
|
||||||
|
: m_shader_cache(shader_cache), m_uid(uid), m_custom_shaders(custom_shaders), m_iter(iter)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compile() override
|
||||||
|
{
|
||||||
|
m_shader = m_shader_cache->CompilePixelShader(m_uid, m_custom_shaders);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Retrieve() override
|
||||||
|
{
|
||||||
|
m_shader_cache->NotifyPixelShaderFinished(m_iter, std::move(m_shader));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CustomShaderCache* m_shader_cache;
|
||||||
|
std::unique_ptr<AbstractShader> m_shader;
|
||||||
|
UberShader::PixelShaderUid m_uid;
|
||||||
|
CustomShaderInstance m_custom_shaders;
|
||||||
|
UberPixelShaderIterator m_iter;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto list_iter = m_uber_ps_cache.InsertElement(uid, custom_shaders);
|
||||||
|
auto work_item = m_async_uber_shader_compiler->CreateWorkItem<PixelShaderWorkItem>(
|
||||||
|
this, uid, custom_shaders, list_iter);
|
||||||
|
m_async_uber_shader_compiler->QueueWorkItem(std::move(work_item), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractShader>
|
||||||
|
CustomShaderCache::CompilePixelShader(const PixelShaderUid& uid,
|
||||||
|
const CustomShaderInstance& custom_shaders) const
|
||||||
|
{
|
||||||
|
const ShaderCode source_code = GeneratePixelShaderCode(
|
||||||
|
m_api_type, m_host_config, uid.GetUidData(), custom_shaders.pixel_contents);
|
||||||
|
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(),
|
||||||
|
"Custom Pixel Shader");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractShader>
|
||||||
|
CustomShaderCache::CompilePixelShader(const UberShader::PixelShaderUid& uid,
|
||||||
|
const CustomShaderInstance& custom_shaders) const
|
||||||
|
{
|
||||||
|
const ShaderCode source_code =
|
||||||
|
GenPixelShader(m_api_type, m_host_config, uid.GetUidData(), custom_shaders.pixel_contents);
|
||||||
|
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(),
|
||||||
|
"Custom Uber Pixel Shader");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomShaderCache::NotifyPixelShaderFinished(PixelShaderIterator iterator,
|
||||||
|
std::unique_ptr<AbstractShader> shader)
|
||||||
|
{
|
||||||
|
iterator->second.pending = false;
|
||||||
|
iterator->second.value = std::move(shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomShaderCache::NotifyPixelShaderFinished(UberPixelShaderIterator iterator,
|
||||||
|
std::unique_ptr<AbstractShader> shader)
|
||||||
|
{
|
||||||
|
iterator->second.pending = false;
|
||||||
|
iterator->second.value = std::move(shader);
|
||||||
|
}
|
|
@ -0,0 +1,144 @@
|
||||||
|
// Copyright 2022 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include "VideoCommon/AbstractPipeline.h"
|
||||||
|
#include "VideoCommon/AbstractShader.h"
|
||||||
|
#include "VideoCommon/AsyncShaderCompiler.h"
|
||||||
|
#include "VideoCommon/GXPipelineTypes.h"
|
||||||
|
#include "VideoCommon/PixelShaderGen.h"
|
||||||
|
#include "VideoCommon/ShaderGenCommon.h"
|
||||||
|
#include "VideoCommon/UberShaderPixel.h"
|
||||||
|
#include "VideoCommon/VideoEvents.h"
|
||||||
|
|
||||||
|
struct CustomShaderInstance
|
||||||
|
{
|
||||||
|
CustomPixelShaderContents pixel_contents;
|
||||||
|
|
||||||
|
bool operator==(const CustomShaderInstance& other) const = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CustomShaderCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CustomShaderCache();
|
||||||
|
~CustomShaderCache();
|
||||||
|
CustomShaderCache(const CustomShaderCache&) = delete;
|
||||||
|
CustomShaderCache(CustomShaderCache&&) = delete;
|
||||||
|
CustomShaderCache& operator=(const CustomShaderCache&) = delete;
|
||||||
|
CustomShaderCache& operator=(CustomShaderCache&&) = delete;
|
||||||
|
|
||||||
|
// Changes the shader host config. Shaders should be reloaded afterwards.
|
||||||
|
void SetHostConfig(const ShaderHostConfig& host_config) { m_host_config.bits = host_config.bits; }
|
||||||
|
|
||||||
|
// Retrieves all pending shaders/pipelines from the async compiler.
|
||||||
|
void RetrieveAsyncShaders();
|
||||||
|
|
||||||
|
// Reloads/recreates all shaders and pipelines.
|
||||||
|
void Reload();
|
||||||
|
|
||||||
|
// The optional will be empty if this pipeline is now background compiling.
|
||||||
|
std::optional<const AbstractPipeline*>
|
||||||
|
GetPipelineAsync(const VideoCommon::GXPipelineUid& uid,
|
||||||
|
const CustomShaderInstance& custom_shaders,
|
||||||
|
const AbstractPipelineConfig& pipeline_config);
|
||||||
|
std::optional<const AbstractPipeline*>
|
||||||
|
GetPipelineAsync(const VideoCommon::GXUberPipelineUid& uid,
|
||||||
|
const CustomShaderInstance& custom_shaders,
|
||||||
|
const AbstractPipelineConfig& pipeline_config);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Configuration bits.
|
||||||
|
APIType m_api_type = APIType::Nothing;
|
||||||
|
ShaderHostConfig m_host_config = {};
|
||||||
|
std::unique_ptr<VideoCommon::AsyncShaderCompiler> m_async_shader_compiler;
|
||||||
|
std::unique_ptr<VideoCommon::AsyncShaderCompiler> m_async_uber_shader_compiler;
|
||||||
|
|
||||||
|
void AsyncCreatePipeline(const VideoCommon::GXPipelineUid& uid,
|
||||||
|
const CustomShaderInstance& custom_shaders,
|
||||||
|
const AbstractPipelineConfig& pipeline_config);
|
||||||
|
void AsyncCreatePipeline(const VideoCommon::GXUberPipelineUid& uid,
|
||||||
|
const CustomShaderInstance& custom_shaders,
|
||||||
|
const AbstractPipelineConfig& pipeline_config);
|
||||||
|
|
||||||
|
// Shader/Pipeline cache helper
|
||||||
|
template <typename Uid, typename ValueType>
|
||||||
|
struct Cache
|
||||||
|
{
|
||||||
|
struct CacheHolder
|
||||||
|
{
|
||||||
|
std::unique_ptr<ValueType> value = nullptr;
|
||||||
|
bool pending = true;
|
||||||
|
};
|
||||||
|
using CacheElement = std::pair<CustomShaderInstance, CacheHolder>;
|
||||||
|
using CacheList = std::list<CacheElement>;
|
||||||
|
std::map<Uid, CacheList> uid_to_cachelist;
|
||||||
|
|
||||||
|
const CacheHolder* GetHolder(const Uid& uid, const CustomShaderInstance& custom_shaders) const
|
||||||
|
{
|
||||||
|
if (auto uuid_it = uid_to_cachelist.find(uid); uuid_it != uid_to_cachelist.end())
|
||||||
|
{
|
||||||
|
for (const auto& [custom_shader_val, holder] : uuid_it->second)
|
||||||
|
{
|
||||||
|
if (custom_shaders == custom_shader_val)
|
||||||
|
{
|
||||||
|
return &holder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
typename CacheList::iterator InsertElement(const Uid& uid,
|
||||||
|
const CustomShaderInstance& custom_shaders)
|
||||||
|
{
|
||||||
|
CacheList& cachelist = uid_to_cachelist[uid];
|
||||||
|
CacheElement e{custom_shaders, CacheHolder{}};
|
||||||
|
return cachelist.emplace(cachelist.begin(), std::move(e));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Cache<PixelShaderUid, AbstractShader> m_ps_cache;
|
||||||
|
Cache<UberShader::PixelShaderUid, AbstractShader> m_uber_ps_cache;
|
||||||
|
Cache<VideoCommon::GXPipelineUid, AbstractPipeline> m_pipeline_cache;
|
||||||
|
Cache<VideoCommon::GXUberPipelineUid, AbstractPipeline> m_uber_pipeline_cache;
|
||||||
|
|
||||||
|
using PipelineIterator = Cache<VideoCommon::GXPipelineUid, AbstractPipeline>::CacheList::iterator;
|
||||||
|
using UberPipelineIterator =
|
||||||
|
Cache<VideoCommon::GXUberPipelineUid, AbstractPipeline>::CacheList::iterator;
|
||||||
|
using PixelShaderIterator = Cache<PixelShaderUid, AbstractShader>::CacheList::iterator;
|
||||||
|
using UberPixelShaderIterator =
|
||||||
|
Cache<UberShader::PixelShaderUid, AbstractShader>::CacheList::iterator;
|
||||||
|
|
||||||
|
void NotifyPipelineFinished(PipelineIterator iterator,
|
||||||
|
std::unique_ptr<AbstractPipeline> pipeline);
|
||||||
|
void NotifyPipelineFinished(UberPipelineIterator iterator,
|
||||||
|
std::unique_ptr<AbstractPipeline> pipeline);
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractShader>
|
||||||
|
CompilePixelShader(const PixelShaderUid& uid, const CustomShaderInstance& custom_shaders) const;
|
||||||
|
void NotifyPixelShaderFinished(PixelShaderIterator iterator,
|
||||||
|
std::unique_ptr<AbstractShader> shader);
|
||||||
|
std::unique_ptr<AbstractShader>
|
||||||
|
CompilePixelShader(const UberShader::PixelShaderUid& uid,
|
||||||
|
const CustomShaderInstance& custom_shaders) const;
|
||||||
|
void NotifyPixelShaderFinished(UberPixelShaderIterator iterator,
|
||||||
|
std::unique_ptr<AbstractShader> shader);
|
||||||
|
|
||||||
|
void QueuePixelShaderCompile(const PixelShaderUid& uid,
|
||||||
|
const CustomShaderInstance& custom_shaders);
|
||||||
|
void QueuePixelShaderCompile(const UberShader::PixelShaderUid& uid,
|
||||||
|
const CustomShaderInstance& custom_shaders);
|
||||||
|
|
||||||
|
Common::EventHook m_frame_end_handler;
|
||||||
|
};
|
|
@ -3,18 +3,23 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <optional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Matrix.h"
|
#include "Common/Matrix.h"
|
||||||
#include "VideoCommon/Assets/TextureAsset.h"
|
#include "VideoCommon/Assets/TextureAsset.h"
|
||||||
|
#include "VideoCommon/PixelShaderGen.h"
|
||||||
|
|
||||||
namespace GraphicsModActionData
|
namespace GraphicsModActionData
|
||||||
{
|
{
|
||||||
struct DrawStarted
|
struct DrawStarted
|
||||||
{
|
{
|
||||||
|
u32 texture_unit;
|
||||||
bool* skip;
|
bool* skip;
|
||||||
|
std::optional<CustomPixelShader>* custom_pixel_shader;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EFB
|
struct EFB
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionFactory.h"
|
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionFactory.h"
|
||||||
|
|
||||||
|
#include "VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.h"
|
||||||
#include "VideoCommon/GraphicsModSystem/Runtime/Actions/MoveAction.h"
|
#include "VideoCommon/GraphicsModSystem/Runtime/Actions/MoveAction.h"
|
||||||
#include "VideoCommon/GraphicsModSystem/Runtime/Actions/PrintAction.h"
|
#include "VideoCommon/GraphicsModSystem/Runtime/Actions/PrintAction.h"
|
||||||
#include "VideoCommon/GraphicsModSystem/Runtime/Actions/ScaleAction.h"
|
#include "VideoCommon/GraphicsModSystem/Runtime/Actions/ScaleAction.h"
|
||||||
|
@ -11,7 +12,7 @@
|
||||||
namespace GraphicsModActionFactory
|
namespace GraphicsModActionFactory
|
||||||
{
|
{
|
||||||
std::unique_ptr<GraphicsModAction> Create(std::string_view name, const picojson::value& json_data,
|
std::unique_ptr<GraphicsModAction> Create(std::string_view name, const picojson::value& json_data,
|
||||||
std::string_view path)
|
std::shared_ptr<VideoCommon::CustomAssetLibrary> library)
|
||||||
{
|
{
|
||||||
if (name == "print")
|
if (name == "print")
|
||||||
{
|
{
|
||||||
|
@ -29,6 +30,10 @@ std::unique_ptr<GraphicsModAction> Create(std::string_view name, const picojson:
|
||||||
{
|
{
|
||||||
return ScaleAction::Create(json_data);
|
return ScaleAction::Create(json_data);
|
||||||
}
|
}
|
||||||
|
else if (name == "custom_pipeline")
|
||||||
|
{
|
||||||
|
return CustomPipelineAction::Create(json_data, std::move(library));
|
||||||
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,11 @@
|
||||||
|
|
||||||
#include <picojson.h>
|
#include <picojson.h>
|
||||||
|
|
||||||
|
#include "VideoCommon/Assets/CustomAssetLibrary.h"
|
||||||
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h"
|
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h"
|
||||||
|
|
||||||
namespace GraphicsModActionFactory
|
namespace GraphicsModActionFactory
|
||||||
{
|
{
|
||||||
std::unique_ptr<GraphicsModAction> Create(std::string_view name, const picojson::value& json_data,
|
std::unique_ptr<GraphicsModAction> Create(std::string_view name, const picojson::value& json_data,
|
||||||
std::string_view path);
|
std::shared_ptr<VideoCommon::CustomAssetLibrary> library);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,9 @@
|
||||||
|
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
|
|
||||||
|
#include "VideoCommon/Assets/DirectFilesystemAssetLibrary.h"
|
||||||
#include "VideoCommon/GraphicsModSystem/Config/GraphicsMod.h"
|
#include "VideoCommon/GraphicsModSystem/Config/GraphicsMod.h"
|
||||||
|
#include "VideoCommon/GraphicsModSystem/Config/GraphicsModAsset.h"
|
||||||
#include "VideoCommon/GraphicsModSystem/Config/GraphicsModGroup.h"
|
#include "VideoCommon/GraphicsModSystem/Config/GraphicsModGroup.h"
|
||||||
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionFactory.h"
|
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionFactory.h"
|
||||||
#include "VideoCommon/TextureInfo.h"
|
#include "VideoCommon/TextureInfo.h"
|
||||||
|
@ -187,6 +189,8 @@ void GraphicsModManager::Load(const GraphicsModGroupConfig& config)
|
||||||
|
|
||||||
const auto& mods = config.GetMods();
|
const auto& mods = config.GetMods();
|
||||||
|
|
||||||
|
auto filesystem_library = std::make_shared<VideoCommon::DirectFilesystemAssetLibrary>();
|
||||||
|
|
||||||
std::map<std::string, std::vector<GraphicsTargetConfig>> group_to_targets;
|
std::map<std::string, std::vector<GraphicsTargetConfig>> group_to_targets;
|
||||||
for (const auto& mod : mods)
|
for (const auto& mod : mods)
|
||||||
{
|
{
|
||||||
|
@ -208,6 +212,29 @@ void GraphicsModManager::Load(const GraphicsModGroupConfig& config)
|
||||||
group_to_targets[internal_group].push_back(target);
|
group_to_targets[internal_group].push_back(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string base_path;
|
||||||
|
SplitPath(mod.GetAbsolutePath(), &base_path, nullptr, nullptr);
|
||||||
|
for (const GraphicsModAssetConfig& asset : mod.m_assets)
|
||||||
|
{
|
||||||
|
auto asset_map = asset.m_map;
|
||||||
|
for (auto& [k, v] : asset_map)
|
||||||
|
{
|
||||||
|
if (v.is_absolute())
|
||||||
|
{
|
||||||
|
WARN_LOG_FMT(VIDEO,
|
||||||
|
"Specified graphics mod asset '{}' for mod '{}' has an absolute path, you "
|
||||||
|
"shouldn't release this to users.",
|
||||||
|
asset.m_name, mod.m_title);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v = std::filesystem::path{base_path} / v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystem_library->SetAssetIDMapData(asset.m_name, std::move(asset_map));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& mod : mods)
|
for (const auto& mod : mods)
|
||||||
|
@ -215,12 +242,11 @@ void GraphicsModManager::Load(const GraphicsModGroupConfig& config)
|
||||||
for (const GraphicsModFeatureConfig& feature : mod.m_features)
|
for (const GraphicsModFeatureConfig& feature : mod.m_features)
|
||||||
{
|
{
|
||||||
const auto create_action =
|
const auto create_action =
|
||||||
[](const std::string_view& action_name, const picojson::value& json_data,
|
[filesystem_library](const std::string_view& action_name,
|
||||||
|
const picojson::value& json_data,
|
||||||
GraphicsModConfig mod_config) -> std::unique_ptr<GraphicsModAction> {
|
GraphicsModConfig mod_config) -> std::unique_ptr<GraphicsModAction> {
|
||||||
std::string base_path;
|
auto action =
|
||||||
SplitPath(mod_config.GetAbsolutePath(), &base_path, nullptr, nullptr);
|
GraphicsModActionFactory::Create(action_name, json_data, std::move(filesystem_library));
|
||||||
|
|
||||||
auto action = GraphicsModActionFactory::Create(action_name, json_data, base_path);
|
|
||||||
if (action == nullptr)
|
if (action == nullptr)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -175,3 +175,180 @@ void GetLightingShaderUid(LightingUidData& uid_data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GenerateCustomLightingHeaderDetails(ShaderCode* out, u32 enablelighting, u32 light_mask)
|
||||||
|
{
|
||||||
|
u32 light_count = 0;
|
||||||
|
for (u32 j = 0; j < NUM_XF_COLOR_CHANNELS; j++)
|
||||||
|
{
|
||||||
|
if ((enablelighting & (1 << j)) != 0) // Color lights
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
if ((light_mask & (1 << (i + 8 * j))) != 0)
|
||||||
|
{
|
||||||
|
light_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((enablelighting & (1 << (j + 2))) != 0) // Alpha lights
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
if ((light_mask & (1 << (i + 8 * (j + 2)))) != 0)
|
||||||
|
{
|
||||||
|
light_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (light_count > 0)
|
||||||
|
{
|
||||||
|
out->Write("\tCustomShaderLightData[{}] light;\n", light_count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Cheat so shaders compile
|
||||||
|
out->Write("\tCustomShaderLightData[1] light;\n", light_count);
|
||||||
|
}
|
||||||
|
out->Write("\tint light_count;\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void GenerateCustomLightingImplementation(ShaderCode* out, const LightingUidData& uid_data,
|
||||||
|
std::string_view in_color_name)
|
||||||
|
{
|
||||||
|
auto generate_lighting = [](ShaderCode* out, const LightingUidData& uid_data, int index,
|
||||||
|
int litchan_index, u32 channel_index, u32 custom_light_index,
|
||||||
|
bool alpha) {
|
||||||
|
const auto attnfunc =
|
||||||
|
static_cast<AttenuationFunc>((uid_data.attnfunc >> (2 * litchan_index)) & 0x3);
|
||||||
|
|
||||||
|
const std::string_view light_type = alpha ? "alpha" : "color";
|
||||||
|
const std::string name = fmt::format("lights_chan{}_{}", channel_index, light_type);
|
||||||
|
|
||||||
|
out->Write("\t{{\n");
|
||||||
|
out->Write("\t\tcustom_data.{}[{}].direction = " LIGHT_DIR ".xyz;\n", name, custom_light_index,
|
||||||
|
LIGHT_DIR_PARAMS(index));
|
||||||
|
out->Write("\t\tcustom_data.{}[{}].position = " LIGHT_POS ".xyz;\n", name, custom_light_index,
|
||||||
|
LIGHT_POS_PARAMS(index));
|
||||||
|
out->Write("\t\tcustom_data.{}[{}].cosatt = " LIGHT_COSATT ";\n", name, custom_light_index,
|
||||||
|
LIGHT_COSATT_PARAMS(index));
|
||||||
|
out->Write("\t\tcustom_data.{}[{}].distatt = " LIGHT_DISTATT ";\n", name, custom_light_index,
|
||||||
|
LIGHT_DISTATT_PARAMS(index));
|
||||||
|
out->Write("\t\tcustom_data.{}[{}].attenuation_type = {};\n", name, custom_light_index,
|
||||||
|
static_cast<u32>(attnfunc));
|
||||||
|
if (alpha)
|
||||||
|
{
|
||||||
|
out->Write("\t\tcustom_data.{}[{}].color = float3(" LIGHT_COL
|
||||||
|
") / float3(255.0, 255.0, 255.0);\n",
|
||||||
|
name, custom_light_index, LIGHT_COL_PARAMS(index, alpha ? "a" : "rgb"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out->Write("\t\tcustom_data.{}[{}].color = " LIGHT_COL " / float3(255.0, 255.0, 255.0);\n",
|
||||||
|
name, custom_light_index, LIGHT_COL_PARAMS(index, alpha ? "a" : "rgb"));
|
||||||
|
}
|
||||||
|
out->Write("\t}}\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
for (u32 channel_index = 0; channel_index < NUM_XF_COLOR_CHANNELS; channel_index++)
|
||||||
|
{
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_color[{}].direction = float3(0, 0, 0);\n",
|
||||||
|
channel_index, i);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_color[{}].position = float3(0, 0, 0);\n",
|
||||||
|
channel_index, i);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_color[{}].color = float3(0, 0, 0);\n", channel_index,
|
||||||
|
i);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_color[{}].cosatt = float4(0, 0, 0, 0);\n",
|
||||||
|
channel_index, i);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_color[{}].distatt = float4(0, 0, 0, 0);\n",
|
||||||
|
channel_index, i);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_color[{}].attenuation_type = 0;\n", channel_index, i);
|
||||||
|
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_alpha[{}].direction = float3(0, 0, 0);\n",
|
||||||
|
channel_index, i);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_alpha[{}].position = float3(0, 0, 0);\n",
|
||||||
|
channel_index, i);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_alpha[{}].color = float3(0, 0, 0);\n", channel_index,
|
||||||
|
i);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_alpha[{}].cosatt = float4(0, 0, 0, 0);\n",
|
||||||
|
channel_index, i);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_alpha[{}].distatt = float4(0, 0, 0, 0);\n",
|
||||||
|
channel_index, i);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_alpha[{}].attenuation_type = 0;\n", channel_index, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 j = 0; j < NUM_XF_COLOR_CHANNELS; j++)
|
||||||
|
{
|
||||||
|
const bool colormatsource = !!(uid_data.matsource & (1 << j));
|
||||||
|
if (colormatsource) // from vertex
|
||||||
|
out->Write("custom_data.base_material[{}] = {}{};\n", j, in_color_name, j);
|
||||||
|
else // from color
|
||||||
|
out->Write("custom_data.base_material[{}] = {}[{}] / 255.0;\n", j, I_MATERIALS, j + 2);
|
||||||
|
|
||||||
|
if ((uid_data.enablelighting & (1 << j)) != 0)
|
||||||
|
{
|
||||||
|
if ((uid_data.ambsource & (1 << j)) != 0) // from vertex
|
||||||
|
out->Write("custom_data.ambient_lighting[{}] = {}{};\n", j, in_color_name, j);
|
||||||
|
else // from color
|
||||||
|
out->Write("custom_data.ambient_lighting[{}] = {}[{}] / 255.0;\n", j, I_MATERIALS, j);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out->Write("custom_data.ambient_lighting[{}] = float4(1, 1, 1, 1);\n", j);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if alpha is different
|
||||||
|
const bool alphamatsource = !!(uid_data.matsource & (1 << (j + 2)));
|
||||||
|
if (alphamatsource != colormatsource)
|
||||||
|
{
|
||||||
|
if (alphamatsource) // from vertex
|
||||||
|
out->Write("custom_data.base_material[{}].w = {}{}.w;\n", j, in_color_name, j);
|
||||||
|
else // from color
|
||||||
|
out->Write("custom_data.base_material[{}].w = {}[{}].w / 255.0;\n", j, I_MATERIALS, j + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((uid_data.enablelighting & (1 << (j + 2))) != 0)
|
||||||
|
{
|
||||||
|
if ((uid_data.ambsource & (1 << (j + 2))) != 0) // from vertex
|
||||||
|
out->Write("custom_data.ambient_lighting[{}].w = {}{}.w;\n", j, in_color_name, j);
|
||||||
|
else // from color
|
||||||
|
out->Write("custom_data.ambient_lighting[{}].w = {}[{}].w / 255.0;\n", j, I_MATERIALS, j);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out->Write("custom_data.ambient_lighting[{}].w = 1;\n", j);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 light_count = 0;
|
||||||
|
if ((uid_data.enablelighting & (1 << j)) != 0) // Color lights
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
if ((uid_data.light_mask & (1 << (i + 8 * j))) != 0)
|
||||||
|
{
|
||||||
|
generate_lighting(out, uid_data, i, j, j, light_count, false);
|
||||||
|
light_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out->Write("\tcustom_data.light_chan{}_color_count = {};\n", j, light_count);
|
||||||
|
|
||||||
|
light_count = 0;
|
||||||
|
if ((uid_data.enablelighting & (1 << (j + 2))) != 0) // Alpha lights
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
if ((uid_data.light_mask & (1 << (i + 8 * (j + 2)))) != 0)
|
||||||
|
{
|
||||||
|
generate_lighting(out, uid_data, i, j + 2, j, light_count, true);
|
||||||
|
light_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out->Write("\tcustom_data.light_chan{}_alpha_count = {};\n", j, light_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -47,3 +47,7 @@ constexpr char s_lighting_struct[] = "struct Light {\n"
|
||||||
void GenerateLightingShaderCode(ShaderCode& object, const LightingUidData& uid_data,
|
void GenerateLightingShaderCode(ShaderCode& object, const LightingUidData& uid_data,
|
||||||
std::string_view in_color_name, std::string_view dest);
|
std::string_view in_color_name, std::string_view dest);
|
||||||
void GetLightingShaderUid(LightingUidData& uid_data);
|
void GetLightingShaderUid(LightingUidData& uid_data);
|
||||||
|
|
||||||
|
void GenerateCustomLightingHeaderDetails(ShaderCode* out, u32 enablelighting, u32 light_mask);
|
||||||
|
void GenerateCustomLightingImplementation(ShaderCode* out, const LightingUidData& uid_data,
|
||||||
|
std::string_view in_color_name);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "VideoCommon/PixelShaderGen.h"
|
#include "VideoCommon/PixelShaderGen.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
@ -130,6 +131,17 @@ constexpr Common::EnumMap<const char*, TevColorArg::Zero> tev_c_input_table{
|
||||||
"int3(0,0,0)", // ZERO
|
"int3(0,0,0)", // ZERO
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr Common::EnumMap<const char*, TevColorArg::Zero> tev_c_input_type{
|
||||||
|
"CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_PREV", "CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_PREV",
|
||||||
|
"CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR", "CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR",
|
||||||
|
"CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR", "CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR",
|
||||||
|
"CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR", "CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR",
|
||||||
|
"CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_TEX", "CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_TEX",
|
||||||
|
"CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_RAS", "CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_RAS",
|
||||||
|
"CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_NUMERIC", "CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_NUMERIC",
|
||||||
|
"CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_KONST", "CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_NUMERIC",
|
||||||
|
};
|
||||||
|
|
||||||
constexpr Common::EnumMap<const char*, TevAlphaArg::Zero> tev_a_input_table{
|
constexpr Common::EnumMap<const char*, TevAlphaArg::Zero> tev_a_input_table{
|
||||||
"prev.a", // APREV,
|
"prev.a", // APREV,
|
||||||
"c0.a", // A0,
|
"c0.a", // A0,
|
||||||
|
@ -141,6 +153,13 @@ constexpr Common::EnumMap<const char*, TevAlphaArg::Zero> tev_a_input_table{
|
||||||
"0", // ZERO
|
"0", // ZERO
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr Common::EnumMap<const char*, TevAlphaArg::Zero> tev_a_input_type{
|
||||||
|
"CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_PREV", "CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR",
|
||||||
|
"CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR", "CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR",
|
||||||
|
"CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_TEX", "CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_RAS",
|
||||||
|
"CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_KONST", "CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_NUMERIC",
|
||||||
|
};
|
||||||
|
|
||||||
constexpr Common::EnumMap<const char*, RasColorChan::Zero> tev_ras_table{
|
constexpr Common::EnumMap<const char*, RasColorChan::Zero> tev_ras_table{
|
||||||
"iround(col0 * 255.0)",
|
"iround(col0 * 255.0)",
|
||||||
"iround(col1 * 255.0)",
|
"iround(col1 * 255.0)",
|
||||||
|
@ -387,6 +406,7 @@ void WritePixelShaderCommonHeader(ShaderCode& out, APIType api_type,
|
||||||
"\tbool blend_subtract_alpha;\n"
|
"\tbool blend_subtract_alpha;\n"
|
||||||
"\tbool logic_op_enable;\n"
|
"\tbool logic_op_enable;\n"
|
||||||
"\tuint logic_op_mode;\n"
|
"\tuint logic_op_mode;\n"
|
||||||
|
"\tuint time_ms;\n"
|
||||||
"}};\n\n");
|
"}};\n\n");
|
||||||
out.Write("#define bpmem_combiners(i) (bpmem_pack1[(i)].xy)\n"
|
out.Write("#define bpmem_combiners(i) (bpmem_pack1[(i)].xy)\n"
|
||||||
"#define bpmem_tevind(i) (bpmem_pack1[(i)].z)\n"
|
"#define bpmem_tevind(i) (bpmem_pack1[(i)].z)\n"
|
||||||
|
@ -732,8 +752,131 @@ uint WrapCoord(int coord, uint wrap, int size) {{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WriteCustomShaderStructImpl(ShaderCode* out, u32 num_stages, bool per_pixel_lighting,
|
||||||
|
const pixel_shader_uid_data* uid_data)
|
||||||
|
{
|
||||||
|
out->Write("\tCustomShaderData custom_data;\n");
|
||||||
|
|
||||||
|
if (per_pixel_lighting)
|
||||||
|
{
|
||||||
|
out->Write("\tcustom_data.position = WorldPos;\n");
|
||||||
|
out->Write("\tcustom_data.normal = Normal;\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out->Write("\tcustom_data.position = float3(0, 0, 0);\n");
|
||||||
|
out->Write("\tcustom_data.normal = float3(0, 0, 0);\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uid_data->genMode_numtexgens == 0) [[unlikely]]
|
||||||
|
{
|
||||||
|
out->Write("\tcustom_data.texcoord[0] = float3(0, 0, 0);\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < uid_data->genMode_numtexgens; ++i)
|
||||||
|
{
|
||||||
|
out->Write("\tif (tex{0}.z == 0.0)\n", i);
|
||||||
|
out->Write("\t{{\n");
|
||||||
|
out->Write("\t\tcustom_data.texcoord[{0}] = tex{0};\n", i);
|
||||||
|
out->Write("\t}}\n");
|
||||||
|
out->Write("\telse {{\n");
|
||||||
|
out->Write("\t\tcustom_data.texcoord[{0}] = float3(tex{0}.xy / tex{0}.z, 0);\n", i);
|
||||||
|
out->Write("\t}}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
// Shader compilation complains if every index isn't initialized
|
||||||
|
out->Write("\tcustom_data.texmap_to_texcoord_index[{0}] = 0;\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = 0; i < uid_data->genMode_numindstages; ++i)
|
||||||
|
{
|
||||||
|
if ((uid_data->nIndirectStagesUsed & (1U << i)) != 0)
|
||||||
|
{
|
||||||
|
u32 texcoord = uid_data->GetTevindirefCoord(i);
|
||||||
|
const u32 texmap = uid_data->GetTevindirefMap(i);
|
||||||
|
|
||||||
|
// Quirk: when the tex coord is not less than the number of tex gens (i.e. the tex coord does
|
||||||
|
// not exist), then tex coord 0 is used (though sometimes glitchy effects happen on console).
|
||||||
|
// This affects the Mario portrait in Luigi's Mansion, where the developers forgot to set
|
||||||
|
// the number of tex gens to 2 (bug 11462).
|
||||||
|
if (texcoord >= uid_data->genMode_numtexgens)
|
||||||
|
texcoord = 0;
|
||||||
|
|
||||||
|
out->Write("\tcustom_data.texmap_to_texcoord_index[{}] = {};\n", texmap, texcoord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out->Write("\tcustom_data.texcoord_count = {};\n", uid_data->genMode_numtexgens);
|
||||||
|
|
||||||
|
// Try and do a best guess on what the texcoord index is
|
||||||
|
// Note: one issue with this would be textures that are used
|
||||||
|
// multiple times in the same draw but with different texture coordinates.
|
||||||
|
// In that scenario, only the last texture coordinate would be defined.
|
||||||
|
// This issue can be seen in how Rogue Squadron 2 does bump mapping
|
||||||
|
for (u32 i = 0; i < num_stages; i++)
|
||||||
|
{
|
||||||
|
auto& tevstage = uid_data->stagehash[i];
|
||||||
|
// Quirk: when the tex coord is not less than the number of tex gens (i.e. the tex coord does
|
||||||
|
// not exist), then tex coord 0 is used (though sometimes glitchy effects happen on console).
|
||||||
|
u32 texcoord = tevstage.tevorders_texcoord;
|
||||||
|
const bool has_tex_coord = texcoord < uid_data->genMode_numtexgens;
|
||||||
|
if (!has_tex_coord)
|
||||||
|
texcoord = 0;
|
||||||
|
|
||||||
|
out->Write("\tcustom_data.texmap_to_texcoord_index[{}] = {};\n", tevstage.tevorders_texmap,
|
||||||
|
texcoord);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenerateCustomLightingImplementation(out, uid_data->lighting, "colors_");
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
// Shader compilation complains if every struct isn't initialized
|
||||||
|
|
||||||
|
// Color Input
|
||||||
|
for (u32 j = 0; j < 4; j++)
|
||||||
|
{
|
||||||
|
out->Write("\tcustom_data.tev_stages[{}].input_color[{}].input_type = "
|
||||||
|
"CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_UNUSED;\n",
|
||||||
|
i, j);
|
||||||
|
out->Write("\tcustom_data.tev_stages[{}].input_color[{}].value = "
|
||||||
|
"float3(0, 0, 0);\n",
|
||||||
|
i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alpha Input
|
||||||
|
for (u32 j = 0; j < 4; j++)
|
||||||
|
{
|
||||||
|
out->Write("\tcustom_data.tev_stages[{}].input_alpha[{}].input_type = "
|
||||||
|
"CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_UNUSED;\n",
|
||||||
|
i, j);
|
||||||
|
out->Write("\tcustom_data.tev_stages[{}].input_alpha[{}].value = "
|
||||||
|
"float(0);\n",
|
||||||
|
i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Texmap
|
||||||
|
out->Write("\tcustom_data.tev_stages[{}].texmap = 0u;\n", i);
|
||||||
|
|
||||||
|
// Output
|
||||||
|
out->Write("\tcustom_data.tev_stages[{}].output_color = "
|
||||||
|
"float4(0, 0, 0, 0);\n",
|
||||||
|
i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actual data will be filled out in the tev stage code, just set the
|
||||||
|
// stage count for now
|
||||||
|
out->Write("\tcustom_data.tev_stage_count = {};\n", num_stages);
|
||||||
|
|
||||||
|
// Time
|
||||||
|
out->Write("\tcustom_data.time_ms = time_ms;\n");
|
||||||
|
}
|
||||||
|
|
||||||
static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n,
|
static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n,
|
||||||
APIType api_type, bool stereo);
|
APIType api_type, bool stereo, bool has_custom_shaders);
|
||||||
static void WriteTevRegular(ShaderCode& out, std::string_view components, TevBias bias, TevOp op,
|
static void WriteTevRegular(ShaderCode& out, std::string_view components, TevBias bias, TevOp op,
|
||||||
bool clamp, TevScale scale);
|
bool clamp, TevScale scale);
|
||||||
static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_data, APIType api_type,
|
static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_data, APIType api_type,
|
||||||
|
@ -746,7 +889,8 @@ static void WriteColor(ShaderCode& out, APIType api_type, const pixel_shader_uid
|
||||||
static void WriteBlend(ShaderCode& out, const pixel_shader_uid_data* uid_data);
|
static void WriteBlend(ShaderCode& out, const pixel_shader_uid_data* uid_data);
|
||||||
|
|
||||||
ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& host_config,
|
ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
const pixel_shader_uid_data* uid_data)
|
const pixel_shader_uid_data* uid_data,
|
||||||
|
const CustomPixelShaderContents& custom_details)
|
||||||
{
|
{
|
||||||
ShaderCode out;
|
ShaderCode out;
|
||||||
|
|
||||||
|
@ -762,8 +906,17 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
|
||||||
|
|
||||||
// Stuff that is shared between ubershaders and pixelgen.
|
// Stuff that is shared between ubershaders and pixelgen.
|
||||||
WriteBitfieldExtractHeader(out, api_type, host_config);
|
WriteBitfieldExtractHeader(out, api_type, host_config);
|
||||||
|
|
||||||
WritePixelShaderCommonHeader(out, api_type, host_config, uid_data->bounding_box);
|
WritePixelShaderCommonHeader(out, api_type, host_config, uid_data->bounding_box);
|
||||||
|
|
||||||
|
// Custom shader details
|
||||||
|
WriteCustomShaderStructDef(&out, uid_data->genMode_numtexgens);
|
||||||
|
for (std::size_t i = 0; i < custom_details.shaders.size(); i++)
|
||||||
|
{
|
||||||
|
const auto& shader_details = custom_details.shaders[i];
|
||||||
|
out.Write(fmt::runtime(shader_details.custom_shader), i);
|
||||||
|
}
|
||||||
|
|
||||||
out.Write("\n#define sampleTextureWrapper(texmap, uv, layer) "
|
out.Write("\n#define sampleTextureWrapper(texmap, uv, layer) "
|
||||||
"sampleTexture(texmap, samp[texmap], uv, layer)\n");
|
"sampleTexture(texmap, samp[texmap], uv, layer)\n");
|
||||||
|
|
||||||
|
@ -892,6 +1045,14 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
|
||||||
out.Write("void main()\n{{\n");
|
out.Write("void main()\n{{\n");
|
||||||
out.Write("\tfloat4 rawpos = gl_FragCoord;\n");
|
out.Write("\tfloat4 rawpos = gl_FragCoord;\n");
|
||||||
|
|
||||||
|
bool has_custom_shaders = false;
|
||||||
|
if (std::any_of(custom_details.shaders.begin(), custom_details.shaders.end(),
|
||||||
|
[](const std::optional<CustomPixelShader>& ps) { return ps.has_value(); }))
|
||||||
|
{
|
||||||
|
WriteCustomShaderStructImpl(&out, numStages, per_pixel_lighting, uid_data);
|
||||||
|
has_custom_shaders = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (use_framebuffer_fetch)
|
if (use_framebuffer_fetch)
|
||||||
{
|
{
|
||||||
// Store off a copy of the initial framebuffer value.
|
// Store off a copy of the initial framebuffer value.
|
||||||
|
@ -1013,7 +1174,7 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
|
||||||
for (u32 i = 0; i < numStages; i++)
|
for (u32 i = 0; i < numStages; i++)
|
||||||
{
|
{
|
||||||
// Build the equation for this stage
|
// Build the equation for this stage
|
||||||
WriteStage(out, uid_data, i, api_type, stereo);
|
WriteStage(out, uid_data, i, api_type, stereo, has_custom_shaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1146,7 +1307,21 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
|
||||||
|
|
||||||
// Write the color and alpha values to the framebuffer
|
// Write the color and alpha values to the framebuffer
|
||||||
// If using shader blend, we still use the separate alpha
|
// If using shader blend, we still use the separate alpha
|
||||||
WriteColor(out, api_type, uid_data, !uid_data->no_dual_src || uid_data->blend_enable);
|
const bool use_dual_source = !uid_data->no_dual_src || uid_data->blend_enable;
|
||||||
|
WriteColor(out, api_type, uid_data, use_dual_source);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < custom_details.shaders.size(); i++)
|
||||||
|
{
|
||||||
|
const auto& shader_details = custom_details.shaders[i];
|
||||||
|
|
||||||
|
if (!shader_details.custom_shader.empty())
|
||||||
|
{
|
||||||
|
out.Write("\t{{\n");
|
||||||
|
out.Write("\t\tcustom_data.final_color = ocol0;\n");
|
||||||
|
out.Write("\t\tocol0.xyz = {}_{}(custom_data).xyz;\n", CUSTOM_PIXELSHADER_COLOR_FUNC, i);
|
||||||
|
out.Write("\t}}\n\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (uid_data->blend_enable)
|
if (uid_data->blend_enable)
|
||||||
WriteBlend(out, uid_data);
|
WriteBlend(out, uid_data);
|
||||||
|
@ -1162,7 +1337,7 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n,
|
static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n,
|
||||||
APIType api_type, bool stereo)
|
APIType api_type, bool stereo, bool has_custom_shaders)
|
||||||
{
|
{
|
||||||
using Common::EnumMap;
|
using Common::EnumMap;
|
||||||
|
|
||||||
|
@ -1556,6 +1731,58 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
|
||||||
out.Write(", -1024, 1023)");
|
out.Write(", -1024, 1023)");
|
||||||
|
|
||||||
out.Write(";\n");
|
out.Write(";\n");
|
||||||
|
|
||||||
|
if (has_custom_shaders)
|
||||||
|
{
|
||||||
|
// Color input
|
||||||
|
out.Write(
|
||||||
|
"\tcustom_data.tev_stages[{}].input_color[0].value = {} / float3(255.0, 255.0, 255.0);\n",
|
||||||
|
n, tev_c_input_table[cc.a]);
|
||||||
|
out.Write("\tcustom_data.tev_stages[{}].input_color[0].input_type = {};\n", n,
|
||||||
|
tev_c_input_type[cc.a]);
|
||||||
|
out.Write(
|
||||||
|
"\tcustom_data.tev_stages[{}].input_color[1].value = {} / float3(255.0, 255.0, 255.0);\n",
|
||||||
|
n, tev_c_input_table[cc.b]);
|
||||||
|
out.Write("\tcustom_data.tev_stages[{}].input_color[1].input_type = {};\n", n,
|
||||||
|
tev_c_input_type[cc.b]);
|
||||||
|
out.Write(
|
||||||
|
"\tcustom_data.tev_stages[{}].input_color[2].value = {} / float3(255.0, 255.0, 255.0);\n",
|
||||||
|
n, tev_c_input_table[cc.c]);
|
||||||
|
out.Write("\tcustom_data.tev_stages[{}].input_color[2].input_type = {};\n", n,
|
||||||
|
tev_c_input_type[cc.c]);
|
||||||
|
out.Write(
|
||||||
|
"\tcustom_data.tev_stages[{}].input_color[3].value = {} / float3(255.0, 255.0, 255.0);\n",
|
||||||
|
n, tev_c_input_table[cc.d]);
|
||||||
|
out.Write("\tcustom_data.tev_stages[{}].input_color[3].input_type = {};\n", n,
|
||||||
|
tev_c_input_type[cc.d]);
|
||||||
|
|
||||||
|
// Alpha input
|
||||||
|
out.Write("\tcustom_data.tev_stages[{}].input_alpha[0].value = {} / float(255.0);\n", n,
|
||||||
|
tev_a_input_table[ac.a]);
|
||||||
|
out.Write("\tcustom_data.tev_stages[{}].input_alpha[0].input_type = {};\n", n,
|
||||||
|
tev_a_input_type[ac.a]);
|
||||||
|
out.Write("\tcustom_data.tev_stages[{}].input_alpha[1].value = {} / float(255.0);\n", n,
|
||||||
|
tev_a_input_table[ac.b]);
|
||||||
|
out.Write("\tcustom_data.tev_stages[{}].input_alpha[1].input_type = {};\n", n,
|
||||||
|
tev_a_input_type[ac.b]);
|
||||||
|
out.Write("\tcustom_data.tev_stages[{}].input_alpha[2].value = {} / float(255.0);\n", n,
|
||||||
|
tev_a_input_table[ac.c]);
|
||||||
|
out.Write("\tcustom_data.tev_stages[{}].input_alpha[2].input_type = {};\n", n,
|
||||||
|
tev_a_input_type[ac.c]);
|
||||||
|
out.Write("\tcustom_data.tev_stages[{}].input_alpha[3].value = {} / float(255.0);\n", n,
|
||||||
|
tev_a_input_table[ac.d]);
|
||||||
|
out.Write("\tcustom_data.tev_stages[{}].input_alpha[3].input_type = {};\n", n,
|
||||||
|
tev_a_input_type[ac.d]);
|
||||||
|
|
||||||
|
// Texmap
|
||||||
|
out.Write("\tcustom_data.tev_stages[{}].texmap = {}u;\n", n, stage.tevorders_texmap);
|
||||||
|
|
||||||
|
// Output
|
||||||
|
out.Write("\tcustom_data.tev_stages[{}].output_color.rgb = {} / float3(255.0, 255.0, 255.0);\n",
|
||||||
|
n, tev_c_output_table[cc.dest]);
|
||||||
|
out.Write("\tcustom_data.tev_stages[{}].output_color.a = {} / float(255.0);\n", n,
|
||||||
|
tev_a_output_table[ac.dest]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteTevRegular(ShaderCode& out, std::string_view components, TevBias bias, TevOp op,
|
static void WriteTevRegular(ShaderCode& out, std::string_view components, TevBias bias, TevOp op,
|
||||||
|
|
|
@ -158,8 +158,12 @@ struct pixel_shader_uid_data
|
||||||
|
|
||||||
using PixelShaderUid = ShaderUid<pixel_shader_uid_data>;
|
using PixelShaderUid = ShaderUid<pixel_shader_uid_data>;
|
||||||
|
|
||||||
ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& host_config,
|
void WriteCustomShaderStructImpl(ShaderCode* out, u32 num_stages, bool per_pixel_lighting,
|
||||||
const pixel_shader_uid_data* uid_data);
|
const pixel_shader_uid_data* uid_data);
|
||||||
|
|
||||||
|
ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
|
const pixel_shader_uid_data* uid_data,
|
||||||
|
const CustomPixelShaderContents& custom_details);
|
||||||
void WritePixelShaderCommonHeader(ShaderCode& out, APIType api_type,
|
void WritePixelShaderCommonHeader(ShaderCode& out, APIType api_type,
|
||||||
const ShaderHostConfig& host_config, bool bounding_box);
|
const ShaderHostConfig& host_config, bool bounding_box);
|
||||||
void ClearUnusedPixelShaderUidBits(APIType api_type, const ShaderHostConfig& host_config,
|
void ClearUnusedPixelShaderUidBits(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
|
|
|
@ -419,9 +419,9 @@ std::vector<std::string> PostProcessing::GetPassiveShaderList()
|
||||||
bool PostProcessing::Initialize(AbstractTextureFormat format)
|
bool PostProcessing::Initialize(AbstractTextureFormat format)
|
||||||
{
|
{
|
||||||
m_framebuffer_format = format;
|
m_framebuffer_format = format;
|
||||||
// CompilePixelShader must be run first if configuration options are used.
|
// CompilePixelShader() must be run first if configuration options are used.
|
||||||
// Otherwise the UBO has a different member list between vertex and pixel
|
// Otherwise the UBO has a different member list between vertex and pixel
|
||||||
// shaders, which is a link error.
|
// shaders, which is a link error on some backends.
|
||||||
if (!CompilePixelShader() || !CompileVertexShader() || !CompilePipeline())
|
if (!CompilePixelShader() || !CompileVertexShader() || !CompilePipeline())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -486,23 +486,29 @@ void PostProcessing::BlitFromTexture(const MathUtil::Rectangle<int>& dst,
|
||||||
|
|
||||||
MathUtil::Rectangle<int> src_rect = src;
|
MathUtil::Rectangle<int> src_rect = src;
|
||||||
g_gfx->SetSamplerState(0, RenderState::GetLinearSamplerState());
|
g_gfx->SetSamplerState(0, RenderState::GetLinearSamplerState());
|
||||||
|
g_gfx->SetSamplerState(1, RenderState::GetPointSamplerState());
|
||||||
g_gfx->SetTexture(0, src_tex);
|
g_gfx->SetTexture(0, src_tex);
|
||||||
|
g_gfx->SetTexture(1, src_tex);
|
||||||
|
|
||||||
const bool is_color_correction_active = IsColorCorrectionActive();
|
const bool needs_color_correction = IsColorCorrectionActive();
|
||||||
|
// Rely on the default (bi)linear sampler with the default mode
|
||||||
|
// (it might not be gamma corrected).
|
||||||
|
const bool needs_resampling =
|
||||||
|
g_ActiveConfig.output_resampling_mode > OutputResamplingMode::Default;
|
||||||
const bool needs_intermediary_buffer = NeedsIntermediaryBuffer();
|
const bool needs_intermediary_buffer = NeedsIntermediaryBuffer();
|
||||||
|
const bool needs_default_pipeline = needs_color_correction || needs_resampling;
|
||||||
const AbstractPipeline* final_pipeline = m_pipeline.get();
|
const AbstractPipeline* final_pipeline = m_pipeline.get();
|
||||||
std::vector<u8>* uniform_staging_buffer = &m_default_uniform_staging_buffer;
|
std::vector<u8>* uniform_staging_buffer = &m_default_uniform_staging_buffer;
|
||||||
bool default_uniform_staging_buffer = true;
|
bool default_uniform_staging_buffer = true;
|
||||||
|
const MathUtil::Rectangle<int> present_rect = g_presenter->GetTargetRectangle();
|
||||||
|
|
||||||
// Intermediary pass.
|
// Intermediary pass.
|
||||||
// We draw to a high quality intermediary texture for two reasons:
|
// We draw to a high quality intermediary texture for a couple reasons:
|
||||||
|
// -Consistently do high quality gamma corrected resampling (upscaling/downscaling)
|
||||||
// -Keep quality for gamma and gamut conversions, and HDR output
|
// -Keep quality for gamma and gamut conversions, and HDR output
|
||||||
// (low bit depths lose too much quality with gamma conversions)
|
// (low bit depths lose too much quality with gamma conversions)
|
||||||
// -We make a texture of the exact same res as the source one,
|
// -Keep the post process phase in linear space, to better operate with colors
|
||||||
// because all the post process shaders we already had assume that
|
if (m_default_pipeline && needs_default_pipeline && needs_intermediary_buffer)
|
||||||
// the source texture size (EFB) is different from the swap chain
|
|
||||||
// texture size (which matches the window size).
|
|
||||||
if (m_default_pipeline && is_color_correction_active && needs_intermediary_buffer)
|
|
||||||
{
|
{
|
||||||
AbstractFramebuffer* const previous_framebuffer = g_gfx->GetCurrentFramebuffer();
|
AbstractFramebuffer* const previous_framebuffer = g_gfx->GetCurrentFramebuffer();
|
||||||
|
|
||||||
|
@ -512,13 +518,18 @@ void PostProcessing::BlitFromTexture(const MathUtil::Rectangle<int>& dst,
|
||||||
// so it would be a waste to allocate two layers (see "bUsesExplictQuadBuffering").
|
// so it would be a waste to allocate two layers (see "bUsesExplictQuadBuffering").
|
||||||
const u32 target_layers = copy_all_layers ? src_tex->GetLayers() : 1;
|
const u32 target_layers = copy_all_layers ? src_tex->GetLayers() : 1;
|
||||||
|
|
||||||
|
const u32 target_width =
|
||||||
|
needs_resampling ? present_rect.GetWidth() : static_cast<u32>(src_rect.GetWidth());
|
||||||
|
const u32 target_height =
|
||||||
|
needs_resampling ? present_rect.GetHeight() : static_cast<u32>(src_rect.GetHeight());
|
||||||
|
|
||||||
if (!m_intermediary_frame_buffer || !m_intermediary_color_texture ||
|
if (!m_intermediary_frame_buffer || !m_intermediary_color_texture ||
|
||||||
m_intermediary_color_texture.get()->GetWidth() != static_cast<u32>(src_rect.GetWidth()) ||
|
m_intermediary_color_texture.get()->GetWidth() != target_width ||
|
||||||
m_intermediary_color_texture.get()->GetHeight() != static_cast<u32>(src_rect.GetHeight()) ||
|
m_intermediary_color_texture.get()->GetHeight() != target_height ||
|
||||||
m_intermediary_color_texture.get()->GetLayers() != target_layers)
|
m_intermediary_color_texture.get()->GetLayers() != target_layers)
|
||||||
{
|
{
|
||||||
const TextureConfig intermediary_color_texture_config(
|
const TextureConfig intermediary_color_texture_config(
|
||||||
src_rect.GetWidth(), src_rect.GetHeight(), 1, target_layers, src_tex->GetSamples(),
|
target_width, target_height, 1, target_layers, src_tex->GetSamples(),
|
||||||
s_intermediary_buffer_format, AbstractTextureFlag_RenderTarget);
|
s_intermediary_buffer_format, AbstractTextureFlag_RenderTarget);
|
||||||
m_intermediary_color_texture = g_gfx->CreateTexture(intermediary_color_texture_config,
|
m_intermediary_color_texture = g_gfx->CreateTexture(intermediary_color_texture_config,
|
||||||
"Intermediary post process texture");
|
"Intermediary post process texture");
|
||||||
|
@ -530,8 +541,8 @@ void PostProcessing::BlitFromTexture(const MathUtil::Rectangle<int>& dst,
|
||||||
g_gfx->SetFramebuffer(m_intermediary_frame_buffer.get());
|
g_gfx->SetFramebuffer(m_intermediary_frame_buffer.get());
|
||||||
|
|
||||||
FillUniformBuffer(src_rect, src_tex, src_layer, g_gfx->GetCurrentFramebuffer()->GetRect(),
|
FillUniformBuffer(src_rect, src_tex, src_layer, g_gfx->GetCurrentFramebuffer()->GetRect(),
|
||||||
g_presenter->GetTargetRectangle(), uniform_staging_buffer->data(),
|
present_rect, uniform_staging_buffer->data(), !default_uniform_staging_buffer,
|
||||||
!default_uniform_staging_buffer);
|
true);
|
||||||
g_vertex_manager->UploadUtilityUniforms(uniform_staging_buffer->data(),
|
g_vertex_manager->UploadUtilityUniforms(uniform_staging_buffer->data(),
|
||||||
static_cast<u32>(uniform_staging_buffer->size()));
|
static_cast<u32>(uniform_staging_buffer->size()));
|
||||||
|
|
||||||
|
@ -544,6 +555,7 @@ void PostProcessing::BlitFromTexture(const MathUtil::Rectangle<int>& dst,
|
||||||
src_rect = m_intermediary_color_texture->GetRect();
|
src_rect = m_intermediary_color_texture->GetRect();
|
||||||
src_tex = m_intermediary_color_texture.get();
|
src_tex = m_intermediary_color_texture.get();
|
||||||
g_gfx->SetTexture(0, src_tex);
|
g_gfx->SetTexture(0, src_tex);
|
||||||
|
g_gfx->SetTexture(1, src_tex);
|
||||||
// The "m_intermediary_color_texture" has already copied
|
// The "m_intermediary_color_texture" has already copied
|
||||||
// from the specified source layer onto its first one.
|
// from the specified source layer onto its first one.
|
||||||
// If we query for a layer that the source texture doesn't have,
|
// If we query for a layer that the source texture doesn't have,
|
||||||
|
@ -557,7 +569,7 @@ void PostProcessing::BlitFromTexture(const MathUtil::Rectangle<int>& dst,
|
||||||
// If we have no custom user shader selected, and color correction
|
// If we have no custom user shader selected, and color correction
|
||||||
// is active, directly run the fixed pipeline shader instead of
|
// is active, directly run the fixed pipeline shader instead of
|
||||||
// doing two passes, with the second one doing nothing useful.
|
// doing two passes, with the second one doing nothing useful.
|
||||||
if (m_default_pipeline && is_color_correction_active)
|
if (m_default_pipeline && needs_default_pipeline)
|
||||||
{
|
{
|
||||||
final_pipeline = m_default_pipeline.get();
|
final_pipeline = m_default_pipeline.get();
|
||||||
}
|
}
|
||||||
|
@ -580,8 +592,8 @@ void PostProcessing::BlitFromTexture(const MathUtil::Rectangle<int>& dst,
|
||||||
if (final_pipeline)
|
if (final_pipeline)
|
||||||
{
|
{
|
||||||
FillUniformBuffer(src_rect, src_tex, src_layer, g_gfx->GetCurrentFramebuffer()->GetRect(),
|
FillUniformBuffer(src_rect, src_tex, src_layer, g_gfx->GetCurrentFramebuffer()->GetRect(),
|
||||||
g_presenter->GetTargetRectangle(), uniform_staging_buffer->data(),
|
present_rect, uniform_staging_buffer->data(), !default_uniform_staging_buffer,
|
||||||
!default_uniform_staging_buffer);
|
false);
|
||||||
g_vertex_manager->UploadUtilityUniforms(uniform_staging_buffer->data(),
|
g_vertex_manager->UploadUtilityUniforms(uniform_staging_buffer->data(),
|
||||||
static_cast<u32>(uniform_staging_buffer->size()));
|
static_cast<u32>(uniform_staging_buffer->size()));
|
||||||
|
|
||||||
|
@ -609,7 +621,11 @@ std::string PostProcessing::GetUniformBufferHeader(bool user_post_process) const
|
||||||
// The first (but not necessarily only) source layer we target
|
// The first (but not necessarily only) source layer we target
|
||||||
ss << " int src_layer;\n";
|
ss << " int src_layer;\n";
|
||||||
ss << " uint time;\n";
|
ss << " uint time;\n";
|
||||||
|
ss << " int graphics_api;\n";
|
||||||
|
// If true, it's an intermediary buffer (including the first), if false, it's the final one
|
||||||
|
ss << " int intermediary_buffer;\n";
|
||||||
|
|
||||||
|
ss << " int resampling_method;\n";
|
||||||
ss << " int correct_color_space;\n";
|
ss << " int correct_color_space;\n";
|
||||||
ss << " int game_color_space;\n";
|
ss << " int game_color_space;\n";
|
||||||
ss << " int correct_gamma;\n";
|
ss << " int correct_gamma;\n";
|
||||||
|
@ -742,6 +758,7 @@ void SetOutput(float4 color)
|
||||||
|
|
||||||
#define GetOption(x) (x)
|
#define GetOption(x) (x)
|
||||||
#define OptionEnabled(x) ((x) != 0)
|
#define OptionEnabled(x) ((x) != 0)
|
||||||
|
#define OptionDisabled(x) ((x) == 0)
|
||||||
|
|
||||||
)";
|
)";
|
||||||
return ss.str();
|
return ss.str();
|
||||||
|
@ -752,13 +769,9 @@ std::string PostProcessing::GetFooter() const
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PostProcessing::CompileVertexShader()
|
std::string GetVertexShaderBody()
|
||||||
{
|
{
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
// We never need the user selected post process custom uniforms in the vertex shader
|
|
||||||
const bool user_post_process = false;
|
|
||||||
ss << GetUniformBufferHeader(user_post_process);
|
|
||||||
|
|
||||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||||
{
|
{
|
||||||
ss << "VARYING_LOCATION(0) out VertexData {\n";
|
ss << "VARYING_LOCATION(0) out VertexData {\n";
|
||||||
|
@ -779,21 +792,34 @@ bool PostProcessing::CompileVertexShader()
|
||||||
|
|
||||||
// Vulkan Y needs to be inverted on every pass
|
// Vulkan Y needs to be inverted on every pass
|
||||||
if (g_ActiveConfig.backend_info.api_type == APIType::Vulkan)
|
if (g_ActiveConfig.backend_info.api_type == APIType::Vulkan)
|
||||||
|
{
|
||||||
ss << " opos.y = -opos.y;\n";
|
ss << " opos.y = -opos.y;\n";
|
||||||
|
}
|
||||||
std::string s2 = ss.str();
|
// OpenGL Y needs to be inverted in all passes except the last one
|
||||||
s2 += "}\n";
|
else if (g_ActiveConfig.backend_info.api_type == APIType::OpenGL)
|
||||||
m_default_vertex_shader = g_gfx->CreateShaderFromSource(ShaderStage::Vertex, s2,
|
{
|
||||||
"Default post-processing vertex shader");
|
ss << " if (intermediary_buffer != 0)\n";
|
||||||
|
|
||||||
// OpenGL Y needs to be inverted once only (in the last pass)
|
|
||||||
if (g_ActiveConfig.backend_info.api_type == APIType::OpenGL)
|
|
||||||
ss << " opos.y = -opos.y;\n";
|
ss << " opos.y = -opos.y;\n";
|
||||||
|
}
|
||||||
|
|
||||||
ss << "}\n";
|
ss << "}\n";
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PostProcessing::CompileVertexShader()
|
||||||
|
{
|
||||||
|
std::ostringstream ss_default;
|
||||||
|
ss_default << GetUniformBufferHeader(false);
|
||||||
|
ss_default << GetVertexShaderBody();
|
||||||
|
m_default_vertex_shader = g_gfx->CreateShaderFromSource(ShaderStage::Vertex, ss_default.str(),
|
||||||
|
"Default post-processing vertex shader");
|
||||||
|
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << GetUniformBufferHeader(true);
|
||||||
|
ss << GetVertexShaderBody();
|
||||||
m_vertex_shader =
|
m_vertex_shader =
|
||||||
g_gfx->CreateShaderFromSource(ShaderStage::Vertex, ss.str(), "Post-processing vertex shader");
|
g_gfx->CreateShaderFromSource(ShaderStage::Vertex, ss.str(), "Post-processing vertex shader");
|
||||||
|
|
||||||
if (!m_default_vertex_shader || !m_vertex_shader)
|
if (!m_default_vertex_shader || !m_vertex_shader)
|
||||||
{
|
{
|
||||||
PanicAlertFmt("Failed to compile post-processing vertex shader");
|
PanicAlertFmt("Failed to compile post-processing vertex shader");
|
||||||
|
@ -816,6 +842,9 @@ struct BuiltinUniforms
|
||||||
std::array<float, 4> src_rect;
|
std::array<float, 4> src_rect;
|
||||||
s32 src_layer;
|
s32 src_layer;
|
||||||
u32 time;
|
u32 time;
|
||||||
|
s32 graphics_api;
|
||||||
|
s32 intermediary_buffer;
|
||||||
|
s32 resampling_method;
|
||||||
s32 correct_color_space;
|
s32 correct_color_space;
|
||||||
s32 game_color_space;
|
s32 game_color_space;
|
||||||
s32 correct_gamma;
|
s32 correct_gamma;
|
||||||
|
@ -839,7 +868,7 @@ void PostProcessing::FillUniformBuffer(const MathUtil::Rectangle<int>& src,
|
||||||
const AbstractTexture* src_tex, int src_layer,
|
const AbstractTexture* src_tex, int src_layer,
|
||||||
const MathUtil::Rectangle<int>& dst,
|
const MathUtil::Rectangle<int>& dst,
|
||||||
const MathUtil::Rectangle<int>& wnd, u8* buffer,
|
const MathUtil::Rectangle<int>& wnd, u8* buffer,
|
||||||
bool user_post_process)
|
bool user_post_process, bool intermediary_buffer)
|
||||||
{
|
{
|
||||||
const float rcp_src_width = 1.0f / src_tex->GetWidth();
|
const float rcp_src_width = 1.0f / src_tex->GetWidth();
|
||||||
const float rcp_src_height = 1.0f / src_tex->GetHeight();
|
const float rcp_src_height = 1.0f / src_tex->GetHeight();
|
||||||
|
@ -860,7 +889,10 @@ void PostProcessing::FillUniformBuffer(const MathUtil::Rectangle<int>& src,
|
||||||
static_cast<float>(src.GetHeight()) * rcp_src_height};
|
static_cast<float>(src.GetHeight()) * rcp_src_height};
|
||||||
builtin_uniforms.src_layer = static_cast<s32>(src_layer);
|
builtin_uniforms.src_layer = static_cast<s32>(src_layer);
|
||||||
builtin_uniforms.time = static_cast<u32>(m_timer.ElapsedMs());
|
builtin_uniforms.time = static_cast<u32>(m_timer.ElapsedMs());
|
||||||
|
builtin_uniforms.graphics_api = static_cast<s32>(g_ActiveConfig.backend_info.api_type);
|
||||||
|
builtin_uniforms.intermediary_buffer = static_cast<s32>(intermediary_buffer);
|
||||||
|
|
||||||
|
builtin_uniforms.resampling_method = static_cast<s32>(g_ActiveConfig.output_resampling_mode);
|
||||||
// Color correction related uniforms.
|
// Color correction related uniforms.
|
||||||
// These are mainly used by the "m_default_pixel_shader",
|
// These are mainly used by the "m_default_pixel_shader",
|
||||||
// but should also be accessible to all other shaders.
|
// but should also be accessible to all other shaders.
|
||||||
|
@ -883,6 +915,8 @@ void PostProcessing::FillUniformBuffer(const MathUtil::Rectangle<int>& src,
|
||||||
std::memcpy(buffer, &builtin_uniforms, sizeof(builtin_uniforms));
|
std::memcpy(buffer, &builtin_uniforms, sizeof(builtin_uniforms));
|
||||||
buffer += sizeof(builtin_uniforms);
|
buffer += sizeof(builtin_uniforms);
|
||||||
|
|
||||||
|
// Don't include the custom pp shader options if they are not necessary,
|
||||||
|
// having mismatching uniforms between different shaders can cause issues on some backends
|
||||||
if (!user_post_process)
|
if (!user_post_process)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1000,8 +1034,7 @@ bool PostProcessing::CompilePipeline()
|
||||||
const bool needs_intermediary_buffer = NeedsIntermediaryBuffer();
|
const bool needs_intermediary_buffer = NeedsIntermediaryBuffer();
|
||||||
|
|
||||||
AbstractPipelineConfig config = {};
|
AbstractPipelineConfig config = {};
|
||||||
config.vertex_shader =
|
config.vertex_shader = m_default_vertex_shader.get();
|
||||||
needs_intermediary_buffer ? m_vertex_shader.get() : m_default_vertex_shader.get();
|
|
||||||
// This geometry shader will take care of reading both layer 0 and 1 on the source texture,
|
// This geometry shader will take care of reading both layer 0 and 1 on the source texture,
|
||||||
// and writing to both layer 0 and 1 on the render target.
|
// and writing to both layer 0 and 1 on the render target.
|
||||||
config.geometry_shader = UseGeometryShaderForPostProcess(needs_intermediary_buffer) ?
|
config.geometry_shader = UseGeometryShaderForPostProcess(needs_intermediary_buffer) ?
|
||||||
|
@ -1018,7 +1051,7 @@ bool PostProcessing::CompilePipeline()
|
||||||
if (config.pixel_shader)
|
if (config.pixel_shader)
|
||||||
m_default_pipeline = g_gfx->CreatePipeline(config);
|
m_default_pipeline = g_gfx->CreatePipeline(config);
|
||||||
|
|
||||||
config.vertex_shader = m_default_vertex_shader.get();
|
config.vertex_shader = m_vertex_shader.get();
|
||||||
config.geometry_shader = UseGeometryShaderForPostProcess(false) ?
|
config.geometry_shader = UseGeometryShaderForPostProcess(false) ?
|
||||||
g_shader_cache->GetTexcoordGeometryShader() :
|
g_shader_cache->GetTexcoordGeometryShader() :
|
||||||
nullptr;
|
nullptr;
|
||||||
|
|
|
@ -124,7 +124,8 @@ protected:
|
||||||
size_t CalculateUniformsSize(bool user_post_process) const;
|
size_t CalculateUniformsSize(bool user_post_process) const;
|
||||||
void FillUniformBuffer(const MathUtil::Rectangle<int>& src, const AbstractTexture* src_tex,
|
void FillUniformBuffer(const MathUtil::Rectangle<int>& src, const AbstractTexture* src_tex,
|
||||||
int src_layer, const MathUtil::Rectangle<int>& dst,
|
int src_layer, const MathUtil::Rectangle<int>& dst,
|
||||||
const MathUtil::Rectangle<int>& wnd, u8* buffer, bool user_post_process);
|
const MathUtil::Rectangle<int>& wnd, u8* buffer, bool user_post_process,
|
||||||
|
bool intermediary_buffer);
|
||||||
|
|
||||||
// Timer for determining our time value
|
// Timer for determining our time value
|
||||||
Common::Timer m_timer;
|
Common::Timer m_timer;
|
||||||
|
|
|
@ -449,7 +449,7 @@ ShaderCache::CompileVertexUberShader(const UberShader::VertexShaderUid& uid) con
|
||||||
std::unique_ptr<AbstractShader> ShaderCache::CompilePixelShader(const PixelShaderUid& uid) const
|
std::unique_ptr<AbstractShader> ShaderCache::CompilePixelShader(const PixelShaderUid& uid) const
|
||||||
{
|
{
|
||||||
const ShaderCode source_code =
|
const ShaderCode source_code =
|
||||||
GeneratePixelShaderCode(m_api_type, m_host_config, uid.GetUidData());
|
GeneratePixelShaderCode(m_api_type, m_host_config, uid.GetUidData(), {});
|
||||||
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer());
|
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,7 +457,7 @@ std::unique_ptr<AbstractShader>
|
||||||
ShaderCache::CompilePixelUberShader(const UberShader::PixelShaderUid& uid) const
|
ShaderCache::CompilePixelUberShader(const UberShader::PixelShaderUid& uid) const
|
||||||
{
|
{
|
||||||
const ShaderCode source_code =
|
const ShaderCode source_code =
|
||||||
UberShader::GenPixelShader(m_api_type, m_host_config, uid.GetUidData());
|
UberShader::GenPixelShader(m_api_type, m_host_config, uid.GetUidData(), {});
|
||||||
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(),
|
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(),
|
||||||
fmt::to_string(*uid.GetUidData()));
|
fmt::to_string(*uid.GetUidData()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "VideoCommon/VideoCommon.h"
|
#include "VideoCommon/VideoCommon.h"
|
||||||
#include "VideoCommon/VideoConfig.h"
|
#include "VideoCommon/VideoConfig.h"
|
||||||
|
#include "VideoCommon/XFMemory.h"
|
||||||
|
|
||||||
ShaderHostConfig ShaderHostConfig::GetCurrent()
|
ShaderHostConfig ShaderHostConfig::GetCurrent()
|
||||||
{
|
{
|
||||||
|
@ -362,3 +363,90 @@ const char* GetInterpolationQualifier(bool msaa, bool ssaa, bool in_glsl_interfa
|
||||||
return "sample";
|
return "sample";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WriteCustomShaderStructDef(ShaderCode* out, u32 numtexgens)
|
||||||
|
{
|
||||||
|
// Bump this when there are breaking changes to the API
|
||||||
|
out->Write("#define CUSTOM_SHADER_API_VERSION 1;\n");
|
||||||
|
|
||||||
|
// CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE "enum" values
|
||||||
|
out->Write("const uint CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_NONE = {}u;\n",
|
||||||
|
static_cast<u32>(AttenuationFunc::None));
|
||||||
|
out->Write("const uint CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_POINT = {}u;\n",
|
||||||
|
static_cast<u32>(AttenuationFunc::Spec));
|
||||||
|
out->Write("const uint CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_DIR = {}u;\n",
|
||||||
|
static_cast<u32>(AttenuationFunc::Dir));
|
||||||
|
out->Write("const uint CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_SPOT = {}u;\n",
|
||||||
|
static_cast<u32>(AttenuationFunc::Spot));
|
||||||
|
|
||||||
|
out->Write("struct CustomShaderLightData\n");
|
||||||
|
out->Write("{{\n");
|
||||||
|
out->Write("\tfloat3 position;\n");
|
||||||
|
out->Write("\tfloat3 direction;\n");
|
||||||
|
out->Write("\tfloat3 color;\n");
|
||||||
|
out->Write("\tuint attenuation_type;\n");
|
||||||
|
out->Write("\tfloat4 cosatt;\n");
|
||||||
|
out->Write("\tfloat4 distatt;\n");
|
||||||
|
out->Write("}};\n\n");
|
||||||
|
|
||||||
|
// CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE "enum" values
|
||||||
|
out->Write("const uint CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_PREV = 0u;\n");
|
||||||
|
out->Write("const uint CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR = 1u;\n");
|
||||||
|
out->Write("const uint CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_TEX = 2u;\n");
|
||||||
|
out->Write("const uint CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_RAS = 3u;\n");
|
||||||
|
out->Write("const uint CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_KONST = 4u;\n");
|
||||||
|
out->Write("const uint CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_NUMERIC = 5u;\n");
|
||||||
|
out->Write("const uint CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_UNUSED = 6u;\n");
|
||||||
|
|
||||||
|
out->Write("struct CustomShaderTevStageInputColor\n");
|
||||||
|
out->Write("{{\n");
|
||||||
|
out->Write("\tuint input_type;\n");
|
||||||
|
out->Write("\tfloat3 value;\n");
|
||||||
|
out->Write("}};\n\n");
|
||||||
|
|
||||||
|
out->Write("struct CustomShaderTevStageInputAlpha\n");
|
||||||
|
out->Write("{{\n");
|
||||||
|
out->Write("\tuint input_type;\n");
|
||||||
|
out->Write("\tfloat value;\n");
|
||||||
|
out->Write("}};\n\n");
|
||||||
|
|
||||||
|
out->Write("struct CustomShaderTevStage\n");
|
||||||
|
out->Write("{{\n");
|
||||||
|
out->Write("\tCustomShaderTevStageInputColor[4] input_color;\n");
|
||||||
|
out->Write("\tCustomShaderTevStageInputAlpha[4] input_alpha;\n");
|
||||||
|
out->Write("\tuint texmap;\n");
|
||||||
|
out->Write("\tfloat4 output_color;\n");
|
||||||
|
out->Write("}};\n\n");
|
||||||
|
|
||||||
|
// Custom structure for data we pass to custom shader hooks
|
||||||
|
out->Write("struct CustomShaderData\n");
|
||||||
|
out->Write("{{\n");
|
||||||
|
out->Write("\tfloat3 position;\n");
|
||||||
|
out->Write("\tfloat3 normal;\n");
|
||||||
|
if (numtexgens == 0)
|
||||||
|
{
|
||||||
|
// Cheat so shaders compile
|
||||||
|
out->Write("\tfloat3[1] texcoord;\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out->Write("\tfloat3[{}] texcoord;\n", numtexgens);
|
||||||
|
}
|
||||||
|
out->Write("\tuint texcoord_count;\n");
|
||||||
|
out->Write("\tuint[8] texmap_to_texcoord_index;\n");
|
||||||
|
out->Write("\tCustomShaderLightData[8] lights_chan0_color;\n");
|
||||||
|
out->Write("\tCustomShaderLightData[8] lights_chan0_alpha;\n");
|
||||||
|
out->Write("\tCustomShaderLightData[8] lights_chan1_color;\n");
|
||||||
|
out->Write("\tCustomShaderLightData[8] lights_chan1_alpha;\n");
|
||||||
|
out->Write("\tfloat4[2] ambient_lighting;\n");
|
||||||
|
out->Write("\tfloat4[2] base_material;\n");
|
||||||
|
out->Write("\tuint light_chan0_color_count;\n");
|
||||||
|
out->Write("\tuint light_chan0_alpha_count;\n");
|
||||||
|
out->Write("\tuint light_chan1_color_count;\n");
|
||||||
|
out->Write("\tuint light_chan1_alpha_count;\n");
|
||||||
|
out->Write("\tCustomShaderTevStage[16] tev_stages;\n");
|
||||||
|
out->Write("\tuint tev_stage_count;\n");
|
||||||
|
out->Write("\tfloat4 final_color;\n");
|
||||||
|
out->Write("\tuint time_ms;\n");
|
||||||
|
out->Write("}};\n\n");
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -327,3 +328,21 @@ static const char s_geometry_shader_uniforms[] = "\tfloat4 " I_STEREOPARAMS ";\n
|
||||||
"\tfloat4 " I_LINEPTPARAMS ";\n"
|
"\tfloat4 " I_LINEPTPARAMS ";\n"
|
||||||
"\tint4 " I_TEXOFFSET ";\n"
|
"\tint4 " I_TEXOFFSET ";\n"
|
||||||
"\tuint vs_expand;\n";
|
"\tuint vs_expand;\n";
|
||||||
|
|
||||||
|
constexpr std::string_view CUSTOM_PIXELSHADER_COLOR_FUNC = "customShaderColor";
|
||||||
|
|
||||||
|
struct CustomPixelShader
|
||||||
|
{
|
||||||
|
std::string custom_shader;
|
||||||
|
|
||||||
|
bool operator==(const CustomPixelShader& other) const = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CustomPixelShaderContents
|
||||||
|
{
|
||||||
|
std::vector<CustomPixelShader> shaders;
|
||||||
|
|
||||||
|
bool operator==(const CustomPixelShaderContents& other) const = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
void WriteCustomShaderStructDef(ShaderCode* out, u32 numtexgens);
|
||||||
|
|
|
@ -17,6 +17,260 @@
|
||||||
|
|
||||||
namespace UberShader
|
namespace UberShader
|
||||||
{
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
void WriteCustomShaderStructImpl(ShaderCode* out, u32 num_texgen, bool per_pixel_lighting)
|
||||||
|
{
|
||||||
|
out->Write("\tCustomShaderData custom_data;\n");
|
||||||
|
if (per_pixel_lighting)
|
||||||
|
{
|
||||||
|
out->Write("\tcustom_data.position = WorldPos;\n");
|
||||||
|
out->Write("\tcustom_data.normal = Normal;\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out->Write("\tcustom_data.position = float3(0, 0, 0);\n");
|
||||||
|
out->Write("\tcustom_data.normal = float3(0, 0, 0);\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_texgen == 0) [[unlikely]]
|
||||||
|
{
|
||||||
|
out->Write("\tcustom_data.texcoord[0] = float3(0, 0, 0);\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < num_texgen; ++i)
|
||||||
|
{
|
||||||
|
out->Write("\tif (tex{0}.z == 0.0)\n", i);
|
||||||
|
out->Write("\t{{\n");
|
||||||
|
out->Write("\t\tcustom_data.texcoord[{0}] = tex{0};\n", i);
|
||||||
|
out->Write("\t}}\n");
|
||||||
|
out->Write("\telse {{\n");
|
||||||
|
out->Write("\t\tcustom_data.texcoord[{0}] = float3(tex{0}.xy / tex{0}.z, 0);\n", i);
|
||||||
|
out->Write("\t}}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out->Write("\tcustom_data.texcoord_count = {};\n", num_texgen);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
// Shader compilation complains if every index isn't initialized
|
||||||
|
out->Write("\tcustom_data.texmap_to_texcoord_index[{0}] = {0};\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = 0; i < NUM_XF_COLOR_CHANNELS; i++)
|
||||||
|
{
|
||||||
|
out->Write("\tcustom_data.base_material[{}] = vec4(0, 0, 0, 1);\n", i);
|
||||||
|
out->Write("\tcustom_data.ambient_lighting[{}] = vec4(0, 0, 0, 1);\n", i);
|
||||||
|
|
||||||
|
// Shader compilation errors can throw if not everything is initialized
|
||||||
|
for (u32 light_count_index = 0; light_count_index < 8; light_count_index++)
|
||||||
|
{
|
||||||
|
// Color
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_color[{}].direction = float3(0, 0, 0);\n", i,
|
||||||
|
light_count_index);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_color[{}].position = float3(0, 0, 0);\n", i,
|
||||||
|
light_count_index);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_color[{}].color = float3(0, 0, 0);\n", i,
|
||||||
|
light_count_index);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_color[{}].cosatt = float4(0, 0, 0, 0);\n", i,
|
||||||
|
light_count_index);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_color[{}].distatt = float4(0, 0, 0, 0);\n", i,
|
||||||
|
light_count_index);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_color[{}].attenuation_type = 0;\n", i,
|
||||||
|
light_count_index);
|
||||||
|
|
||||||
|
// Alpha
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_alpha[{}].direction = float3(0, 0, 0);\n", i,
|
||||||
|
light_count_index);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_alpha[{}].position = float3(0, 0, 0);\n", i,
|
||||||
|
light_count_index);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_alpha[{}].color = float3(0, 0, 0);\n", i,
|
||||||
|
light_count_index);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_alpha[{}].cosatt = float4(0, 0, 0, 0);\n", i,
|
||||||
|
light_count_index);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_alpha[{}].distatt = float4(0, 0, 0, 0);\n", i,
|
||||||
|
light_count_index);
|
||||||
|
out->Write("\tcustom_data.lights_chan{}_alpha[{}].attenuation_type = 0;\n", i,
|
||||||
|
light_count_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
out->Write("\tcustom_data.light_chan{}_color_count = 0;\n", i);
|
||||||
|
out->Write("\tcustom_data.light_chan{}_alpha_count = 0;\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_texgen > 0) [[likely]]
|
||||||
|
{
|
||||||
|
out->Write("\n");
|
||||||
|
out->Write("\tfor(uint stage = 0u; stage <= num_stages; stage++)\n");
|
||||||
|
out->Write("\t{{\n");
|
||||||
|
out->Write("\t\tStageState ss;\n");
|
||||||
|
out->Write("\t\tss.order = bpmem_tevorder(stage>>1);\n");
|
||||||
|
out->Write("\t\tif ((stage & 1u) == 1u)\n");
|
||||||
|
out->Write("\t\t\tss.order = ss.order >> {};\n\n",
|
||||||
|
int(TwoTevStageOrders().enable_tex_odd.StartBit() -
|
||||||
|
TwoTevStageOrders().enable_tex_even.StartBit()));
|
||||||
|
out->Write("\t\tuint texmap = {};\n",
|
||||||
|
BitfieldExtract<&TwoTevStageOrders::texcoord_even>("ss.order"));
|
||||||
|
// Shader compilation is weird, shader arrays can't use indexing by variable
|
||||||
|
// to set values unless the variable is an index in a for loop.
|
||||||
|
// So instead we have to do this if check nonsense
|
||||||
|
for (u32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
out->Write("\t\tif (texmap == {})\n", i);
|
||||||
|
out->Write("\t\t{{\n");
|
||||||
|
out->Write("\t\t\tcustom_data.texmap_to_texcoord_index[{}] = selectTexCoordIndex(texmap);\n",
|
||||||
|
i);
|
||||||
|
out->Write("\t\t}}\n");
|
||||||
|
}
|
||||||
|
out->Write("\t}}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
out->Write("\tuint light_count = 0;\n");
|
||||||
|
out->Write("\tfor (uint chan = 0u; chan < {}u; chan++)\n", NUM_XF_COLOR_CHANNELS);
|
||||||
|
out->Write("\t{{\n");
|
||||||
|
out->Write("\t\tuint colorreg = xfmem_color(chan);\n");
|
||||||
|
out->Write("\t\tuint alphareg = xfmem_alpha(chan);\n");
|
||||||
|
for (const auto& color_type : std::array<std::string_view, 2>{"colorreg", "alphareg"})
|
||||||
|
{
|
||||||
|
if (color_type == "colorreg")
|
||||||
|
{
|
||||||
|
out->Write("\t\tcustom_data.base_material[0] = " I_MATERIALS "[2u] / 255.0; \n");
|
||||||
|
out->Write("\t\tif ({} != 0u)\n", BitfieldExtract<&LitChannel::enablelighting>(color_type));
|
||||||
|
out->Write("\t\t\tcustom_data.base_material[0] = colors_0; \n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out->Write("custom_data.base_material[1].w = " I_MATERIALS "[3u].w / 255.0; \n");
|
||||||
|
out->Write("\t\tif ({} != 0u)\n", BitfieldExtract<&LitChannel::enablelighting>(color_type));
|
||||||
|
out->Write("\t\t\tcustom_data.base_material[1].w = colors_1.w; \n");
|
||||||
|
}
|
||||||
|
out->Write("\t\tif ({} != 0u)\n", BitfieldExtract<&LitChannel::enablelighting>(color_type));
|
||||||
|
out->Write("\t\t{{\n");
|
||||||
|
out->Write("\t\t\tuint light_mask = {} | ({} << 4u);\n",
|
||||||
|
BitfieldExtract<&LitChannel::lightMask0_3>(color_type),
|
||||||
|
BitfieldExtract<&LitChannel::lightMask4_7>(color_type));
|
||||||
|
out->Write("\t\t\tuint attnfunc = {};\n", BitfieldExtract<&LitChannel::attnfunc>(color_type));
|
||||||
|
out->Write("\t\t\tfor (uint light_index = 0u; light_index < 8u; light_index++)\n");
|
||||||
|
out->Write("\t\t\t{{\n");
|
||||||
|
out->Write("\t\t\t\tif ((light_mask & (1u << light_index)) != 0u)\n");
|
||||||
|
out->Write("\t\t\t\t{{\n");
|
||||||
|
// Shader compilation is weird, shader arrays can't use indexing by variable
|
||||||
|
// to set values unless the variable is an index in a for loop.
|
||||||
|
// So instead we have to do this if check nonsense
|
||||||
|
for (u32 light_count_index = 0; light_count_index < 8; light_count_index++)
|
||||||
|
{
|
||||||
|
out->Write("\t\t\t\t\tif (light_index == {})\n", light_count_index);
|
||||||
|
out->Write("\t\t\t\t\t{{\n");
|
||||||
|
if (color_type == "colorreg")
|
||||||
|
{
|
||||||
|
for (u32 channel_index = 0; channel_index < NUM_XF_COLOR_CHANNELS; channel_index++)
|
||||||
|
{
|
||||||
|
out->Write("\t\t\t\t\t\tif (chan == {})\n", channel_index);
|
||||||
|
out->Write("\t\t\t\t\t\t{{\n");
|
||||||
|
out->Write("\t\t\t\t\t\t\tcustom_data.lights_chan{}_color[{}].direction = " I_LIGHTS
|
||||||
|
"[light_index].dir.xyz;\n",
|
||||||
|
channel_index, light_count_index);
|
||||||
|
out->Write("\t\t\t\t\t\t\tcustom_data.lights_chan{}_color[{}].position = " I_LIGHTS
|
||||||
|
"[light_index].pos.xyz;\n",
|
||||||
|
channel_index, light_count_index);
|
||||||
|
out->Write("\t\t\t\t\t\t\tcustom_data.lights_chan{}_color[{}].cosatt = " I_LIGHTS
|
||||||
|
"[light_index].cosatt;\n",
|
||||||
|
channel_index, light_count_index);
|
||||||
|
out->Write("\t\t\t\t\t\t\tcustom_data.lights_chan{}_color[{}].distatt = " I_LIGHTS
|
||||||
|
"[light_index].distatt;\n",
|
||||||
|
channel_index, light_count_index);
|
||||||
|
out->Write(
|
||||||
|
"\t\t\t\t\t\t\tcustom_data.lights_chan{}_color[{}].attenuation_type = attnfunc;\n",
|
||||||
|
channel_index, light_count_index);
|
||||||
|
out->Write("\t\t\t\t\t\t\tcustom_data.lights_chan{}_color[{}].color = " I_LIGHTS
|
||||||
|
"[light_index].color.rgb / float3(255.0, 255.0, 255.0);\n",
|
||||||
|
channel_index, light_count_index);
|
||||||
|
out->Write("\t\t\t\t\t\t\tcustom_data.light_chan{}_color_count += 1;\n", channel_index);
|
||||||
|
out->Write("\t\t\t\t\t\t}}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (u32 channel_index = 0; channel_index < NUM_XF_COLOR_CHANNELS; channel_index++)
|
||||||
|
{
|
||||||
|
out->Write("\t\t\t\t\t\tif (chan == {})\n", channel_index);
|
||||||
|
out->Write("\t\t\t\t\t\t{{\n");
|
||||||
|
out->Write("\t\t\t\t\t\t\tcustom_data.lights_chan{}_alpha[{}].direction = " I_LIGHTS
|
||||||
|
"[light_index].dir.xyz;\n",
|
||||||
|
channel_index, light_count_index);
|
||||||
|
out->Write("\t\t\t\t\t\t\tcustom_data.lights_chan{}_alpha[{}].position = " I_LIGHTS
|
||||||
|
"[light_index].pos.xyz;\n",
|
||||||
|
channel_index, light_count_index);
|
||||||
|
out->Write("\t\t\t\t\t\t\tcustom_data.lights_chan{}_alpha[{}].cosatt = " I_LIGHTS
|
||||||
|
"[light_index].cosatt;\n",
|
||||||
|
channel_index, light_count_index);
|
||||||
|
out->Write("\t\t\t\t\t\t\tcustom_data.lights_chan{}_alpha[{}].distatt = " I_LIGHTS
|
||||||
|
"[light_index].distatt;\n",
|
||||||
|
channel_index, light_count_index);
|
||||||
|
out->Write(
|
||||||
|
"\t\t\t\t\t\t\tcustom_data.lights_chan{}_alpha[{}].attenuation_type = attnfunc;\n",
|
||||||
|
channel_index, light_count_index);
|
||||||
|
out->Write("\t\t\t\t\t\t\tcustom_data.lights_chan{}_alpha[{}].color = float3(" I_LIGHTS
|
||||||
|
"[light_index].color.a) / float3(255.0, 255.0, 255.0);\n",
|
||||||
|
channel_index, light_count_index);
|
||||||
|
out->Write("\t\t\t\t\t\t\tcustom_data.light_chan{}_alpha_count += 1;\n", channel_index);
|
||||||
|
out->Write("\t\t\t\t\t\t}}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out->Write("\t\t\t\t\t}}\n");
|
||||||
|
}
|
||||||
|
out->Write("\t\t\t\t}}\n");
|
||||||
|
out->Write("\t\t\t}}\n");
|
||||||
|
out->Write("\t\t}}\n");
|
||||||
|
}
|
||||||
|
out->Write("\t}}\n");
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
// Shader compilation complains if every struct isn't initialized
|
||||||
|
|
||||||
|
// Color Input
|
||||||
|
for (u32 j = 0; j < 4; j++)
|
||||||
|
{
|
||||||
|
out->Write("\tcustom_data.tev_stages[{}].input_color[{}].input_type = "
|
||||||
|
"CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_UNUSED;\n",
|
||||||
|
i, j);
|
||||||
|
out->Write("\tcustom_data.tev_stages[{}].input_color[{}].value = "
|
||||||
|
"float3(0, 0, 0);\n",
|
||||||
|
i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alpha Input
|
||||||
|
for (u32 j = 0; j < 4; j++)
|
||||||
|
{
|
||||||
|
out->Write("\tcustom_data.tev_stages[{}].input_alpha[{}].input_type = "
|
||||||
|
"CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_UNUSED;\n",
|
||||||
|
i, j);
|
||||||
|
out->Write("\tcustom_data.tev_stages[{}].input_alpha[{}].value = "
|
||||||
|
"float(0);\n",
|
||||||
|
i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Texmap
|
||||||
|
out->Write("\tcustom_data.tev_stages[{}].texmap = 0u;\n", i);
|
||||||
|
|
||||||
|
// Output
|
||||||
|
out->Write("\tcustom_data.tev_stages[{}].output_color = "
|
||||||
|
"float4(0, 0, 0, 0);\n",
|
||||||
|
i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actual data will be filled out in the tev stage code, just set the
|
||||||
|
// stage count for now
|
||||||
|
out->Write("\tcustom_data.tev_stage_count = num_stages;\n");
|
||||||
|
|
||||||
|
// Time
|
||||||
|
out->Write("\tcustom_data.time_ms = time_ms;\n");
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
PixelShaderUid GetPixelShaderUid()
|
PixelShaderUid GetPixelShaderUid()
|
||||||
{
|
{
|
||||||
PixelShaderUid out;
|
PixelShaderUid out;
|
||||||
|
@ -56,7 +310,8 @@ void ClearUnusedPixelShaderUidBits(APIType api_type, const ShaderHostConfig& hos
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
const pixel_ubershader_uid_data* uid_data)
|
const pixel_ubershader_uid_data* uid_data,
|
||||||
|
const CustomPixelShaderContents& custom_details)
|
||||||
{
|
{
|
||||||
const bool per_pixel_lighting = host_config.per_pixel_lighting;
|
const bool per_pixel_lighting = host_config.per_pixel_lighting;
|
||||||
const bool msaa = host_config.msaa;
|
const bool msaa = host_config.msaa;
|
||||||
|
@ -76,6 +331,12 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
out.Write("// {}\n", *uid_data);
|
out.Write("// {}\n", *uid_data);
|
||||||
WriteBitfieldExtractHeader(out, api_type, host_config);
|
WriteBitfieldExtractHeader(out, api_type, host_config);
|
||||||
WritePixelShaderCommonHeader(out, api_type, host_config, bounding_box);
|
WritePixelShaderCommonHeader(out, api_type, host_config, bounding_box);
|
||||||
|
WriteCustomShaderStructDef(&out, numTexgen);
|
||||||
|
for (std::size_t i = 0; i < custom_details.shaders.size(); i++)
|
||||||
|
{
|
||||||
|
const auto& shader_details = custom_details.shaders[i];
|
||||||
|
out.Write(fmt::runtime(shader_details.custom_shader), i);
|
||||||
|
}
|
||||||
if (per_pixel_lighting)
|
if (per_pixel_lighting)
|
||||||
WriteLightingFunction(out);
|
WriteLightingFunction(out);
|
||||||
|
|
||||||
|
@ -228,6 +489,68 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Write("}}\n\n");
|
out.Write("}}\n\n");
|
||||||
|
|
||||||
|
out.Write("uint selectTexCoordIndex(uint texmap)");
|
||||||
|
out.Write("{{\n");
|
||||||
|
|
||||||
|
if (api_type == APIType::D3D)
|
||||||
|
{
|
||||||
|
out.Write(" switch (texmap) {{\n");
|
||||||
|
for (u32 i = 0; i < numTexgen; i++)
|
||||||
|
{
|
||||||
|
out.Write(" case {}u:\n"
|
||||||
|
" return {};\n",
|
||||||
|
i, i);
|
||||||
|
}
|
||||||
|
out.Write(" default:\n"
|
||||||
|
" return 0;\n"
|
||||||
|
" }}\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out.Write(" if (texmap >= {}u) {{\n", numTexgen);
|
||||||
|
out.Write(" return 0;\n"
|
||||||
|
" }}\n");
|
||||||
|
if (numTexgen > 4)
|
||||||
|
out.Write(" if (texmap < 4u) {{\n");
|
||||||
|
if (numTexgen > 2)
|
||||||
|
out.Write(" if (texmap < 2u) {{\n");
|
||||||
|
if (numTexgen > 1)
|
||||||
|
out.Write(" return (texmap == 0u) ? 0 : 1;\n");
|
||||||
|
else
|
||||||
|
out.Write(" return 0;\n");
|
||||||
|
if (numTexgen > 2)
|
||||||
|
{
|
||||||
|
out.Write(" }} else {{\n"); // >= 2 < min(4, numTexgen)
|
||||||
|
if (numTexgen > 3)
|
||||||
|
out.Write(" return (texmap == 2u) ? 2 : 3;\n");
|
||||||
|
else
|
||||||
|
out.Write(" return 2;\n");
|
||||||
|
out.Write(" }}\n");
|
||||||
|
}
|
||||||
|
if (numTexgen > 4)
|
||||||
|
{
|
||||||
|
out.Write(" }} else {{\n"); // >= 4 < min(8, numTexgen)
|
||||||
|
if (numTexgen > 6)
|
||||||
|
out.Write(" if (texmap < 6u) {{\n");
|
||||||
|
if (numTexgen > 5)
|
||||||
|
out.Write(" return (texmap == 4u) ? 4 : 5;\n");
|
||||||
|
else
|
||||||
|
out.Write(" return 4;\n");
|
||||||
|
if (numTexgen > 6)
|
||||||
|
{
|
||||||
|
out.Write(" }} else {{\n"); // >= 6 < min(8, numTexgen)
|
||||||
|
if (numTexgen > 7)
|
||||||
|
out.Write(" return (texmap == 6u) ? 6 : 7;\n");
|
||||||
|
else
|
||||||
|
out.Write(" return 6;\n");
|
||||||
|
out.Write(" }}\n");
|
||||||
|
}
|
||||||
|
out.Write(" }}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.Write("}}\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// =====================
|
// =====================
|
||||||
|
@ -316,8 +639,7 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
// TEV's Special Lerp
|
// TEV's Special Lerp
|
||||||
// ======================
|
// ======================
|
||||||
const auto WriteTevLerp = [&out](std::string_view components) {
|
const auto WriteTevLerp = [&out](std::string_view components) {
|
||||||
out.Write(
|
out.Write("// TEV's Linear Interpolate, plus bias, add/subtract and scale\n"
|
||||||
"// TEV's Linear Interpolate, plus bias, add/subtract and scale\n"
|
|
||||||
"int{0} tevLerp{0}(int{0} A, int{0} B, int{0} C, int{0} D, uint bias, bool op, "
|
"int{0} tevLerp{0}(int{0} A, int{0} B, int{0} C, int{0} D, uint bias, bool op, "
|
||||||
"uint scale) {{\n"
|
"uint scale) {{\n"
|
||||||
" // Scale C from 0..255 to 0..256\n"
|
" // Scale C from 0..255 to 0..256\n"
|
||||||
|
@ -333,7 +655,8 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
" D = D << scale;\n"
|
" D = D << scale;\n"
|
||||||
" }}\n"
|
" }}\n"
|
||||||
"\n"
|
"\n"
|
||||||
" // TODO: Is this rounding bias still added when the scale is divide by 2? Currently we "
|
" // TODO: Is this rounding bias still added when the scale is divide by 2? "
|
||||||
|
"Currently we "
|
||||||
"do not apply it.\n"
|
"do not apply it.\n"
|
||||||
" if (scale != 3u)\n"
|
" if (scale != 3u)\n"
|
||||||
" lerp = lerp + (op ? 127 : 128);\n"
|
" lerp = lerp + (op ? 127 : 128);\n"
|
||||||
|
@ -437,6 +760,25 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
"return int3(0, 0, 0);", // ZERO
|
"return int3(0, 0, 0);", // ZERO
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static constexpr Common::EnumMap<std::string_view, TevColorArg::Zero> tev_c_input_type{
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_PREV;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_PREV;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_TEX;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_TEX;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_RAS;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_RAS;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_NUMERIC;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_NUMERIC;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_KONST;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_NUMERIC;",
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr Common::EnumMap<std::string_view, TevAlphaArg::Zero> tev_a_input_table{
|
static constexpr Common::EnumMap<std::string_view, TevAlphaArg::Zero> tev_a_input_table{
|
||||||
"return s.Reg[0].a;", // APREV,
|
"return s.Reg[0].a;", // APREV,
|
||||||
"return s.Reg[1].a;", // A0,
|
"return s.Reg[1].a;", // A0,
|
||||||
|
@ -448,6 +790,17 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
"return 0;", // ZERO
|
"return 0;", // ZERO
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static constexpr Common::EnumMap<std::string_view, TevAlphaArg::Zero> tev_a_input_type{
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_PREV;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_TEX;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_RAS;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_KONST;",
|
||||||
|
"return CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_NUMERIC;",
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr Common::EnumMap<std::string_view, TevOutput::Color2> tev_regs_lookup_table{
|
static constexpr Common::EnumMap<std::string_view, TevOutput::Color2> tev_regs_lookup_table{
|
||||||
"return s.Reg[0];",
|
"return s.Reg[0];",
|
||||||
"return s.Reg[1];",
|
"return s.Reg[1];",
|
||||||
|
@ -489,6 +842,16 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
out.Write("}}\n"
|
out.Write("}}\n"
|
||||||
"\n");
|
"\n");
|
||||||
|
|
||||||
|
out.Write("// Helper function for Custom Shader Input Type\n"
|
||||||
|
"uint getColorInputType(uint index) {{\n");
|
||||||
|
WriteSwitch(out, api_type, "index", tev_c_input_type, 2, false);
|
||||||
|
out.Write("}}\n"
|
||||||
|
"\n"
|
||||||
|
"uint getAlphaInputType(uint index) {{\n");
|
||||||
|
WriteSwitch(out, api_type, "index", tev_a_input_type, 2, false);
|
||||||
|
out.Write("}}\n"
|
||||||
|
"\n");
|
||||||
|
|
||||||
// Since the fixed-point texture coodinate variables aren't global, we need to pass
|
// Since the fixed-point texture coodinate variables aren't global, we need to pass
|
||||||
// them to the select function. This applies to all backends.
|
// them to the select function. This applies to all backends.
|
||||||
if (numTexgen > 0)
|
if (numTexgen > 0)
|
||||||
|
@ -505,6 +868,17 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
out.Write("void main()\n{{\n");
|
out.Write("void main()\n{{\n");
|
||||||
out.Write(" float4 rawpos = gl_FragCoord;\n");
|
out.Write(" float4 rawpos = gl_FragCoord;\n");
|
||||||
|
|
||||||
|
out.Write(" uint num_stages = {};\n\n",
|
||||||
|
BitfieldExtract<&GenMode::numtevstages>("bpmem_genmode"));
|
||||||
|
|
||||||
|
bool has_custom_shader_details = false;
|
||||||
|
if (std::any_of(custom_details.shaders.begin(), custom_details.shaders.end(),
|
||||||
|
[](const std::optional<CustomPixelShader>& ps) { return ps.has_value(); }))
|
||||||
|
{
|
||||||
|
WriteCustomShaderStructImpl(&out, numTexgen, per_pixel_lighting);
|
||||||
|
has_custom_shader_details = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (use_framebuffer_fetch)
|
if (use_framebuffer_fetch)
|
||||||
{
|
{
|
||||||
// Store off a copy of the initial framebuffer value.
|
// Store off a copy of the initial framebuffer value.
|
||||||
|
@ -563,9 +937,6 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
" // o.colors_1 = float4(0.0, 0.0, 0.0, 0.0);\n");
|
" // o.colors_1 = float4(0.0, 0.0, 0.0, 0.0);\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Write(" uint num_stages = {};\n\n",
|
|
||||||
BitfieldExtract<&GenMode::numtevstages>("bpmem_genmode"));
|
|
||||||
|
|
||||||
out.Write(" // Main tev loop\n");
|
out.Write(" // Main tev loop\n");
|
||||||
|
|
||||||
out.Write(" for(uint stage = 0u; stage <= num_stages; stage++)\n"
|
out.Write(" for(uint stage = 0u; stage <= num_stages; stage++)\n"
|
||||||
|
@ -618,9 +989,9 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
// indirect texture stage is enabled). If the matrix is off, the result doesn't matter; if the
|
// indirect texture stage is enabled). If the matrix is off, the result doesn't matter; if the
|
||||||
// indirect texture stage is disabled, the result is undefined (and produces a glitchy pattern
|
// indirect texture stage is disabled, the result is undefined (and produces a glitchy pattern
|
||||||
// on hardware, different from this).
|
// on hardware, different from this).
|
||||||
// For the undefined case, we just skip applying the indirect operation, which is close enough.
|
// For the undefined case, we just skip applying the indirect operation, which is close
|
||||||
// Viewtiful Joe hits the undefined case (bug 12525).
|
// enough. Viewtiful Joe hits the undefined case (bug 12525). Wrapping and add to previous
|
||||||
// Wrapping and add to previous still apply in this case (and when the stage is disabled).
|
// still apply in this case (and when the stage is disabled).
|
||||||
out.Write(" if (bpmem_iref(bt) != 0u) {{\n");
|
out.Write(" if (bpmem_iref(bt) != 0u) {{\n");
|
||||||
out.Write(" int3 indcoord;\n");
|
out.Write(" int3 indcoord;\n");
|
||||||
LookupIndirectTexture("indcoord", "bt");
|
LookupIndirectTexture("indcoord", "bt");
|
||||||
|
@ -826,7 +1197,8 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
" alpha_B = selectAlphaInput(s, ss, {0}colors_0, {0}colors_1, alpha_b) & 255;\n"
|
" alpha_B = selectAlphaInput(s, ss, {0}colors_0, {0}colors_1, alpha_b) & 255;\n"
|
||||||
" }};\n"
|
" }};\n"
|
||||||
" int alpha_C = selectAlphaInput(s, ss, {0}colors_0, {0}colors_1, alpha_c) & 255;\n"
|
" int alpha_C = selectAlphaInput(s, ss, {0}colors_0, {0}colors_1, alpha_c) & 255;\n"
|
||||||
" int alpha_D = selectAlphaInput(s, ss, {0}colors_0, {0}colors_1, alpha_d); // 10 bits "
|
" int alpha_D = selectAlphaInput(s, ss, {0}colors_0, {0}colors_1, alpha_d); // 10 "
|
||||||
|
"bits "
|
||||||
"+ sign\n"
|
"+ sign\n"
|
||||||
"\n", // TODO: do we need to sign extend?
|
"\n", // TODO: do we need to sign extend?
|
||||||
color_input_prefix);
|
color_input_prefix);
|
||||||
|
@ -857,9 +1229,81 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
"\n"
|
"\n"
|
||||||
" // Write result to the correct input register of the next stage\n");
|
" // Write result to the correct input register of the next stage\n");
|
||||||
WriteSwitch(out, api_type, "alpha_dest", tev_a_set_table, 6, true);
|
WriteSwitch(out, api_type, "alpha_dest", tev_a_set_table, 6, true);
|
||||||
out.Write(" }}\n"
|
if (has_custom_shader_details)
|
||||||
" }} // Main TEV loop\n"
|
{
|
||||||
"\n");
|
for (u32 stage_index = 0; stage_index < 16; stage_index++)
|
||||||
|
{
|
||||||
|
out.Write("\tif (stage == {}u) {{\n", stage_index);
|
||||||
|
// Color input
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].input_color[0].value = color_A / float3(255.0, "
|
||||||
|
"255.0, 255.0);\n",
|
||||||
|
stage_index);
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].input_color[0].input_type = "
|
||||||
|
"getColorInputType(color_a);\n",
|
||||||
|
stage_index);
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].input_color[1].value = color_B / float3(255.0, "
|
||||||
|
"255.0, 255.0);\n",
|
||||||
|
stage_index);
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].input_color[1].input_type = "
|
||||||
|
"getColorInputType(color_b);\n",
|
||||||
|
stage_index);
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].input_color[2].value = color_C / float3(255.0, "
|
||||||
|
"255.0, 255.0);\n",
|
||||||
|
stage_index);
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].input_color[2].input_type = "
|
||||||
|
"getColorInputType(color_c);\n",
|
||||||
|
stage_index);
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].input_color[3].value = color_D / float3(255.0, "
|
||||||
|
"255.0, 255.0);\n",
|
||||||
|
stage_index);
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].input_color[3].input_type = "
|
||||||
|
"getColorInputType(color_c);\n",
|
||||||
|
stage_index);
|
||||||
|
|
||||||
|
// Alpha input
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].input_alpha[0].value = alpha_A / float(255.0);\n",
|
||||||
|
stage_index);
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].input_alpha[0].input_type = "
|
||||||
|
"getAlphaInputType(alpha_a);\n",
|
||||||
|
stage_index);
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].input_alpha[1].value = alpha_B / float(255.0);\n",
|
||||||
|
stage_index);
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].input_alpha[1].input_type = "
|
||||||
|
"getAlphaInputType(alpha_b);\n",
|
||||||
|
stage_index);
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].input_alpha[2].value = alpha_C / float(255.0);\n",
|
||||||
|
stage_index);
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].input_alpha[2].input_type = "
|
||||||
|
"getAlphaInputType(alpha_c);\n",
|
||||||
|
stage_index);
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].input_alpha[3].value = alpha_D / float(255.0);\n",
|
||||||
|
stage_index);
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].input_alpha[3].input_type = "
|
||||||
|
"getAlphaInputType(alpha_d);\n",
|
||||||
|
stage_index);
|
||||||
|
|
||||||
|
if (numTexgen != 0)
|
||||||
|
{
|
||||||
|
// Texmap
|
||||||
|
out.Write("\t\tif (texture_enabled) {{\n");
|
||||||
|
out.Write("\t\t\tuint sampler_num = {};\n",
|
||||||
|
BitfieldExtract<&TwoTevStageOrders::texmap_even>("ss.order"));
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].texmap = sampler_num;\n", stage_index);
|
||||||
|
out.Write("\t\t}}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].output_color.rgb = color / float3(255.0, 255.0, "
|
||||||
|
"255.0);\n",
|
||||||
|
stage_index);
|
||||||
|
out.Write("\t\tcustom_data.tev_stages[{}].output_color.a = alpha / float(255.0);\n",
|
||||||
|
stage_index);
|
||||||
|
out.Write("\t}}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.Write(" }}\n");
|
||||||
|
out.Write(" }} // Main TEV loop\n");
|
||||||
|
out.Write("\n");
|
||||||
|
|
||||||
// Select the output color and alpha registers from the last stage.
|
// Select the output color and alpha registers from the last stage.
|
||||||
out.Write(" int4 TevResult;\n");
|
out.Write(" int4 TevResult;\n");
|
||||||
|
@ -942,8 +1386,8 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
{
|
{
|
||||||
// Instead of using discard, fetch the framebuffer's color value and use it as the output
|
// Instead of using discard, fetch the framebuffer's color value and use it as the output
|
||||||
// for this fragment.
|
// for this fragment.
|
||||||
out.Write(
|
out.Write(" #define discard_fragment {{ real_ocol0 = float4(initial_ocol0.xyz, 1.0); "
|
||||||
" #define discard_fragment {{ real_ocol0 = float4(initial_ocol0.xyz, 1.0); return; }}\n");
|
"return; }}\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1109,8 +1553,8 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
" }}\n");
|
" }}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some backends require that the shader outputs be uint when writing to a uint render target for
|
// Some backends require that the shader outputs be uint when writing to a uint render target
|
||||||
// logic op.
|
// for logic op.
|
||||||
if (uid_data->uint_output)
|
if (uid_data->uint_output)
|
||||||
{
|
{
|
||||||
out.Write(" if (bpmem_rgba6_format)\n"
|
out.Write(" if (bpmem_rgba6_format)\n"
|
||||||
|
@ -1142,6 +1586,19 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < custom_details.shaders.size(); i++)
|
||||||
|
{
|
||||||
|
const auto& shader_details = custom_details.shaders[i];
|
||||||
|
|
||||||
|
if (!shader_details.custom_shader.empty())
|
||||||
|
{
|
||||||
|
out.Write("\t{{\n");
|
||||||
|
out.Write("\t\tcustom_data.final_color = ocol0;\n");
|
||||||
|
out.Write("\t\tocol0.xyz = {}_{}(custom_data).xyz;\n", CUSTOM_PIXELSHADER_COLOR_FUNC, i);
|
||||||
|
out.Write("\t}}\n\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (bounding_box)
|
if (bounding_box)
|
||||||
{
|
{
|
||||||
out.Write(" if (bpmem_bounding_box) {{\n"
|
out.Write(" if (bpmem_bounding_box) {{\n"
|
||||||
|
@ -1209,10 +1666,10 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
WriteSwitch(out, api_type, "blend_dst_factor", blendDstFactor, 4, true);
|
WriteSwitch(out, api_type, "blend_dst_factor", blendDstFactor, 4, true);
|
||||||
WriteSwitch(out, api_type, "blend_dst_factor_alpha", blendDstFactorAlpha, 4, true);
|
WriteSwitch(out, api_type, "blend_dst_factor_alpha", blendDstFactorAlpha, 4, true);
|
||||||
|
|
||||||
out.Write(
|
out.Write(" float4 blend_result;\n"
|
||||||
" float4 blend_result;\n"
|
|
||||||
" if (blend_subtract)\n"
|
" if (blend_subtract)\n"
|
||||||
" blend_result.rgb = initial_ocol0.rgb * blend_dst.rgb - ocol0.rgb * blend_src.rgb;\n"
|
" blend_result.rgb = initial_ocol0.rgb * blend_dst.rgb - ocol0.rgb * "
|
||||||
|
"blend_src.rgb;\n"
|
||||||
" else\n"
|
" else\n"
|
||||||
" blend_result.rgb = initial_ocol0.rgb * blend_dst.rgb + ocol0.rgb * "
|
" blend_result.rgb = initial_ocol0.rgb * blend_dst.rgb + ocol0.rgb * "
|
||||||
"blend_src.rgb;\n");
|
"blend_src.rgb;\n");
|
||||||
|
|
|
@ -29,7 +29,8 @@ using PixelShaderUid = ShaderUid<pixel_ubershader_uid_data>;
|
||||||
PixelShaderUid GetPixelShaderUid();
|
PixelShaderUid GetPixelShaderUid();
|
||||||
|
|
||||||
ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
const pixel_ubershader_uid_data* uid_data);
|
const pixel_ubershader_uid_data* uid_data,
|
||||||
|
const CustomPixelShaderContents& custom_details);
|
||||||
|
|
||||||
void EnumeratePixelShaderUids(const std::function<void(const PixelShaderUid&)>& callback);
|
void EnumeratePixelShaderUids(const std::function<void(const PixelShaderUid&)>& callback);
|
||||||
void ClearUnusedPixelShaderUidBits(APIType api_type, const ShaderHostConfig& host_config,
|
void ClearUnusedPixelShaderUidBits(APIType api_type, const ShaderHostConfig& host_config,
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/DolphinAnalytics.h"
|
#include "Core/DolphinAnalytics.h"
|
||||||
|
#include "Core/HW/SystemTimers.h"
|
||||||
#include "Core/System.h"
|
#include "Core/System.h"
|
||||||
|
|
||||||
#include "VideoCommon/AbstractGfx.h"
|
#include "VideoCommon/AbstractGfx.h"
|
||||||
|
@ -23,12 +24,14 @@
|
||||||
#include "VideoCommon/DataReader.h"
|
#include "VideoCommon/DataReader.h"
|
||||||
#include "VideoCommon/FramebufferManager.h"
|
#include "VideoCommon/FramebufferManager.h"
|
||||||
#include "VideoCommon/GeometryShaderManager.h"
|
#include "VideoCommon/GeometryShaderManager.h"
|
||||||
|
#include "VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.h"
|
||||||
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionData.h"
|
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionData.h"
|
||||||
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.h"
|
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.h"
|
||||||
#include "VideoCommon/IndexGenerator.h"
|
#include "VideoCommon/IndexGenerator.h"
|
||||||
#include "VideoCommon/NativeVertexFormat.h"
|
#include "VideoCommon/NativeVertexFormat.h"
|
||||||
#include "VideoCommon/OpcodeDecoding.h"
|
#include "VideoCommon/OpcodeDecoding.h"
|
||||||
#include "VideoCommon/PerfQueryBase.h"
|
#include "VideoCommon/PerfQueryBase.h"
|
||||||
|
#include "VideoCommon/PixelShaderGen.h"
|
||||||
#include "VideoCommon/PixelShaderManager.h"
|
#include "VideoCommon/PixelShaderManager.h"
|
||||||
#include "VideoCommon/Statistics.h"
|
#include "VideoCommon/Statistics.h"
|
||||||
#include "VideoCommon/TextureCacheBase.h"
|
#include "VideoCommon/TextureCacheBase.h"
|
||||||
|
@ -105,7 +108,10 @@ VertexManagerBase::~VertexManagerBase() = default;
|
||||||
bool VertexManagerBase::Initialize()
|
bool VertexManagerBase::Initialize()
|
||||||
{
|
{
|
||||||
m_frame_end_event = AfterFrameEvent::Register([this] { OnEndFrame(); }, "VertexManagerBase");
|
m_frame_end_event = AfterFrameEvent::Register([this] { OnEndFrame(); }, "VertexManagerBase");
|
||||||
|
m_after_present_event = AfterPresentEvent::Register(
|
||||||
|
[this](PresentInfo& pi) { m_ticks_elapsed = pi.emulated_timestamp; }, "VertexManagerBase");
|
||||||
m_index_generator.Init();
|
m_index_generator.Init();
|
||||||
|
m_custom_shader_cache = std::make_unique<CustomShaderCache>();
|
||||||
m_cpu_cull.Init();
|
m_cpu_cull.Init();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -523,10 +529,18 @@ void VertexManagerBase::Flush()
|
||||||
auto& geometry_shader_manager = system.GetGeometryShaderManager();
|
auto& geometry_shader_manager = system.GetGeometryShaderManager();
|
||||||
auto& vertex_shader_manager = system.GetVertexShaderManager();
|
auto& vertex_shader_manager = system.GetVertexShaderManager();
|
||||||
|
|
||||||
|
if (g_ActiveConfig.bGraphicMods)
|
||||||
|
{
|
||||||
|
const double seconds_elapsed =
|
||||||
|
static_cast<double>(m_ticks_elapsed) / SystemTimers::GetTicksPerSecond();
|
||||||
|
pixel_shader_manager.constants.time_ms = seconds_elapsed * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
CalculateBinormals(VertexLoaderManager::GetCurrentVertexFormat());
|
CalculateBinormals(VertexLoaderManager::GetCurrentVertexFormat());
|
||||||
// Calculate ZSlope for zfreeze
|
// Calculate ZSlope for zfreeze
|
||||||
const auto used_textures = UsedTextures();
|
const auto used_textures = UsedTextures();
|
||||||
std::vector<std::string> texture_names;
|
std::vector<std::string> texture_names;
|
||||||
|
std::vector<u32> texture_units;
|
||||||
if (!m_cull_all)
|
if (!m_cull_all)
|
||||||
{
|
{
|
||||||
if (!g_ActiveConfig.bGraphicMods)
|
if (!g_ActiveConfig.bGraphicMods)
|
||||||
|
@ -542,8 +556,13 @@ void VertexManagerBase::Flush()
|
||||||
{
|
{
|
||||||
const auto cache_entry = g_texture_cache->Load(TextureInfo::FromStage(i));
|
const auto cache_entry = g_texture_cache->Load(TextureInfo::FromStage(i));
|
||||||
if (cache_entry)
|
if (cache_entry)
|
||||||
|
{
|
||||||
|
if (std::find(texture_names.begin(), texture_names.end(),
|
||||||
|
cache_entry->texture_info_name) == texture_names.end())
|
||||||
{
|
{
|
||||||
texture_names.push_back(cache_entry->texture_info_name);
|
texture_names.push_back(cache_entry->texture_info_name);
|
||||||
|
texture_units.push_back(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -562,13 +581,24 @@ void VertexManagerBase::Flush()
|
||||||
|
|
||||||
if (!m_cull_all)
|
if (!m_cull_all)
|
||||||
{
|
{
|
||||||
for (const auto& texture_name : texture_names)
|
CustomPixelShaderContents custom_pixel_shader_contents;
|
||||||
|
std::optional<CustomPixelShader> custom_pixel_shader;
|
||||||
|
std::vector<std::string> custom_pixel_texture_names;
|
||||||
|
for (int i = 0; i < texture_names.size(); i++)
|
||||||
{
|
{
|
||||||
|
const std::string& texture_name = texture_names[i];
|
||||||
|
const u32 texture_unit = texture_units[i];
|
||||||
bool skip = false;
|
bool skip = false;
|
||||||
GraphicsModActionData::DrawStarted draw_started{&skip};
|
GraphicsModActionData::DrawStarted draw_started{texture_unit, &skip, &custom_pixel_shader};
|
||||||
for (const auto& action : g_graphics_mod_manager->GetDrawStartedActions(texture_name))
|
for (const auto& action : g_graphics_mod_manager->GetDrawStartedActions(texture_name))
|
||||||
{
|
{
|
||||||
action->OnDrawStarted(&draw_started);
|
action->OnDrawStarted(&draw_started);
|
||||||
|
if (custom_pixel_shader)
|
||||||
|
{
|
||||||
|
custom_pixel_shader_contents.shaders.push_back(*custom_pixel_shader);
|
||||||
|
custom_pixel_texture_names.push_back(texture_name);
|
||||||
|
}
|
||||||
|
custom_pixel_shader = std::nullopt;
|
||||||
}
|
}
|
||||||
if (skip == true)
|
if (skip == true)
|
||||||
return;
|
return;
|
||||||
|
@ -610,7 +640,65 @@ void VertexManagerBase::Flush()
|
||||||
UpdatePipelineObject();
|
UpdatePipelineObject();
|
||||||
if (m_current_pipeline_object)
|
if (m_current_pipeline_object)
|
||||||
{
|
{
|
||||||
g_gfx->SetPipeline(m_current_pipeline_object);
|
const AbstractPipeline* current_pipeline = m_current_pipeline_object;
|
||||||
|
if (!custom_pixel_shader_contents.shaders.empty())
|
||||||
|
{
|
||||||
|
CustomShaderInstance custom_shaders;
|
||||||
|
custom_shaders.pixel_contents = std::move(custom_pixel_shader_contents);
|
||||||
|
|
||||||
|
switch (g_ActiveConfig.iShaderCompilationMode)
|
||||||
|
{
|
||||||
|
case ShaderCompilationMode::Synchronous:
|
||||||
|
case ShaderCompilationMode::AsynchronousSkipRendering:
|
||||||
|
{
|
||||||
|
if (auto pipeline = m_custom_shader_cache->GetPipelineAsync(
|
||||||
|
m_current_pipeline_config, custom_shaders, m_current_pipeline_object->m_config))
|
||||||
|
{
|
||||||
|
current_pipeline = *pipeline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ShaderCompilationMode::SynchronousUberShaders:
|
||||||
|
{
|
||||||
|
// D3D has issues compiling large custom ubershaders
|
||||||
|
// use specialized shaders instead
|
||||||
|
if (g_ActiveConfig.backend_info.api_type == APIType::D3D)
|
||||||
|
{
|
||||||
|
if (auto pipeline = m_custom_shader_cache->GetPipelineAsync(
|
||||||
|
m_current_pipeline_config, custom_shaders, m_current_pipeline_object->m_config))
|
||||||
|
{
|
||||||
|
current_pipeline = *pipeline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (auto pipeline = m_custom_shader_cache->GetPipelineAsync(
|
||||||
|
m_current_uber_pipeline_config, custom_shaders,
|
||||||
|
m_current_pipeline_object->m_config))
|
||||||
|
{
|
||||||
|
current_pipeline = *pipeline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ShaderCompilationMode::AsynchronousUberShaders:
|
||||||
|
{
|
||||||
|
if (auto pipeline = m_custom_shader_cache->GetPipelineAsync(
|
||||||
|
m_current_pipeline_config, custom_shaders, m_current_pipeline_object->m_config))
|
||||||
|
{
|
||||||
|
current_pipeline = *pipeline;
|
||||||
|
}
|
||||||
|
else if (auto uber_pipeline = m_custom_shader_cache->GetPipelineAsync(
|
||||||
|
m_current_uber_pipeline_config, custom_shaders,
|
||||||
|
m_current_pipeline_object->m_config))
|
||||||
|
{
|
||||||
|
current_pipeline = *uber_pipeline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
g_gfx->SetPipeline(current_pipeline);
|
||||||
if (PerfQueryBase::ShouldEmulate())
|
if (PerfQueryBase::ShouldEmulate())
|
||||||
g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
|
g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
|
||||||
|
|
||||||
|
@ -1006,3 +1094,9 @@ void VertexManagerBase::OnEndFrame()
|
||||||
// state changes the specialized shader will not take over.
|
// state changes the specialized shader will not take over.
|
||||||
InvalidatePipelineObject();
|
InvalidatePipelineObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VertexManagerBase::NotifyCustomShaderCacheOfHostChange(const ShaderHostConfig& host_config)
|
||||||
|
{
|
||||||
|
m_custom_shader_cache->SetHostConfig(host_config);
|
||||||
|
m_custom_shader_cache->Reload();
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "VideoCommon/ShaderCache.h"
|
#include "VideoCommon/ShaderCache.h"
|
||||||
#include "VideoCommon/VideoEvents.h"
|
#include "VideoCommon/VideoEvents.h"
|
||||||
|
|
||||||
|
class CustomShaderCache;
|
||||||
class DataReader;
|
class DataReader;
|
||||||
class NativeVertexFormat;
|
class NativeVertexFormat;
|
||||||
class PointerWrap;
|
class PointerWrap;
|
||||||
|
@ -128,6 +129,7 @@ public:
|
||||||
m_current_pipeline_object = nullptr;
|
m_current_pipeline_object = nullptr;
|
||||||
m_pipeline_config_changed = true;
|
m_pipeline_config_changed = true;
|
||||||
}
|
}
|
||||||
|
void NotifyCustomShaderCacheOfHostChange(const ShaderHostConfig& host_config);
|
||||||
|
|
||||||
// Utility pipeline drawing (e.g. EFB copies, post-processing, UI).
|
// Utility pipeline drawing (e.g. EFB copies, post-processing, UI).
|
||||||
virtual void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size);
|
virtual void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size);
|
||||||
|
@ -230,7 +232,11 @@ private:
|
||||||
std::vector<u32> m_scheduled_command_buffer_kicks;
|
std::vector<u32> m_scheduled_command_buffer_kicks;
|
||||||
bool m_allow_background_execution = true;
|
bool m_allow_background_execution = true;
|
||||||
|
|
||||||
|
std::unique_ptr<CustomShaderCache> m_custom_shader_cache;
|
||||||
|
u64 m_ticks_elapsed;
|
||||||
|
|
||||||
Common::EventHook m_frame_end_event;
|
Common::EventHook m_frame_end_event;
|
||||||
|
Common::EventHook m_after_present_event;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::unique_ptr<VertexManagerBase> g_vertex_manager;
|
extern std::unique_ptr<VertexManagerBase> g_vertex_manager;
|
||||||
|
|
|
@ -134,6 +134,7 @@ void VideoConfig::Refresh()
|
||||||
|
|
||||||
texture_filtering_mode = Config::Get(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING);
|
texture_filtering_mode = Config::Get(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING);
|
||||||
iMaxAnisotropy = Config::Get(Config::GFX_ENHANCE_MAX_ANISOTROPY);
|
iMaxAnisotropy = Config::Get(Config::GFX_ENHANCE_MAX_ANISOTROPY);
|
||||||
|
output_resampling_mode = Config::Get(Config::GFX_ENHANCE_OUTPUT_RESAMPLING);
|
||||||
sPostProcessingShader = Config::Get(Config::GFX_ENHANCE_POST_SHADER);
|
sPostProcessingShader = Config::Get(Config::GFX_ENHANCE_POST_SHADER);
|
||||||
bForceTrueColor = Config::Get(Config::GFX_ENHANCE_FORCE_TRUE_COLOR);
|
bForceTrueColor = Config::Get(Config::GFX_ENHANCE_FORCE_TRUE_COLOR);
|
||||||
bDisableCopyFilter = Config::Get(Config::GFX_ENHANCE_DISABLE_COPY_FILTER);
|
bDisableCopyFilter = Config::Get(Config::GFX_ENHANCE_DISABLE_COPY_FILTER);
|
||||||
|
@ -353,6 +354,7 @@ void CheckForConfigChanges()
|
||||||
{
|
{
|
||||||
OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL);
|
OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL);
|
||||||
g_vertex_manager->InvalidatePipelineObject();
|
g_vertex_manager->InvalidatePipelineObject();
|
||||||
|
g_vertex_manager->NotifyCustomShaderCacheOfHostChange(new_host_config);
|
||||||
g_shader_cache->SetHostConfig(new_host_config);
|
g_shader_cache->SetHostConfig(new_host_config);
|
||||||
g_shader_cache->Reload();
|
g_shader_cache->Reload();
|
||||||
g_framebuffer_manager->RecompileShaders();
|
g_framebuffer_manager->RecompileShaders();
|
||||||
|
|
|
@ -52,6 +52,17 @@ enum class TextureFilteringMode : int
|
||||||
Linear,
|
Linear,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class OutputResamplingMode : int
|
||||||
|
{
|
||||||
|
Default,
|
||||||
|
Bilinear,
|
||||||
|
BSpline,
|
||||||
|
MitchellNetravali,
|
||||||
|
CatmullRom,
|
||||||
|
SharpBilinear,
|
||||||
|
AreaSampling,
|
||||||
|
};
|
||||||
|
|
||||||
enum class ColorCorrectionRegion : int
|
enum class ColorCorrectionRegion : int
|
||||||
{
|
{
|
||||||
SMPTE_NTSCM,
|
SMPTE_NTSCM,
|
||||||
|
@ -103,6 +114,7 @@ struct VideoConfig final
|
||||||
bool bSSAA = false;
|
bool bSSAA = false;
|
||||||
int iEFBScale = 0;
|
int iEFBScale = 0;
|
||||||
TextureFilteringMode texture_filtering_mode = TextureFilteringMode::Default;
|
TextureFilteringMode texture_filtering_mode = TextureFilteringMode::Default;
|
||||||
|
OutputResamplingMode output_resampling_mode = OutputResamplingMode::Default;
|
||||||
int iMaxAnisotropy = 0;
|
int iMaxAnisotropy = 0;
|
||||||
std::string sPostProcessingShader;
|
std::string sPostProcessingShader;
|
||||||
bool bForceTrueColor = false;
|
bool bForceTrueColor = false;
|
||||||
|
|
|
@ -128,6 +128,9 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
void TearDown() override { cpu_info = CPUInfo(); }
|
void TearDown() override { cpu_info = CPUInfo(); }
|
||||||
|
|
||||||
|
void ResetCodeBuffer() { emitter->SetCodePtr(code_buffer, code_buffer_end); }
|
||||||
|
|
||||||
void ExpectDisassembly(const std::string& expected)
|
void ExpectDisassembly(const std::string& expected)
|
||||||
{
|
{
|
||||||
std::string disasmed;
|
std::string disasmed;
|
||||||
|
@ -186,8 +189,16 @@ protected:
|
||||||
|
|
||||||
EXPECT_EQ(expected_norm, disasmed_norm);
|
EXPECT_EQ(expected_norm, disasmed_norm);
|
||||||
|
|
||||||
// Reset code buffer afterwards.
|
ResetCodeBuffer();
|
||||||
emitter->SetCodePtr(code_buffer, code_buffer_end);
|
}
|
||||||
|
|
||||||
|
void ExpectBytes(const std::vector<u8> expected_bytes)
|
||||||
|
{
|
||||||
|
const std::vector<u8> code_bytes(code_buffer, emitter->GetWritableCodePtr());
|
||||||
|
|
||||||
|
EXPECT_EQ(expected_bytes, code_bytes);
|
||||||
|
|
||||||
|
ResetCodeBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<X64CodeBlock> emitter;
|
std::unique_ptr<X64CodeBlock> emitter;
|
||||||
|
@ -286,15 +297,13 @@ TEST_F(x64EmitterTest, POP_Register)
|
||||||
|
|
||||||
TEST_F(x64EmitterTest, JMP)
|
TEST_F(x64EmitterTest, JMP)
|
||||||
{
|
{
|
||||||
emitter->NOP(6);
|
emitter->NOP(1);
|
||||||
emitter->JMP(code_buffer);
|
emitter->JMP(code_buffer, XEmitter::Jump::Short);
|
||||||
ExpectDisassembly("multibyte nop "
|
ExpectBytes({/* nop */ 0x90, /* short jmp */ 0xeb, /* offset -3 */ 0xfd});
|
||||||
"jmp .-8");
|
|
||||||
|
|
||||||
emitter->NOP(6);
|
emitter->NOP(1);
|
||||||
emitter->JMP(code_buffer, XEmitter::Jump::Near);
|
emitter->JMP(code_buffer, XEmitter::Jump::Near);
|
||||||
ExpectDisassembly("multibyte nop "
|
ExpectBytes({/* nop */ 0x90, /* near jmp */ 0xe9, /* offset -6 */ 0xfa, 0xff, 0xff, 0xff});
|
||||||
"jmp .-11");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(x64EmitterTest, JMPptr_Register)
|
TEST_F(x64EmitterTest, JMPptr_Register)
|
||||||
|
@ -306,11 +315,93 @@ TEST_F(x64EmitterTest, JMPptr_Register)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: J/SetJumpTarget
|
TEST_F(x64EmitterTest, J)
|
||||||
|
{
|
||||||
|
FixupBranch jump = emitter->J(XEmitter::Jump::Short);
|
||||||
|
emitter->NOP(1);
|
||||||
|
emitter->SetJumpTarget(jump);
|
||||||
|
ExpectBytes({/* short jmp */ 0xeb, /* offset 1 */ 0x1, /* nop */ 0x90});
|
||||||
|
|
||||||
// TODO: CALL
|
jump = emitter->J(XEmitter::Jump::Near);
|
||||||
|
emitter->NOP(1);
|
||||||
|
emitter->SetJumpTarget(jump);
|
||||||
|
ExpectBytes({/* near jmp */ 0xe9, /* offset 1 */ 0x1, 0x0, 0x0, 0x0, /* nop */ 0x90});
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: J_CC
|
TEST_F(x64EmitterTest, CALL)
|
||||||
|
{
|
||||||
|
FixupBranch call = emitter->CALL();
|
||||||
|
emitter->NOP(6);
|
||||||
|
emitter->SetJumpTarget(call);
|
||||||
|
ExpectDisassembly("call .+6 "
|
||||||
|
"multibyte nop");
|
||||||
|
|
||||||
|
const u8* const code_start = emitter->GetCodePtr();
|
||||||
|
emitter->CALL(code_start + 5);
|
||||||
|
ExpectDisassembly("call .+0");
|
||||||
|
|
||||||
|
emitter->NOP(6);
|
||||||
|
emitter->CALL(code_start);
|
||||||
|
ExpectDisassembly("multibyte nop "
|
||||||
|
"call .-11");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(x64EmitterTest, J_CC)
|
||||||
|
{
|
||||||
|
for (const auto& [condition_code, condition_name] : ccnames)
|
||||||
|
{
|
||||||
|
FixupBranch fixup = emitter->J_CC(condition_code, XEmitter::Jump::Short);
|
||||||
|
emitter->NOP(1);
|
||||||
|
emitter->SetJumpTarget(fixup);
|
||||||
|
const u8 short_jump_condition_opcode = 0x70 + condition_code;
|
||||||
|
ExpectBytes({short_jump_condition_opcode, /* offset 1 */ 0x1, /* nop */ 0x90});
|
||||||
|
|
||||||
|
fixup = emitter->J_CC(condition_code, XEmitter::Jump::Near);
|
||||||
|
emitter->NOP(1);
|
||||||
|
emitter->SetJumpTarget(fixup);
|
||||||
|
const u8 near_jump_condition_opcode = 0x80 + condition_code;
|
||||||
|
ExpectBytes({/* two byte opcode */ 0x0f, near_jump_condition_opcode, /* offset 1 */ 0x1, 0x0,
|
||||||
|
0x0, 0x0, /* nop */ 0x90});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify a short jump is used when possible and a near jump when needed.
|
||||||
|
//
|
||||||
|
// A short jump to a particular address and a near jump to that same address will have different
|
||||||
|
// offsets. This is because short jumps are 2 bytes and near jumps are 6 bytes, and the offset to
|
||||||
|
// the target is calculated from the address of the next instruction.
|
||||||
|
|
||||||
|
const u8* const code_start = emitter->GetCodePtr();
|
||||||
|
constexpr int short_jump_bytes = 2;
|
||||||
|
const u8* const next_byte_after_short_jump_instruction = code_start + short_jump_bytes;
|
||||||
|
|
||||||
|
constexpr int longest_backward_short_jump = 0x80;
|
||||||
|
const u8* const furthest_byte_reachable_with_backward_short_jump =
|
||||||
|
next_byte_after_short_jump_instruction - longest_backward_short_jump;
|
||||||
|
emitter->J_CC(CC_O, furthest_byte_reachable_with_backward_short_jump);
|
||||||
|
ExpectBytes({/* JO opcode */ 0x70, /* offset -128 */ 0x80});
|
||||||
|
|
||||||
|
const u8* const closest_byte_requiring_backward_near_jump =
|
||||||
|
furthest_byte_reachable_with_backward_short_jump - 1;
|
||||||
|
emitter->J_CC(CC_O, closest_byte_requiring_backward_near_jump);
|
||||||
|
// This offset is 5 less than the offset for the furthest backward short jump. -1 because this
|
||||||
|
// target is 1 byte before the short target, and -4 because the address of the next instruction is
|
||||||
|
// 4 bytes further away from the jump target than it would be with a short jump.
|
||||||
|
ExpectBytes({/* two byte JO opcode */ 0x0f, 0x80, /* offset -133 */ 0x7b, 0xff, 0xff, 0xff});
|
||||||
|
|
||||||
|
constexpr int longest_forward_short_jump = 0x7f;
|
||||||
|
const u8* const furthest_byte_reachable_with_forward_short_jump =
|
||||||
|
next_byte_after_short_jump_instruction + longest_forward_short_jump;
|
||||||
|
emitter->J_CC(CC_O, furthest_byte_reachable_with_forward_short_jump);
|
||||||
|
ExpectBytes({/* JO opcode */ 0x70, /* offset 127 */ 0x7f});
|
||||||
|
|
||||||
|
const u8* const closest_byte_requiring_forward_near_jump =
|
||||||
|
furthest_byte_reachable_with_forward_short_jump + 1;
|
||||||
|
emitter->J_CC(CC_O, closest_byte_requiring_forward_near_jump);
|
||||||
|
// This offset is 3 less than the offset for the furthest forward short jump. +1 because this
|
||||||
|
// target is 1 byte after the short target, and -4 because the address of the next instruction is
|
||||||
|
// 4 bytes closer to the jump target than it would be with a short jump.
|
||||||
|
ExpectBytes({/* two byte JO opcode */ 0x0f, 0x80, /* offset 124 */ 0x7c, 0x0, 0x0, 0x0});
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(x64EmitterTest, SETcc)
|
TEST_F(x64EmitterTest, SETcc)
|
||||||
{
|
{
|
||||||
|
|
251
docs/CustomPipelineGraphicsMod.md
Normal file
251
docs/CustomPipelineGraphicsMod.md
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
# Dolphin Custom Pipeline Specification
|
||||||
|
|
||||||
|
Dolphin provides content creators a way to overwrite its internal graphics pipeline data using graphics mods. At the moment, this supports modifying only the pixel shader. This document will describe the specification and give some examples.
|
||||||
|
|
||||||
|
## Graphics mod metadata format
|
||||||
|
|
||||||
|
This feature is powered by graphics mods. This document assumes the user is familiar with them and will only detail the action specific data needed to trigger this capability.
|
||||||
|
|
||||||
|
The action type for this feature is `custom_pipeline`. This action has the following data:
|
||||||
|
|
||||||
|
|Identifier |Required | Since |
|
||||||
|
|-------------------------|---------|-------|
|
||||||
|
|``passes`` | **Yes** | v1 |
|
||||||
|
|
||||||
|
`passes` is an array of pass blobs. Note that at the moment, Dolphin only supports a single pass. Each pass can have the following data:
|
||||||
|
|
||||||
|
|Identifier |Required | Since |
|
||||||
|
|-------------------------|---------|-------|
|
||||||
|
|``pixel_material_asset`` | **Yes** | v1 |
|
||||||
|
|
||||||
|
Here `pixel_material_asset` is the name of a material asset.
|
||||||
|
|
||||||
|
A full example is given below:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"name": "material_replace_normal",
|
||||||
|
"data":
|
||||||
|
{
|
||||||
|
"": "normal.material.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "shader_replace_normal",
|
||||||
|
"data":
|
||||||
|
{
|
||||||
|
"metadata": "replace_normal.shader.json",
|
||||||
|
"shader": "replace_normal.glsl"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "normal_texture",
|
||||||
|
"data":
|
||||||
|
{
|
||||||
|
"": "normal_texture.png"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"features": [
|
||||||
|
{
|
||||||
|
"action": "custom_pipeline",
|
||||||
|
"action_data": {
|
||||||
|
"passes": [
|
||||||
|
{
|
||||||
|
"pixel_material_asset": "material_replace_normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"group": "PipelineTarget"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "PipelineTarget",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"texture_filename": "tex1_512x512_m_afdbe7efg332229e_14",
|
||||||
|
"type": "draw_started"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"texture_filename": "tex1_512x512_m_afdbe7efg332229e_14",
|
||||||
|
"type": "create_texture"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## The shader format
|
||||||
|
|
||||||
|
The shaders are written in GLSL and converted to the target shader that the backend uses internally. The user is expected to provide an entrypoint with the following signature:
|
||||||
|
|
||||||
|
```
|
||||||
|
vec4 custom_main( in CustomShaderData data )
|
||||||
|
```
|
||||||
|
|
||||||
|
`CustomShaderData` encompasses all the data that Dolphin will pass to the user (in addition to the `samp` variable outlined above which is how textures are accessed). It has the following structure:
|
||||||
|
|
||||||
|
|Name | Type | Since | Description |
|
||||||
|
|-----------------------------|-------------------------|-------|-----------------------------------------------------------------------------------------------|
|
||||||
|
|``position`` | vec3 | v1 | The position of this pixel in _view space_ |
|
||||||
|
|``normal`` | vec3 | v1 | The normal of this pixel in _view space_ |
|
||||||
|
|``texcoord`` | vec3[] | v1 | An array of texture coordinates, the amount available is specified by ``texcoord_count`` |
|
||||||
|
|``texcoord_count`` | uint | v1 | The count of texture coordinates |
|
||||||
|
|``texmap_to_texcoord_index`` | uint[] | v1 | An array of texture units to texture coordinate values |
|
||||||
|
|``lights_chan0_color`` | CustomShaderLightData[] | v1 | An array of color lights for channel 0, the amount is specified by ``light_chan0_color_count``|
|
||||||
|
|``lights_chan0_alpha`` | CustomShaderLightData[] | v1 | An array of alpha lights for channel 0, the amount is specified by ``light_chan0_alpha_count``|
|
||||||
|
|``lights_chan1_color`` | CustomShaderLightData[] | v1 | An array of color lights for channel 1, the amount is specified by ``light_chan1_color_count``|
|
||||||
|
|``lights_chan1_alpha`` | CustomShaderLightData[] | v1 | An array of alpha lights for channel 1, the amount is specified by ``light_chan1_alpha_count``|
|
||||||
|
|``ambient_lighting`` | vec4[] | v1 | An array of ambient lighting values. Count is two, one for each color channel |
|
||||||
|
|``base_material`` | vec4[] | v1 | An array of the base material values. Count is two, one for each color channel |
|
||||||
|
|``tev_stages`` | CustomShaderTevStage[] | v1 | An array of TEV stages, the amount is specified by ``tev_stage_count`` |
|
||||||
|
|``tev_stage_count`` | uint | v1 | The count of TEV stages |
|
||||||
|
|``final_color`` | vec4 | v1 | The final color generated by Dolphin after all TEV stages are executed |
|
||||||
|
|``time_ms`` | uint | v1 | The time that has passed in milliseconds, since the game was started. Useful for animating |
|
||||||
|
|
||||||
|
`CustomShaderLightData` is used to denote lighting data the game is applying when rendering the specific draw call. It has the following structure:
|
||||||
|
|
||||||
|
|Name | Type | Since | Description |
|
||||||
|
|-------------------------|-------------------------|-------|-------------------------------------------------------------------------------------------------|
|
||||||
|
|``position`` | vec3 | v1 | The position of the light in _view space_ |
|
||||||
|
|``direction`` | vec3 | v1 | The direction in _view space_ the light is pointing (only applicable for point and spot lights) |
|
||||||
|
|``color`` | vec3 | v1 | The color of the light |
|
||||||
|
|``attenuation_type`` | uint | v1 | The attentuation type of the light. See details below |
|
||||||
|
|``cosatt`` | vec4 | v1 | The cos attenuation values used |
|
||||||
|
|``distatt`` | vec4 | v1 | The distance attenuation values used |
|
||||||
|
|
||||||
|
The `attenuation_type` is defined as a `uint` but is effecitvely an enumeration. It has the following values:
|
||||||
|
|
||||||
|
|Name | Since | Description |
|
||||||
|
|--------------------------------------------------|-------|-------------------------------------------------------------------------|
|
||||||
|
|``CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_POINT`` | v1 | This value denotes the lighting attentuation is for a point light |
|
||||||
|
|``CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_DIR`` | v1 | This value denotes the lighting attentuation is for a directional light |
|
||||||
|
|``CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_SPOT`` | v1 | This value denotes the lighting attentuation is for a directional light |
|
||||||
|
|
||||||
|
|
||||||
|
`CustomShaderTevStage` is used to denote the various TEV operations. Each operation describes a graphical operation that the game is applying when rendering the specific draw call. It has the following structure:
|
||||||
|
|
||||||
|
|Name | Type | Since | Description |
|
||||||
|
|-------------------------|----------------------------------|-------|-------------------------------------------------------------------------------|
|
||||||
|
|``input_color`` | CustomShaderTevStageInputColor[] | v1 | The four color inputs that are used to produce the final output of this stage |
|
||||||
|
|``input_alpha`` | CustomShaderTevStageInputAlpha[] | v1 | The four alpha inputs that are used to produce the final output of this stage |
|
||||||
|
|``texmap`` | uint | v1 | The texture unit for this stage |
|
||||||
|
|``output_color`` | vec4 | v1 | The final output color this stage produces |
|
||||||
|
|
||||||
|
|
||||||
|
`CustomShaderTevStageInputColor` is a single input TEV operation for a color value. It has the following structure:
|
||||||
|
|
||||||
|
|Name | Type | Since | Description |
|
||||||
|
|-------------------------|------|-------|-------------------------------------------------|
|
||||||
|
|``input_type`` | uint | v1 | The input type of the input. See details below |
|
||||||
|
|``value`` | vec3 | v1 | The value of input |
|
||||||
|
|
||||||
|
The `input_type` is defined as a `uint` but is effectively an enumeration. it has the following values:
|
||||||
|
|
||||||
|
|Name | Since | Description |
|
||||||
|
|--------------------------------------------------|-------|---------------------------------------------------------------------------|
|
||||||
|
|``CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_PREV`` | v1 | The value is provided by the last stage |
|
||||||
|
|``CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_COLOR`` | v1 | The value is provided by the color data |
|
||||||
|
|``CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_TEX`` | v1 | The value is provided by a texture |
|
||||||
|
|``CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_RAS`` | v1 | |
|
||||||
|
|``CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_KONST`` | v1 | The value is a constant value defined by the software |
|
||||||
|
|``CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_NUMERIC`` | v1 | The value is a constant numeric value like vec3(0, 0, 0) or vec3(1, 1, 1) |
|
||||||
|
|
||||||
|
`CustomShaderTevStageInputAlpha` is a single input TEV operation for an alpha value. It has the following structure:
|
||||||
|
|
||||||
|
|Name | Type | Since | Description |
|
||||||
|
|-------------------------|------|-------|-------------------------------------------------------------------------------|
|
||||||
|
|``input_type`` | uint | v1 | The input type of the input. See `input_type` for color input stages |
|
||||||
|
|``value`` | uint | v1 | The value of input |
|
||||||
|
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
Below are a handful of examples.
|
||||||
|
|
||||||
|
### Single color
|
||||||
|
|
||||||
|
The following shader displays the color red on the screen:
|
||||||
|
|
||||||
|
```glsl
|
||||||
|
vec4 custom_main( in CustomShaderData data )
|
||||||
|
{
|
||||||
|
return vec4(1.0, 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Normal
|
||||||
|
|
||||||
|
The following shader displays the normal on the screen:
|
||||||
|
|
||||||
|
```glsl
|
||||||
|
vec4 custom_main( in CustomShaderData data )
|
||||||
|
{
|
||||||
|
return vec4(data.normal * 0.5 + 0.5, 1);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Reading a texture
|
||||||
|
|
||||||
|
The following shader displays the contents of the texture denoted in the shader asset as `MY_TEX`:
|
||||||
|
|
||||||
|
```glsl
|
||||||
|
vec4 custom_main( in CustomShaderData data )
|
||||||
|
{
|
||||||
|
return texture(samp[MY_TEX_UNIT], MY_TEX_COORD);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Capturing the first texture the game renders with
|
||||||
|
|
||||||
|
The following shader would display the contents of the first texture the game uses, ignoring any other operations. If no stages are available or none exist with a texture it would use the final color of all the staging operations:
|
||||||
|
|
||||||
|
```glsl
|
||||||
|
vec4 custom_main( in CustomShaderData data )
|
||||||
|
{
|
||||||
|
vec4 final_color = data.final_color;
|
||||||
|
uint texture_set = 0;
|
||||||
|
for (uint i = 0; i < data.tev_stage_count; i++)
|
||||||
|
{
|
||||||
|
// There are 4 color inputs
|
||||||
|
for (uint j = 0; j < 4; j++)
|
||||||
|
{
|
||||||
|
if (data.tev_stages[i].input_color[j].input_type == CUSTOM_SHADER_TEV_STAGE_INPUT_TYPE_TEX && texture_set == 0)
|
||||||
|
{
|
||||||
|
final_color = vec4(data.tev_stages[i].input_color[j].value, 1.0);
|
||||||
|
texture_set = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return final_color;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Applying lighting with a point type attenuation
|
||||||
|
|
||||||
|
The following shader would apply the lighting for any point lights used during the draw for channel 0's color lights, using blue as a base color:
|
||||||
|
|
||||||
|
```glsl
|
||||||
|
vec4 custom_main( in CustomShaderData data )
|
||||||
|
{
|
||||||
|
float total_diffuse = 0;
|
||||||
|
for (int i = 0; i < data.light_chan0_color_count; i++)
|
||||||
|
{
|
||||||
|
if (data.lights_chan0_color[i].attenuation_type == CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_POINT)
|
||||||
|
{
|
||||||
|
vec3 light_dir = normalize(data.lights_chan0_color[i].position - data.position.xyz);
|
||||||
|
float attn = (dot(normal, light_dir) >= 0.0) ? max(0.0, dot(normal, data.lights_chan0_color[i].direction.xyz)) : 0.0;
|
||||||
|
vec3 cosAttn = data.lights_chan0_color[i].cosatt.xyz;
|
||||||
|
vec3 distAttn = data.lights_chan0_color[i].distatt.xyz;
|
||||||
|
attn = max(0.0, dot(cosAttn, vec3(1.0, attn, attn*attn))) / dot(distAttn, vec3(1.0, attn, attn * attn));
|
||||||
|
total_diffuse += attn * max(0.0, dot(normal, light_dir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vec4(total_diffuse * vec3(0, 0, 1), 1);
|
||||||
|
}
|
||||||
|
```
|
Loading…
Add table
Add a link
Reference in a new issue