@@ -589,31 +589,9 @@ fn init_composite_texture(width: u32, height: u32) -> Result<(), &'static str> {
589589 )
590590 } ) ?;
591591
592- // Attach backing memory
592+ // Attach backing memory (per-page scatter-gather, required by Parallels)
593593 with_device_state ( |state| {
594- unsafe {
595- let cmd_ptr = & raw mut PCI_CMD_BUF ;
596- let attach = & mut * ( ( * cmd_ptr) . data . as_mut_ptr ( ) as * mut PciAttachBackingCmd ) ;
597- * attach = PciAttachBackingCmd {
598- cmd : VirtioGpuResourceAttachBacking {
599- hdr : VirtioGpuCtrlHdr {
600- type_ : cmd:: RESOURCE_ATTACH_BACKING ,
601- flags : 0 ,
602- fence_id : 0 ,
603- ctx_id : 0 ,
604- padding : 0 ,
605- } ,
606- resource_id : RESOURCE_COMPOSITE_TEX_ID ,
607- nr_entries : 1 ,
608- } ,
609- entry : VirtioGpuMemEntry {
610- addr : phys,
611- length : size as u32 ,
612- padding : 0 ,
613- } ,
614- } ;
615- }
616- send_command_expect_ok ( state, core:: mem:: size_of :: < PciAttachBackingCmd > ( ) as u32 )
594+ virgl_attach_backing_paged ( state, RESOURCE_COMPOSITE_TEX_ID , unsafe { COMPOSITE_TEX_PTR } , size)
617595 } ) ?;
618596
619597 // Attach to VirGL context
@@ -2001,20 +1979,19 @@ fn virgl_resource_create_3d_cmd(
20011979
20021980/// Attach backing memory to a 3D resource using per-page scatter-gather entries.
20031981///
2004- /// Uses heap-allocated PCI_3D_FB_PTR as the backing store.
2005- /// CRITICAL: Must NOT share backing with the 2D resource (PCI_FRAMEBUFFER).
2006- /// Linux's Mesa/virgl creates independent GEM buffers for each resource.
2007- ///
20081982/// KEY FIX: Linux kernel sends one VirtioGpuMemEntry per 4KB page (768 entries
2009- /// for a 1024×768×4 framebuffer). Our previous approach sent 1 entry with the
2010- /// entire 3MB range. The host (Parallels) may require per-page entries to
2011- /// properly map backing for GL texture operations and TRANSFER_FROM_HOST_3D.
2012- fn virgl_attach_backing_cmd ( state : & mut GpuPciDeviceState , resource_id : u32 ) -> Result < ( ) , & ' static str > {
2013- let fb_ptr = unsafe { PCI_3D_FB_PTR } ;
2014- assert ! ( !fb_ptr. is_null( ) , "3D framebuffer not initialized" ) ;
2015- let fb_base_phys = virt_to_phys ( fb_ptr as u64 ) ;
2016- let fb_len = unsafe { PCI_3D_FB_LEN } ;
2017- let actual_len = ( state. width as usize * state. height as usize * 4 ) . min ( fb_len) ;
1983+ /// for a 1024×768×4 framebuffer). The host (Parallels) requires per-page entries
1984+ /// to properly map backing for GL texture operations and TRANSFER_FROM_HOST_3D.
1985+ /// A single-entry approach causes the host to read zeros → BLACK texture sampling.
1986+ fn virgl_attach_backing_paged (
1987+ state : & mut GpuPciDeviceState ,
1988+ resource_id : u32 ,
1989+ backing_ptr : * const u8 ,
1990+ backing_len : usize ,
1991+ ) -> Result < ( ) , & ' static str > {
1992+ assert ! ( !backing_ptr. is_null( ) , "backing pointer is null" ) ;
1993+ let fb_base_phys = virt_to_phys ( backing_ptr as u64 ) ;
1994+ let actual_len = backing_len;
20181995
20191996 const PAGE_SIZE : usize = 4096 ;
20201997 let nr_pages = ( actual_len + PAGE_SIZE - 1 ) / PAGE_SIZE ;
@@ -3054,7 +3031,6 @@ pub fn virgl_composite_frame(
30543031/// alpha blending, transforms). Currently not working on Parallels — texture
30553032/// sampling produces black output despite successful SUBMIT_3D. Kept for future
30563033/// debugging and enablement.
3057- #[ allow( dead_code) ]
30583034pub fn virgl_composite_frame_textured (
30593035 pixels : & [ u32 ] ,
30603036 width : u32 ,
@@ -3095,41 +3071,45 @@ pub fn virgl_composite_frame_textured(
30953071 } ) ?;
30963072
30973073 // Build VirGL batch: full pipeline + textured quad
3074+ // Object handles are unique per batch to avoid hash collisions in virglrenderer:
3075+ // 10=surface, 11=blend, 12=DSA, 13=rasterizer, 14=VS, 15=FS,
3076+ // 16=VE, 17=sampler_view, 18=sampler_state
30983077 let mut cmdbuf = CommandBuffer :: new ( ) ;
30993078 cmdbuf. create_sub_ctx ( 1 ) ;
31003079 cmdbuf. set_sub_ctx ( 1 ) ;
31013080 cmdbuf. set_tweaks ( 1 , 1 ) ;
31023081 cmdbuf. set_tweaks ( 2 , display_w) ;
31033082
3104- cmdbuf. create_surface ( 1 , RESOURCE_3D_ID , vfmt:: B8G8R8X8_UNORM , 0 , 0 ) ;
3105- cmdbuf. set_framebuffer_state ( 0 , & [ 1 ] ) ;
3106- cmdbuf. create_blend_simple ( 1 ) ;
3107- cmdbuf. bind_object ( 1 , super :: virgl:: OBJ_BLEND ) ;
3108- cmdbuf. create_dsa_default ( 1 ) ;
3109- cmdbuf. bind_object ( 1 , super :: virgl:: OBJ_DSA ) ;
3110- cmdbuf. create_rasterizer_default ( 1 ) ;
3111- cmdbuf. bind_object ( 1 , super :: virgl:: OBJ_RASTERIZER ) ;
3083+ cmdbuf. create_surface ( 10 , RESOURCE_3D_ID , vfmt:: B8G8R8X8_UNORM , 0 , 0 ) ;
3084+ cmdbuf. set_framebuffer_state ( 0 , & [ 10 ] ) ;
3085+ cmdbuf. create_blend_simple ( 11 ) ;
3086+ cmdbuf. bind_object ( 11 , super :: virgl:: OBJ_BLEND ) ;
3087+ cmdbuf. create_dsa_default ( 12 ) ;
3088+ cmdbuf. bind_object ( 12 , super :: virgl:: OBJ_DSA ) ;
3089+ cmdbuf. create_rasterizer_default ( 13 ) ;
3090+ cmdbuf. bind_object ( 13 , super :: virgl:: OBJ_RASTERIZER ) ;
31123091
3113- // Texture shaders
3092+ // Texture shaders (num_tokens=300 required by Parallels)
31143093 let tex_vs = b"VERT\n DCL IN[0]\n DCL IN[1]\n DCL OUT[0], POSITION\n DCL OUT[1], GENERIC[0]\n 0: MOV OUT[0], IN[0]\n 1: MOV OUT[1], IN[1]\n 2: END\n " ;
3115- cmdbuf. create_shader ( 1 , pipe:: SHADER_VERTEX , 300 , tex_vs) ;
3116- cmdbuf. bind_shader ( 1 , pipe:: SHADER_VERTEX ) ;
3117- let tex_fs = b"FRAG\n DCL IN[0], GENERIC[0], LINEAR\n DCL OUT[0], COLOR\n DCL SAMP[0]\n DCL SVIEW[0], 2D, FLOAT\n 0: TEX OUT[0], IN[0], SAMP[0], 2D\n 1: END\n " ;
3118- cmdbuf. create_shader ( 2 , pipe:: SHADER_FRAGMENT , 300 , tex_fs) ;
3119- cmdbuf. bind_shader ( 2 , pipe:: SHADER_FRAGMENT ) ;
3094+ cmdbuf. create_shader ( 14 , pipe:: SHADER_VERTEX , 300 , tex_vs) ;
3095+ cmdbuf. bind_shader ( 14 , pipe:: SHADER_VERTEX ) ;
3096+ let tex_fs = b"FRAG\n PROPERTY FS_COLOR0_WRITES_ALL_CBUFS 1 \ n DCL IN[0], GENERIC[0], LINEAR\n DCL OUT[0], COLOR\n DCL SAMP[0]\n DCL SVIEW[0], 2D, FLOAT\n 0: TEX OUT[0], IN[0], SAMP[0], 2D\n 1: END\n " ;
3097+ cmdbuf. create_shader ( 15 , pipe:: SHADER_FRAGMENT , 300 , tex_fs) ;
3098+ cmdbuf. bind_shader ( 15 , pipe:: SHADER_FRAGMENT ) ;
31203099
3121- cmdbuf. create_vertex_elements ( 1 , & [
3100+ cmdbuf. create_vertex_elements ( 16 , & [
31223101 ( 0 , 0 , 0 , vfmt:: R32G32B32A32_FLOAT ) ,
31233102 ( 16 , 0 , 0 , vfmt:: R32G32B32A32_FLOAT ) ,
31243103 ] ) ;
3125- cmdbuf. bind_object ( 1 , super :: virgl:: OBJ_VERTEX_ELEMENTS ) ;
3104+ cmdbuf. bind_object ( 16 , super :: virgl:: OBJ_VERTEX_ELEMENTS ) ;
31263105
3127- cmdbuf. create_sampler_view ( 2 , RESOURCE_COMPOSITE_TEX_ID , vfmt:: B8G8R8X8_UNORM , 0 , 0 , swizzle:: IDENTITY ) ;
3128- cmdbuf. create_sampler_state ( 3 , pipe:: TEX_WRAP_CLAMP_TO_EDGE , pipe:: TEX_WRAP_CLAMP_TO_EDGE , pipe:: TEX_WRAP_CLAMP_TO_EDGE , pipe:: TEX_FILTER_NEAREST , pipe:: TEX_MIPFILTER_NONE , pipe:: TEX_FILTER_NEAREST ) ;
3106+ // Sampler view: format DWORD must include texture target in bits [24:31]
3107+ cmdbuf. create_sampler_view ( 17 , RESOURCE_COMPOSITE_TEX_ID , vfmt:: B8G8R8X8_UNORM , pipe:: TEXTURE_2D , 0 , 0 , 0 , 0 , swizzle:: IDENTITY ) ;
3108+ cmdbuf. create_sampler_state ( 18 , pipe:: TEX_WRAP_CLAMP_TO_EDGE , pipe:: TEX_WRAP_CLAMP_TO_EDGE , pipe:: TEX_WRAP_CLAMP_TO_EDGE , pipe:: TEX_FILTER_NEAREST , pipe:: TEX_MIPFILTER_NONE , pipe:: TEX_FILTER_NEAREST ) ;
31293109 cmdbuf. set_min_samples ( 1 ) ;
31303110 cmdbuf. set_viewport ( display_w as f32 , display_h as f32 ) ;
3131- cmdbuf. set_sampler_views ( pipe:: SHADER_FRAGMENT , 0 , & [ 2 ] ) ;
3132- cmdbuf. bind_sampler_states ( pipe:: SHADER_FRAGMENT , 0 , & [ 3 ] ) ;
3111+ cmdbuf. set_sampler_views ( pipe:: SHADER_FRAGMENT , 0 , & [ 17 ] ) ;
3112+ cmdbuf. bind_sampler_states ( pipe:: SHADER_FRAGMENT , 0 , & [ 18 ] ) ;
31333113 cmdbuf. clear_color ( 0.0 , 0.0 , 0.0 , 1.0 ) ;
31343114
31353115 let u_max = copy_w as f32 / tex_w as f32 ;
@@ -3329,9 +3309,12 @@ pub fn virgl_init() -> Result<(), &'static str> {
33293309 crate :: serial_println!( "[virgl] Step 2: 3D resource created ({}x{}, bind=0x{:08x})" ,
33303310 width, height, bind_flags) ;
33313311
3332- // Step 4: Attach backing memory
3312+ // Step 4: Attach backing memory (per-page scatter-gather)
33333313 with_device_state ( |state| {
3334- virgl_attach_backing_cmd ( state, RESOURCE_3D_ID )
3314+ let fb_ptr = unsafe { PCI_3D_FB_PTR } ;
3315+ let fb_len = unsafe { PCI_3D_FB_LEN } ;
3316+ let actual_len = ( state. width as usize * state. height as usize * 4 ) . min ( fb_len) ;
3317+ virgl_attach_backing_paged ( state, RESOURCE_3D_ID , fb_ptr, actual_len)
33353318 } ) ?;
33363319 crate :: serial_println!( "[virgl] Step 3: backing attached" ) ;
33373320
@@ -3585,8 +3568,9 @@ fn virgl_test_textured_quad() -> Result<(), &'static str> {
35853568 5 , // handle
35863569 RESOURCE_TEX_ID , // resource
35873570 vfmt:: B8G8R8A8_UNORM , // format
3588- 0 , // first_level
3589- 0 , // last_level
3571+ pipe:: TEXTURE_2D , // target (packed into format bits [24:31])
3572+ 0 , 0 , // first_layer, last_layer
3573+ 0 , 0 , // first_level, last_level
35903574 swizzle:: IDENTITY , // RGBA identity swizzle
35913575 ) ;
35923576
0 commit comments