From efc2800358bb4952a511c5ac292e512db7844dd2 Mon Sep 17 00:00:00 2001 From: modeco80 Date: Tue, 15 Oct 2024 08:11:56 -0400 Subject: [PATCH] server: fix software rendering It was broken --- server/src/retro_thread.rs | 84 ++++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 7 deletions(-) diff --git a/server/src/retro_thread.rs b/server/src/retro_thread.rs index a5ca908..a287bc9 100644 --- a/server/src/retro_thread.rs +++ b/server/src/retro_thread.rs @@ -4,6 +4,7 @@ use std::{ time::Duration, }; +use cudarc::driver::sys::CUmemorytype; use tokio::sync::{mpsc, oneshot}; use anyhow::Result; @@ -185,9 +186,12 @@ impl RetroState { let has_disconnected_pitch = pitch != size.width as u32; - for y in 0..size.height { + for _y in 0..size.height { + // Trick to flip the buffer the way OpenGL likes. + let y = (size.height - 1) - _y; + let src_line_off = (y as u32 * pitch) as usize; - let mut dest_line_off = (y as u32 * size.width) as usize; + let mut dest_line_off = (_y as u32 * size.width) as usize; // copy only if has_disconnected_pitch { @@ -224,7 +228,10 @@ impl FrontendInterface for RetroState { .lock() .expect("Failed to lock CUDA resource"); - locked.device().bind_to_thread().expect("Failed to bind CUDA device to thread"); + locked + .device() + .bind_to_thread() + .expect("Failed to bind CUDA device to thread"); locked .register(self.gl_framebuffer.texture_id(), gl::TEXTURE_2D) @@ -242,18 +249,78 @@ impl FrontendInterface for RetroState { let size = self.software_framebuffer.size.clone(); // upload texture to GPU - unsafe { + /*unsafe { + tracing::info!("bind tex"); + gl::BindTexture(gl::TEXTURE_2D, self.gl_framebuffer.texture_id()); + + tracing::info!("upload"); gl::TexImage2D( gl::TEXTURE_2D, 0, - gl::RGBA as i32, + gl::RGBA8 as i32, size.width as i32, size.height as i32, 0, - gl::RGBA_INTEGER, - gl::UNSIGNED_INT_8_8_8_8, + gl::RGBA, + gl::UNSIGNED_BYTE, self.software_framebuffer.get_buffer().as_mut_ptr() as *const _, ); + + tracing::info!("unbind tex"); + gl::BindTexture(gl::TEXTURE_2D, 0); + }*/ + + // TODO: Figure out a way to do this with standard OpenGL primitives. + // (the above does not work *at all*. Don't ask how I know) + unsafe { + let mut cuda_resource = self + .cuda_resource + .lock() + .expect("Failed to lock CUDA resource"); + + cuda_resource + .device() + .bind_to_thread() + .expect("Failed to bind CUDA device to thread"); + + let mut mapped_cuda_resource = cuda_resource + .map() + .expect("Failed to map CUDA resource"); + + let array = mapped_cuda_resource + .get_mapped_array() + .expect("Failed to get CUarray from CUDA resource"); + + let mut memcpy = cudarc::driver::sys::CUDA_MEMCPY2D_st::default(); + + // src + memcpy.srcXInBytes = 0; + memcpy.srcY = 0; + memcpy.srcMemoryType = CUmemorytype::CU_MEMORYTYPE_HOST; + memcpy.srcHost = self.software_framebuffer.get_buffer().as_mut_ptr() as *const _; + + // dest + memcpy.dstXInBytes = 0; + memcpy.dstY = 0; + memcpy.dstMemoryType = CUmemorytype::CU_MEMORYTYPE_ARRAY; + memcpy.dstArray = array; + + memcpy.WidthInBytes = (size.width * 4) as usize; + memcpy.Height = size.height as usize; + memcpy.dstPitch = (size.width * 4) as usize; + + // kick it off + cudarc::driver::sys::lib() + .cuMemcpy2DAsync_v2(&memcpy, std::ptr::null_mut()) + .result() + .expect("cuMemcpy2D fail epic"); + + cudarc::driver::sys::lib() + .cuStreamSynchronize(std::ptr::null_mut()) + .result() + .expect("fucking"); + + mapped_cuda_resource.unmap().expect("fuck you asshole"); } let _ = self.event_tx.blocking_send(RetroEvent::Frame); @@ -353,6 +420,9 @@ impl FrontendInterface for RetroState { } fn hw_gl_init(&mut self) -> Option { + // test SW-only even if a core wants to upgrade + //return None; + // Only create a new EGL/OpenGL context if we have to. let context = self.egl_context.lock().expect("fuck you!"); let extensions = gpu::egl_helpers::get_extensions(context.get_display());