8484#include "../../retroarch.h"
8585
8686#include "d3d_shaders/shaders_common.h"
87+ #include "d3d_shaders/ribbon_sm3.hlsl.h"
88+ #include "d3d_shaders/ribbon_simple_sm3.hlsl.h"
89+ #include "d3d_shaders/simple_snow_sm3.hlsl.h"
90+ #include "d3d_shaders/snow_sm3.hlsl.h"
91+ #include "d3d_shaders/bokeh_sm3.hlsl.h"
92+ #include "d3d_shaders/snowflake_sm3.hlsl.h"
8793
8894static const char * stock_hlsl_program = CG (
8995 void main_vertex
@@ -645,12 +651,18 @@ typedef struct hlsl_renderchain
645651 hlsl_pass_data_t pass_data [GFX_MAX_SHADERS + 1 ];
646652 unsigned pass_data_count ;
647653 hlsl_pass_data_t stock_data ;
654+ /* XMB pipeline shaders */
655+ struct shader_pass pipeline_shaders [6 ]; /* MENU..MENU_6 */
656+ hlsl_pass_data_t pipeline_data [6 ];
657+ bool pipeline_inited ;
648658} hlsl_renderchain_t ;
649659
650660/* Pipeline vertex buffer for menu shader effects (VIDEO_SHADER_MENU, etc.).
651661 * Stored as a file-static since the d3d9 menu_display struct
652662 * does not have a pipeline_vbo member like d3d10_video_t does. */
653663static LPDIRECT3DVERTEXBUFFER9 d3d9_hlsl_menu_pipeline_vbo = NULL ;
664+ static LPDIRECT3DVERTEXBUFFER9 d3d9_hlsl_menu_fullscreen_vbo = NULL ;
665+ static LPDIRECT3DVERTEXDECLARATION9 d3d9_hlsl_pipeline_decl = NULL ;
654666static LPDIRECT3DVERTEXDECLARATION9 d3d9_hlsl_overlay_decl = NULL ;
655667
656668static void d3d9_vertex_buffer_free (void * vertex_data , void * vertex_declaration )
@@ -788,21 +800,60 @@ static void gfx_display_d3d9_hlsl_draw(gfx_display_ctx_draw_t *draw,
788800 case VIDEO_SHADER_MENU :
789801 case VIDEO_SHADER_MENU_2 :
790802 case VIDEO_SHADER_MENU_3 :
803+ case VIDEO_SHADER_MENU_4 :
804+ case VIDEO_SHADER_MENU_5 :
805+ case VIDEO_SHADER_MENU_6 :
791806 {
792- /* Draw the pipeline vertices using the stock shader,
793- * then restore blend state and menu display vertex state.
794- * Adapted from d3d10 gfx_display_d3d10_draw pipeline path. */
795807 hlsl_renderchain_t * _chain = (hlsl_renderchain_t * )d3d -> renderchain_data ;
796808
797- if (_chain )
809+ if (_chain && _chain -> pipeline_inited )
798810 {
799- IDirect3DDevice9_SetVertexShader (dev , (LPDIRECT3DVERTEXSHADER9 )(& _chain -> stock_shader )-> vprg );
800-
801- IDirect3DDevice9_SetPixelShader (dev , (LPDIRECT3DPIXELSHADER9 )(& _chain -> stock_shader )-> fprg );
811+ unsigned idx = VIDEO_SHADER_MENU - draw -> pipeline_id ;
812+ struct shader_pass * shader = & _chain -> pipeline_shaders [idx ];
813+
814+ IDirect3DDevice9_SetVertexShader (dev ,
815+ (LPDIRECT3DVERTEXSHADER9 )shader -> vprg );
816+ IDirect3DDevice9_SetPixelShader (dev ,
817+ (LPDIRECT3DPIXELSHADER9 )shader -> fprg );
818+ IDirect3DDevice9_SetVertexDeclaration (dev ,
819+ (LPDIRECT3DVERTEXDECLARATION9 )d3d -> menu_display .decl );
820+
821+ /* Snow/bokeh/snowflake need MVP matrix set */
822+ if (draw -> pipeline_id <= VIDEO_SHADER_MENU_3 )
823+ {
824+ hlsl_pass_data_t * pd = & _chain -> pipeline_data [idx ];
825+ /* Row-major ortho for mul(matrix, vector) in shader.
826+ * D3D9 SetVertexShaderConstantF stores rows sequentially.
827+ * mul(M, v) computes dot(row[i], v) — correct with row-major.
828+ * Maps X [0,1]→[-1,1], Y [0,1]→[-1,1], Z pass-through. */
829+ static const float ortho_mvp [16 ] = {
830+ 2.0f , 0.0f , 0.0f , 0.0f ,
831+ 0.0f , 2.0f , 0.0f , 0.0f ,
832+ 0.0f , 0.0f , 1.0f , 0.0f ,
833+ -1.0f , -1.0f , 0.0f , 1.0f
834+ };
835+ {
836+ int reg = d3d9_hlsl_ctab_find_register (
837+ pd -> vs_bytecode , pd -> vs_bytecode_dwords ,
838+ "modelViewProj" , NULL , NULL );
839+ if (reg >= 0 )
840+ d3d9_hlsl_set_vs_const (dev , reg , ortho_mvp , 4 );
841+ }
842+ }
802843
803844 IDirect3DDevice9_DrawPrimitive (dev , D3DPT_TRIANGLESTRIP ,
804845 0 , draw -> coords -> vertices - 2 );
805846 }
847+ else if (_chain )
848+ {
849+ /* Fallback to stock shader */
850+ IDirect3DDevice9_SetVertexShader (dev ,
851+ (LPDIRECT3DVERTEXSHADER9 )(& _chain -> stock_shader )-> vprg );
852+ IDirect3DDevice9_SetPixelShader (dev ,
853+ (LPDIRECT3DPIXELSHADER9 )(& _chain -> stock_shader )-> fprg );
854+ IDirect3DDevice9_DrawPrimitive (dev , D3DPT_TRIANGLESTRIP ,
855+ 0 , draw -> coords -> vertices - 2 );
856+ }
806857
807858 /* Re-enable alpha blending after pipeline draw */
808859 IDirect3DDevice9_SetRenderState (dev ,
@@ -818,6 +869,16 @@ static void gfx_display_d3d9_hlsl_draw(gfx_display_ctx_draw_t *draw,
818869 0 , sizeof (Vertex ));
819870 IDirect3DDevice9_SetVertexDeclaration (dev ,
820871 (LPDIRECT3DVERTEXDECLARATION9 )d3d -> menu_display .decl );
872+
873+ /* Restore stock shader and its constants so subsequent
874+ * non-pipeline draws (text, icons) work correctly. */
875+ if (_chain )
876+ {
877+ IDirect3DDevice9_SetVertexShader (dev ,
878+ (LPDIRECT3DVERTEXSHADER9 )(& _chain -> stock_shader )-> vprg );
879+ IDirect3DDevice9_SetPixelShader (dev ,
880+ (LPDIRECT3DPIXELSHADER9 )(& _chain -> stock_shader )-> fprg );
881+ }
821882 return ;
822883 }
823884 default :
@@ -1080,19 +1141,79 @@ static void gfx_display_d3d9_hlsl_draw_pipeline(
10801141
10811142 draw -> coords -> vertices = ca -> coords .vertices ;
10821143
1083- /* Set pipeline blend state */
1144+ /* Set pipeline blend state — ribbon uses multiplicative blend
1145+ * (DESTCOLOR + ONE) matching D3D11's blend_pipeline. */
10841146 IDirect3DDevice9_SetRenderState (d3d -> dev ,
1085- D3DRS_SRCBLEND , D3DBLEND_SRCALPHA );
1147+ D3DRS_SRCBLEND , D3DBLEND_DESTCOLOR );
10861148 IDirect3DDevice9_SetRenderState (d3d -> dev ,
1087- D3DRS_DESTBLEND , D3DBLEND_INVSRCALPHA );
1149+ D3DRS_DESTBLEND , D3DBLEND_ONE );
10881150 IDirect3DDevice9_SetRenderState (d3d -> dev ,
10891151 D3DRS_ALPHABLENDENABLE , true);
10901152 break ;
10911153 }
10921154
10931155 case VIDEO_SHADER_MENU_3 :
1156+ case VIDEO_SHADER_MENU_4 :
1157+ case VIDEO_SHADER_MENU_5 :
1158+ case VIDEO_SHADER_MENU_6 :
10941159 {
1095- draw -> coords -> vertices = 4 ;
1160+ static struct video_coords blank_coords = {0 };
1161+
1162+ /* Fullscreen quad for snow/bokeh/snowflake effects */
1163+ if (!d3d9_hlsl_menu_fullscreen_vbo )
1164+ {
1165+ Vertex verts [4 ];
1166+ verts [0 ].x = 0.0f ; verts [0 ].y = 0.0f ; verts [0 ].z = 0.0f ;
1167+ verts [0 ].u = 0.0f ; verts [0 ].v = 1.0f ;
1168+ verts [0 ].color = D3DCOLOR_ARGB (0xFF , 0xFF , 0xFF , 0xFF );
1169+ verts [1 ].x = 1.0f ; verts [1 ].y = 0.0f ; verts [1 ].z = 0.0f ;
1170+ verts [1 ].u = 1.0f ; verts [1 ].v = 1.0f ;
1171+ verts [1 ].color = D3DCOLOR_ARGB (0xFF , 0xFF , 0xFF , 0xFF );
1172+ verts [2 ].x = 0.0f ; verts [2 ].y = 1.0f ; verts [2 ].z = 0.0f ;
1173+ verts [2 ].u = 0.0f ; verts [2 ].v = 0.0f ;
1174+ verts [2 ].color = D3DCOLOR_ARGB (0xFF , 0xFF , 0xFF , 0xFF );
1175+ verts [3 ].x = 1.0f ; verts [3 ].y = 1.0f ; verts [3 ].z = 0.0f ;
1176+ verts [3 ].u = 1.0f ; verts [3 ].v = 0.0f ;
1177+ verts [3 ].color = D3DCOLOR_ARGB (0xFF , 0xFF , 0xFF , 0xFF );
1178+
1179+ if (SUCCEEDED (IDirect3DDevice9_CreateVertexBuffer (
1180+ d3d -> dev , 4 * sizeof (Vertex ),
1181+ D3DUSAGE_WRITEONLY , 0 , D3DPOOL_DEFAULT ,
1182+ (LPDIRECT3DVERTEXBUFFER9 * )& d3d9_hlsl_menu_fullscreen_vbo , NULL )))
1183+ {
1184+ void * lock = NULL ;
1185+ IDirect3DVertexBuffer9_Lock (
1186+ (LPDIRECT3DVERTEXBUFFER9 )d3d9_hlsl_menu_fullscreen_vbo ,
1187+ 0 , 0 , & lock , 0 );
1188+ if (lock )
1189+ {
1190+ memcpy (lock , verts , sizeof (verts ));
1191+ IDirect3DVertexBuffer9_Unlock (
1192+ (LPDIRECT3DVERTEXBUFFER9 )d3d9_hlsl_menu_fullscreen_vbo );
1193+ }
1194+ }
1195+ }
1196+
1197+ if (d3d9_hlsl_menu_fullscreen_vbo )
1198+ {
1199+ IDirect3DDevice9_SetStreamSource (d3d -> dev , 0 ,
1200+ (LPDIRECT3DVERTEXBUFFER9 )d3d9_hlsl_menu_fullscreen_vbo ,
1201+ 0 , sizeof (Vertex ));
1202+ }
1203+
1204+ /* Use separate coords to avoid mutating the shared
1205+ * ca->coords.vertices (which ribbon needs at 8064). */
1206+ blank_coords .vertices = 4 ;
1207+ draw -> coords = & blank_coords ;
1208+ draw -> prim_type = GFX_DISPLAY_PRIM_TRIANGLESTRIP ;
1209+
1210+ /* Set blend state for particle effects */
1211+ IDirect3DDevice9_SetRenderState (d3d -> dev ,
1212+ D3DRS_SRCBLEND , D3DBLEND_SRCALPHA );
1213+ IDirect3DDevice9_SetRenderState (d3d -> dev ,
1214+ D3DRS_DESTBLEND , D3DBLEND_INVSRCALPHA );
1215+ IDirect3DDevice9_SetRenderState (d3d -> dev ,
1216+ D3DRS_ALPHABLENDENABLE , true);
10961217 break ;
10971218 }
10981219
@@ -1105,7 +1226,56 @@ static void gfx_display_d3d9_hlsl_draw_pipeline(
11051226
11061227 {
11071228 hlsl_renderchain_t * _chain = (hlsl_renderchain_t * )d3d -> renderchain_data ;
1108- if (_chain )
1229+ if (_chain && _chain -> pipeline_inited
1230+ && draw -> pipeline_id <= VIDEO_SHADER_MENU
1231+ && draw -> pipeline_id >= VIDEO_SHADER_MENU_6 )
1232+ {
1233+ unsigned idx = VIDEO_SHADER_MENU - draw -> pipeline_id ;
1234+ hlsl_pass_data_t * pd = & _chain -> pipeline_data [idx ];
1235+
1236+ /* Set time uniform for all pipeline shaders */
1237+ d3d9_hlsl_set_param_1f (pd -> vs_bytecode , pd -> vs_bytecode_dwords ,
1238+ true, d3d -> dev , "time" , & t );
1239+ d3d9_hlsl_set_param_1f (pd -> ps_bytecode , pd -> ps_bytecode_dwords ,
1240+ false, d3d -> dev , "time" , & t );
1241+
1242+ /* Set OutputSize for snow/bokeh/snowflake shaders */
1243+ if (draw -> pipeline_id <= VIDEO_SHADER_MENU_3 )
1244+ {
1245+ D3DVIEWPORT9 vp ;
1246+ IDirect3DDevice9_GetViewport (d3d -> dev , & vp );
1247+ {
1248+ float output_size [4 ];
1249+ int reg ;
1250+ output_size [0 ] = (float )vp .Width ;
1251+ output_size [1 ] = (float )vp .Height ;
1252+ output_size [2 ] = 0.0f ;
1253+ output_size [3 ] = 0.0f ;
1254+ /* Set OutputSize as a full register (float2 occupies one register) */
1255+ reg = d3d9_hlsl_ctab_find_register (
1256+ pd -> vs_bytecode , pd -> vs_bytecode_dwords ,
1257+ "OutputSize" , NULL , NULL );
1258+ if (reg >= 0 )
1259+ d3d9_hlsl_set_vs_const (d3d -> dev , reg , output_size , 1 );
1260+ reg = d3d9_hlsl_ctab_find_register (
1261+ pd -> ps_bytecode , pd -> ps_bytecode_dwords ,
1262+ "OutputSize" , NULL , NULL );
1263+ if (reg >= 0 )
1264+ d3d9_hlsl_set_ps_const (d3d -> dev , reg , output_size , 1 );
1265+ }
1266+ }
1267+
1268+ /* Set alpha for ribbon shaders */
1269+ if (draw -> pipeline_id >= VIDEO_SHADER_MENU_2 )
1270+ {
1271+ float alpha_val = draw -> color ? draw -> color [3 ] : 1.0f ;
1272+ d3d9_hlsl_set_param_1f (pd -> vs_bytecode , pd -> vs_bytecode_dwords ,
1273+ true, d3d -> dev , "alpha" , & alpha_val );
1274+ d3d9_hlsl_set_param_1f (pd -> ps_bytecode , pd -> ps_bytecode_dwords ,
1275+ false, d3d -> dev , "alpha" , & alpha_val );
1276+ }
1277+ }
1278+ else if (_chain )
11091279 {
11101280 d3d9_hlsl_set_param_1f (
11111281 _chain -> stock_data .vs_bytecode ,
@@ -2546,6 +2716,35 @@ static bool hlsl_d3d9_renderchain_init(
25462716 IDirect3DDevice9_SetVertexShader (dev , (LPDIRECT3DVERTEXSHADER9 )(& chain -> stock_shader )-> vprg );
25472717 IDirect3DDevice9_SetPixelShader (dev , (LPDIRECT3DPIXELSHADER9 )(& chain -> stock_shader )-> fprg );
25482718
2719+ /* Compile XMB pipeline shaders */
2720+ {
2721+ const char * pipeline_sources [6 ];
2722+ unsigned i ;
2723+ pipeline_sources [0 ] = hlsl_ribbon_program ;
2724+ pipeline_sources [1 ] = hlsl_ribbon_simple_program ;
2725+ pipeline_sources [2 ] = hlsl_simple_snow_program ;
2726+ pipeline_sources [3 ] = hlsl_snow_program ;
2727+ pipeline_sources [4 ] = hlsl_bokeh_program ;
2728+ pipeline_sources [5 ] = hlsl_snowflake_program ;
2729+ chain -> pipeline_inited = true;
2730+ for (i = 0 ; i < 6 ; i ++ )
2731+ {
2732+ hlsl_uniform_map_init (& chain -> pipeline_data [i ].vs_map );
2733+ hlsl_uniform_map_init (& chain -> pipeline_data [i ].ps_map );
2734+ chain -> pipeline_data [i ].vs_bytecode = NULL ;
2735+ chain -> pipeline_data [i ].ps_bytecode = NULL ;
2736+ if (!d3d9_hlsl_load_program_ex (dev ,
2737+ & chain -> pipeline_shaders [i ],
2738+ pipeline_sources [i ],
2739+ & chain -> pipeline_data [i ]))
2740+ {
2741+ RARCH_WARN ("[D3D9 HLSL] Could not compile XMB pipeline shader %u, effects disabled.\n" , i );
2742+ chain -> pipeline_inited = false;
2743+ break ;
2744+ }
2745+ }
2746+ }
2747+
25492748 return true;
25502749}
25512750
@@ -6222,6 +6421,16 @@ static void d3d9_hlsl_deinitialize(d3d9_video_t *d3d)
62226421 d3d9_vertex_buffer_free (d3d -> menu_display .buffer ,
62236422 d3d -> menu_display .decl );
62246423
6424+ if (d3d9_hlsl_menu_fullscreen_vbo )
6425+ {
6426+ IDirect3DVertexBuffer9_Release (d3d9_hlsl_menu_fullscreen_vbo );
6427+ d3d9_hlsl_menu_fullscreen_vbo = NULL ;
6428+ }
6429+ if (d3d9_hlsl_pipeline_decl )
6430+ {
6431+ IDirect3DVertexDeclaration9_Release (d3d9_hlsl_pipeline_decl );
6432+ d3d9_hlsl_pipeline_decl = NULL ;
6433+ }
62256434 if (d3d9_hlsl_menu_pipeline_vbo )
62266435 {
62276436 IDirect3DVertexBuffer9_Release (d3d9_hlsl_menu_pipeline_vbo );
0 commit comments