Crates.io | nexg |
lib.rs | nexg |
version | 0.1.1 |
source | src |
created_at | 2024-02-08 14:28:08.346103 |
updated_at | 2024-02-09 22:49:57.025779 |
description | Nexg is a pure-rust library that makes coding Vulkan functionality easier and more Rust-like. |
homepage | |
repository | https://github.com/Ichinose0/Nexg |
max_upload_size | |
id | 1132174 |
size | 187,471 |
Nexg is a pure-rust library that makes coding Vulkan functionality easier and more Rust-like
Nexg aims to support gaming applications as well as operation on GPUs
use std::ffi::c_void;
use std::mem::offset_of;
use std::{env, fs::File, io::BufWriter};
use nexg::{
Buffer, BufferDescriptor, CommandPoolDescriptor, CommandRecorderDescriptor, DataFormat,
Extent3d, FrameBuffer, FrameBufferDescriptor, Image, ImageDescriptor, ImageFormat,
ImageViewDescriptor, InstanceBuilder, InstanceFeature, LoadOp, Pipeline, PipelineDescriptor,
PipelineLayout, PipelineLayoutDescriptor, PipelineVertexInputDescriptor, QueueSubmitDescriptor,
RenderPass, RenderPassBeginDescriptor, RenderPassDescriptor, Shader, ShaderStage,
ShaderStageDescriptor, Spirv, StoreOp, SubPass, SubPassDescriptor,
VertexInputAttributeDescriptor, VertexInputBindingDescriptor,
};
use png::text_metadata::ZTXtChunk;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct Vec4(f32, f32, f32, f32);
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct Vertex {
pos: Vec4,
color: Vec4,
}
const VERTEX: [Vertex; 3] = [
Vertex {
pos: Vec4(0.0, -0.5, 0.0, 0.0),
color: Vec4(1.0, 0.0, 0.0, 1.0),
},
Vertex {
pos: Vec4(0.5, 0.5, 0.0, 0.0),
color: Vec4(0.0, 1.0, 0.0, 1.0),
},
Vertex {
pos: Vec4(-0.5, 0.5, 0.0, 0.0),
color: Vec4(0.0, 0.0, 1.0, 1.0),
},
];
const WIDTH: u32 = 640;
const HEIGHT: u32 = 480;
fn main() {
let feature = InstanceFeature::empty();
let instance = InstanceBuilder::new().feature(feature).build().unwrap();
// Request suitable connecter.
let desc = RequestConnecterDescriptor::new()
.graphic_support(true)
.compute_support(true)
.transfer_support(true);
let connecters = instance.request_connecters(&[desc]).unwrap();
let connecter = connecters[0];
let index = connecter.get_queue_family_index();
let device = connecter.create_device(&instance, index).unwrap();
let queue = device.get_queue(index);
let desc = CommandPoolDescriptor::empty().queue_family_index(index);
let pool = device.create_command_pool(&desc).unwrap();
let desc = CommandRecorderDescriptor::empty();
let recorders = device.allocate_command_recorder(pool, &desc).unwrap();
let desc = ImageDescriptor::new().extent(Extent3d::new(WIDTH, HEIGHT, 1));
let image = Image::create(&instance, &device, connecter, &desc).unwrap();
let desc = ImageViewDescriptor::empty().format(ImageFormat::R8G8B8A8Unorm);
let image_view = image.create_image_view(&device, &desc);
let vertex = Shader::new(
&device,
&Spirv::new(concat!(
env!("CARGO_MANIFEST_DIR"),
"/examples/shader/shader.vert.spv"
))
.unwrap(),
);
let fragment = Shader::new(
&device,
&Spirv::new(concat!(
env!("CARGO_MANIFEST_DIR"),
"/examples/shader/shader.frag.spv"
))
.unwrap(),
);
let desc = BufferDescriptor::empty().size(std::mem::size_of::<Vertex>() * VERTEX.len());
let vertex_buffer = Buffer::new(&instance, connecter, &device, &desc).unwrap();
vertex_buffer.write(&device, VERTEX.as_ptr() as *const c_void);
vertex_buffer.lock(&device);
let desc = SubPassDescriptor::empty();
let subpass = SubPass::new(connecter, &desc);
let subpasses = &[subpass];
let desc = RenderPassDescriptor::empty()
.subpasses(subpasses)
.load_op(LoadOp::Clear)
.store_op(StoreOp::Store);
let render_pass = RenderPass::new(&device, &desc).unwrap();
let desc = PipelineLayoutDescriptor::empty().render_pass(&render_pass);
let pipeline_layout = PipelineLayout::new(&device, &desc).unwrap();
let shader_stages = vec![
ShaderStageDescriptor::empty()
.entry_point("main")
.stage(ShaderStage::Vertex)
.shaders(&vertex),
ShaderStageDescriptor::empty()
.entry_point("main")
.stage(ShaderStage::Fragment)
.shaders(&fragment),
];
let binding_desc = vec![VertexInputBindingDescriptor::empty()
.binding(0)
.stride(std::mem::size_of::<Vertex>())];
let attribute_desc = vec![
VertexInputAttributeDescriptor::empty()
.binding(0)
.location(0)
.format(DataFormat::R32G32SFloat)
.offset(offset_of!(Vertex, pos)),
VertexInputAttributeDescriptor::empty()
.binding(0)
.location(1)
.format(DataFormat::R32G32B32SFloat)
.offset(offset_of!(Vertex, color)),
];
let vertex_input_desc = PipelineVertexInputDescriptor::empty()
.attribute_desc(&attribute_desc)
.binding_desc(&binding_desc);
let desc = PipelineDescriptor::empty()
.shader_stages(&shader_stages)
.input_descriptor(&vertex_input_desc)
.width(WIDTH)
.height(HEIGHT);
let pipeline = Pipeline::new(&device, pipeline_layout, &render_pass, &desc).unwrap();
let desc = FrameBufferDescriptor::empty()
.render_pass(&render_pass)
.image_view(&image_view)
.width(WIDTH)
.height(HEIGHT);
let framebuffer = FrameBuffer::new(&device, &desc).unwrap();
let begin_desc = RenderPassBeginDescriptor::empty()
.width(WIDTH)
.height(HEIGHT)
.clear(1.0, 1.0, 1.0, 1.0)
.render_pass(&render_pass)
.frame_buffer(&framebuffer);
recorders[0].begin(&device, begin_desc);
recorders[0].bind_pipeline(&device, &pipeline[0]);
recorders[0].bind_vertex_buffer(&device, &vertex_buffer);
recorders[0].draw(&device, 3, 1, 0, 0);
recorders[0].end(&device);
let desc = QueueSubmitDescriptor::empty();
queue.submit(&device, &desc, &recorders);
let file = File::create("triangle.png").unwrap();
let w = &mut BufWriter::new(file);
let mut encoder = png::Encoder::new(w, WIDTH, HEIGHT);
encoder.set_color(png::ColorType::Rgba);
encoder.set_depth(png::BitDepth::Eight);
let mut writer = encoder.write_header().unwrap();
let slice = image.as_raw_data(&device, WIDTH, HEIGHT).unwrap();
writer.write_image_data(&slice).unwrap(); // Save
let tail_ztxt_chunk = ZTXtChunk::new(
"Comment".to_string(),
"A zTXt chunk after the image data.".to_string(),
);
writer.write_text_chunk(&tail_ztxt_chunk).unwrap();
}
This API is not an abstraction to other graphics APIs (DirectX, Metal).
It is an API that makes it easier to use and optimize Vulkan's functionality.
Nexg is licensed under MIT LICENSE