This commit is contained in:
shenjack 2025-01-23 23:01:27 +08:00
parent f8ee925d32
commit 2fb9bbbf37
Signed by: shenjack
GPG Key ID: 7B1134A979775551
5 changed files with 274 additions and 254 deletions

View File

@ -29,7 +29,7 @@ pyo3 = { version = "0.23", features = [
# 让我们来试试黑魔法
winit = "0.30"
wgpu = "24"
wgpu = { version = "24", features = ["wgsl"]}
rapier2d-f64 = { version = "0.23", features = ["simd-stable"] }
# 虽然但是, raiper在这里!

View File

@ -4,7 +4,7 @@ use pyo3::prelude::*;
#[pyo3(name = "WgpuRender")]
pub struct WgpuRenderPy {
#[cfg(windows)]
pub app: crate::renders::win_gpu::WgpuContext,
pub app: crate::renders::win::WgpuContext,
}
#[pymethods]
@ -21,5 +21,5 @@ impl WgpuRenderPy {
}
impl WgpuRenderPy {
pub fn new(app: crate::renders::win_gpu::WgpuContext) -> Self { Self { app } }
pub fn new(app: crate::renders::win::WgpuContext) -> Self { Self { app } }
}

View File

@ -1,7 +1,5 @@
#[cfg(windows)]
pub mod win;
#[cfg(windows)]
pub mod win_gpu;
use pyo3::pyfunction;
@ -10,7 +8,7 @@ pub fn render_hack() -> Option<crate::python::renders::WgpuRenderPy> {
println!("render_hacking_start");
#[cfg(windows)]
// let render = win::render_main();
let render = win_gpu::render_init();
let render = win::render_init();
#[cfg(not(windows))]
println!("对不起不支持非 Windows 捏");
println!("render_hacking_end");

View File

@ -1,122 +1,292 @@
//! 目前我有一个cpython程序
//! 使用pyglet通过OpenGL创建一个窗口
//! 其中会通过pyo3调用rust代码(也就是不需要通过手动ffi来调用)
//! 调用rust代码的步骤比较自由, 可以在 Python 侧的渲染循环开始之前调用, 也可以在渲染循环中调用
//! 甚至自定义某个阶段的回调函数, 由 Python 侧调用
//! 我想在rust部分能够直接在pyglet创建的窗口上绘制内容 要怎么做呢?
//! 请优先考虑Windows平台下的实现即可
//! 不一定拘泥与使用 OpenGL 来渲染, 也可以使用其他的渲染方式
//! 其他桌面平台如macOS/Linux的需求可以先行忽略
//! 不需要考虑 web 平台或者移动平台 的需求
//! 但是请保留移植的可能性
use std::num::NonZeroIsize;
use winit::event::WindowEvent;
use winit::platform::run_on_demand::EventLoopExtRunOnDemand;
use winit::platform::windows::EventLoopBuilderExtWindows;
use winit::window::WindowAttributes;
use winit::{application::ApplicationHandler, event_loop::EventLoop, window::Window};
use windows_sys::Win32::Foundation::HWND;
use pollster::block_on;
use raw_window_handle::{RawWindowHandle, Win32WindowHandle};
use wgpu::{util::DeviceExt, Adapter, Device, Instance, InstanceDescriptor, Queue, Surface, SurfaceTargetUnsafe};
struct App {
window: Option<Window>,
parent: RawWindowHandle,
/// 定义一个结构体保存所有渲染上下文
#[derive(Debug)]
pub struct WgpuContext {
pub surface: Surface<'static>,
pub adapter: Adapter,
pub device: Device,
pub queue: Queue,
pub config: wgpu::SurfaceConfiguration,
pub render_pipeline: wgpu::RenderPipeline,
pub vertex_buffer: wgpu::Buffer,
}
impl ApplicationHandler for App {
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
// 这里需要获取现有的窗口, 毕竟是运行在一个已有窗口的 Python 程序里
if self.window.is_none() {
println!("Create window");
let window_attribute = unsafe { WindowAttributes::default().with_parent_window(Some(self.parent.clone())) };
let window = event_loop.create_window(window_attribute).unwrap();
self.window = Some(window);
}
#[derive(Copy, Clone, Debug)]
struct Vertex {
position: [f32; 3],
color: [f32; 3],
}
impl Vertex {
pub fn as_u8(&self) -> Vec<u8> {
let mut data: Vec<u8> = Vec::with_capacity(6 * 4);
data.extend_from_slice(&self.position.iter().map(|x| x.to_ne_bytes()).flatten().collect::<Vec<u8>>());
data.extend_from_slice(&self.color.iter().map(|x| x.to_ne_bytes()).flatten().collect::<Vec<u8>>());
data
}
fn window_event(
&mut self,
event_loop: &winit::event_loop::ActiveEventLoop,
_window_id: winit::window::WindowId,
event: winit::event::WindowEvent,
) {
match event {
WindowEvent::CloseRequested => {
println!("Close window");
event_loop.exit();
pub fn extend_u8(&self, data: &mut Vec<u8>) {
data.extend_from_slice(&self.position.iter().map(|x| x.to_ne_bytes()).flatten().collect::<Vec<u8>>());
data.extend_from_slice(&self.color.iter().map(|x| x.to_ne_bytes()).flatten().collect::<Vec<u8>>());
}
}
const SHADER: &str = r#"
// 顶点着色器
struct VertexInput {
@location(0) position: vec3f,
@location(1) color: vec3f,
};
struct VertexOutput {
@builtin(position) clip_position: vec4f,
@location(0) color: vec3f,
};
@vertex
fn vs_main(
model: VertexInput,
) -> VertexOutput {
var out: VertexOutput;
out.color = model.color;
out.clip_position = vec4f(model.position, 1.0);
return out;
}
// 片元着色器
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
return vec4f(in.color, 1.0);
}
"#;
impl WgpuContext {
pub fn new(unsafe_handle: SurfaceTargetUnsafe) -> anyhow::Result<Self> {
let mut descripter = InstanceDescriptor::default();
descripter.backends = wgpu::Backends::from_comma_list("vulkan,dx12");
let instance = Instance::new(&descripter);
let surface = unsafe { instance.create_surface_unsafe(unsafe_handle) }?;
// 步骤2: 请求适配器Adapter
let adapter = block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::HighPerformance,
compatible_surface: Some(&surface),
force_fallback_adapter: false,
}))
.expect("没找到合适的适配器");
// 步骤3: 创建设备和队列Device/Queue
let (device, queue) = block_on(adapter.request_device(
&wgpu::DeviceDescriptor {
label: Some("主设备"),
// 如果需要特定功能(如深度缓冲),在此处声明
required_features: wgpu::Features::empty(),
// 根据需求调整限制(如纹理大小)
required_limits: wgpu::Limits::downlevel_defaults(),
memory_hints: wgpu::MemoryHints::default(),
},
None, // 追踪路径Trace Path
))?;
// 步骤4: 配置Surface
let surface_caps = surface.get_capabilities(&adapter);
let surface_format = surface_caps.formats.iter().find(|f| f.is_srgb()).unwrap_or(&surface_caps.formats[0]);
let height = 100;
let width = 100;
// let size =
let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: *surface_format,
width,
height,
present_mode: wgpu::PresentMode::Fifo, // 垂直同步
alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![],
desired_maximum_frame_latency: 1,
};
surface.configure(&device, &config);
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("main shader"),
source: wgpu::ShaderSource::Wgsl(SHADER.into()),
});
let render_pipline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layout"),
bind_group_layouts: &[],
push_constant_ranges: &[],
});
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"),
layout: Some(&render_pipline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
buffers: &[],
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: config.format,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList, // 1.
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw, // 2.
cull_mode: Some(wgpu::Face::Back),
// 将此设置为 Fill 以外的任何值都要需要开启 Feature::NON_FILL_POLYGON_MODE
polygon_mode: wgpu::PolygonMode::Fill,
// 需要开启 Features::DEPTH_CLIP_CONTROL
unclipped_depth: false,
// 需要开启 Features::CONSERVATIVE_RASTERIZATION
conservative: false,
},
depth_stencil: None,
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
let vertex_data = [
Vertex {
position: [-0.0868241, -0.49240386, 0.0],
color: [0.5, 0.0, 0.5],
},
Vertex {
position: [0.4131759, -0.49240386, 0.0],
color: [0.5, 0.0, 0.5],
},
Vertex {
position: [0.4131759, 0.49240386, 0.0],
color: [0.5, 0.0, 0.5],
},
Vertex {
position: [-0.0868241, -0.49240386, 0.0],
color: [0.5, 0.0, 0.5],
},
Vertex {
position: [0.4131759, 0.49240386, 0.0],
color: [0.5, 0.0, 0.5],
},
Vertex {
position: [-0.0868241, 0.49240386, 0.0],
color: [0.5, 0.0, 0.5],
},
];
let mut data = Vec::new();
for vertex in vertex_data.iter() {
vertex.extend_u8(&mut data);
}
let vertex_buffer = device.create_buffer_init( &wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"),
contents: &data,
usage: wgpu::BufferUsages::VERTEX,
});
Ok(Self {
surface,
adapter,
device,
queue,
config,
render_pipeline,
vertex_buffer,
})
}
pub fn on_resize(&mut self, width: u32, height: u32) {
self.config.width = width;
self.config.height = height;
self.surface.configure(&self.device, &self.config);
}
fn inner_on_draw(&mut self) -> anyhow::Result<()> {
let output = self.surface.get_current_texture()?;
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render Encoder"),
});
{
// let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
// label: Some("Render Pass"),
// color_attachments: &[Some(wgpu::RenderPassColorAttachment {
// view: &view,
// resolve_target: None,
// ops: wgpu::Operations {
// load: wgpu::LoadOp::Clear(wgpu::Color {
// r: 0.1,
// g: 0.2,
// b: 0.3,
// a: 1.0,
// }),
// store: wgpu::StoreOp::Store,
// },
// })],
// ..Default::default()
// });
}
self.queue.submit(std::iter::once(encoder.finish()));
output.present();
Ok(())
}
pub fn on_draw(&mut self) {
match self.inner_on_draw() {
Ok(_) => {}
Err(e) => {
println!("Failed to draw: {:?}", e);
}
WindowEvent::Destroyed => {
println!("Window destroyed");
event_loop.exit();
}
WindowEvent::RedrawRequested => {
println!("Redraw window");
// self.ref_window().
event_loop.exit();
}
WindowEvent::MouseInput { button, .. } => {
println!("Mouse input: {:?}", button);
}
WindowEvent::Moved(pos) => {
println!("Window moved: {:?}", pos);
}
_ => {}
}
}
}
impl App {
pub fn new(handle: RawWindowHandle) -> Self {
Self {
window: None,
parent: handle,
}
}
pub fn ref_window(&self) -> &Window { self.window.as_ref().unwrap() }
}
fn render_thread(handler: isize) -> anyhow::Result<()> {
let window = handler as HWND;
let win32_handle = Win32WindowHandle::new(NonZeroIsize::new(window as isize).unwrap());
let raw_handle = RawWindowHandle::Win32(win32_handle);
let mut app = App::new(raw_handle);
let event_loop = EventLoop::builder().with_any_thread(true).build()?;
// let event_loop = EventLoop::new()?;
event_loop.run_app(&mut app)?;
Ok(())
}
pub fn render_main() {
let window = match crate::platform::win::get_window_handler() {
Some(window) => window,
pub fn render_init() -> Option<crate::python::renders::WgpuRenderPy> {
let handler = match crate::platform::win::get_window_handler() {
Some(handler) => handler,
None => {
println!("Failed to get window handler");
return;
println!("找不到 pyglet 创建的窗口");
return None;
}
};
// let window_ptr = window as isize;
let win32_handle = Win32WindowHandle::new(NonZeroIsize::new(window as isize).unwrap());
let win32_handle = Win32WindowHandle::new(NonZeroIsize::new(handler).unwrap());
let raw_handle: RawWindowHandle = RawWindowHandle::Win32(win32_handle);
let unsafe_handle = SurfaceTargetUnsafe::RawHandle {
raw_window_handle: raw_handle,
raw_display_handle: raw_window_handle::RawDisplayHandle::Windows(raw_window_handle::WindowsDisplayHandle::new()),
};
let mut app = App::new(raw_handle);
let content = match WgpuContext::new(unsafe_handle) {
Ok(content) => content,
Err(e) => {
println!("Failed to create wgpu context: {:?}", e);
return None;
}
};
let mut event_loop = EventLoop::new().unwrap();
// let event_loop = EventLoop::new()?;
// event_loop.run_app(&mut app).unwrap();
let py_warped = crate::python::renders::WgpuRenderPy::new(content);
let threaded_event_loop = event_loop.run_app_on_demand(&mut app).unwrap();
std::thread::spawn(move || {
// render_thread(window as isize).unwrap();
});
Some(py_warped)
}

View File

@ -1,148 +0,0 @@
use std::num::NonZeroIsize;
use pollster::block_on;
use raw_window_handle::{RawWindowHandle, Win32WindowHandle};
use wgpu::{Adapter, Device, Instance, InstanceDescriptor, Queue, Surface, SurfaceTargetUnsafe};
/// 定义一个结构体保存所有渲染上下文
#[derive(Debug)]
pub struct WgpuContext {
pub surface: Surface<'static>,
pub adapter: Adapter,
pub device: Device,
pub queue: Queue,
pub config: wgpu::SurfaceConfiguration,
}
impl WgpuContext {
pub fn new(unsafe_handle: SurfaceTargetUnsafe) -> anyhow::Result<Self> {
let mut descripter = InstanceDescriptor::default();
descripter.backends = wgpu::Backends::from_comma_list("vulkan,dx12");
let instance = Instance::new(&descripter);
let surface = unsafe { instance.create_surface_unsafe(unsafe_handle) }?;
// 步骤2: 请求适配器Adapter
let adapter = block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::HighPerformance,
compatible_surface: Some(&surface),
force_fallback_adapter: false,
}))
.expect("没找到合适的适配器");
// 步骤3: 创建设备和队列Device/Queue
let (device, queue) = block_on(adapter.request_device(
&wgpu::DeviceDescriptor {
label: Some("主设备"),
// 如果需要特定功能(如深度缓冲),在此处声明
required_features: wgpu::Features::empty(),
// 根据需求调整限制(如纹理大小)
required_limits: wgpu::Limits::downlevel_defaults(),
memory_hints: wgpu::MemoryHints::default(),
},
None, // 追踪路径Trace Path
))?;
// 步骤4: 配置Surface
let surface_caps = surface.get_capabilities(&adapter);
let surface_format = surface_caps.formats.iter().find(|f| f.is_srgb()).unwrap_or(&surface_caps.formats[0]);
let height = 100;
let width = 100;
// let size =
let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: *surface_format,
width,
height,
present_mode: wgpu::PresentMode::Fifo, // 垂直同步
alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![],
desired_maximum_frame_latency: 1,
};
surface.configure(&device, &config);
Ok(Self {
surface,
adapter,
device,
queue,
config,
})
}
pub fn on_resize(&mut self, width: u32, height: u32) {
self.config.width = width;
self.config.height = height;
self.surface.configure(&self.device, &self.config);
}
fn inner_on_draw(&mut self) -> anyhow::Result<()> {
let output = self.surface.get_current_texture()?;
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render Encoder"),
});
{
let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 0.1,
g: 0.2,
b: 0.3,
a: 1.0,
}),
store: wgpu::StoreOp::Store,
},
})],
..Default::default()
});
}
self.queue.submit(std::iter::once(encoder.finish()));
output.present();
Ok(())
}
pub fn on_draw(&mut self) {
match self.inner_on_draw() {
Ok(_) => {}
Err(e) => {
println!("Failed to draw: {:?}", e);
}
}
}
}
pub fn render_init() -> Option<crate::python::renders::WgpuRenderPy> {
let handler = match crate::platform::win::get_window_handler() {
Some(handler) => handler,
None => {
println!("找不到 pyglet 创建的窗口");
return None;
}
};
let win32_handle = Win32WindowHandle::new(NonZeroIsize::new(handler).unwrap());
let raw_handle: RawWindowHandle = RawWindowHandle::Win32(win32_handle);
let unsafe_handle = SurfaceTargetUnsafe::RawHandle {
raw_window_handle: raw_handle,
raw_display_handle: raw_window_handle::RawDisplayHandle::Windows(raw_window_handle::WindowsDisplayHandle::new()),
};
let content = match WgpuContext::new(unsafe_handle) {
Ok(content) => content,
Err(e) => {
println!("Failed to create wgpu context: {:?}", e);
return None;
}
};
let py_warped = crate::python::renders::WgpuRenderPy::new(content);
Some(py_warped)
}