Skip to content

Commit

Permalink
- fix conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
polymonster committed Dec 2, 2024
2 parents 3590226 + 49cec26 commit 6e5c3f1
Show file tree
Hide file tree
Showing 4 changed files with 282 additions and 5 deletions.
14 changes: 13 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,18 @@
"cwd": "${fileDirname}",
"environment": [],
"console": "externalTerminal",
}
},
{
"name": "raytraced_triangle (Debug)",
"type": "cppvsdbg",
"request": "launch",
"program": "${workspaceFolder}/target/debug/examples/raytraced_triangle.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"console": "externalTerminal",
"preLaunchTask": "examples"
},
]
}
186 changes: 186 additions & 0 deletions examples/raytraced_triangle/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
use hotline_rs::*;

use gfx::CmdBuf;
use gfx::Device;
use gfx::SwapChain;

use os::App;
use os::Window;

use std::fs;

#[cfg(target_os = "windows")]
use os::win32 as os_platform;
use gfx::d3d12 as gfx_platform;

#[repr(C)]
struct Vertex {
position: [f32; 3],
color: [f32; 4],
}

fn main() -> Result<(), hotline_rs::Error> {
let mut app = os_platform::App::create(os::AppInfo {
name: String::from("raytraced_triangle"),
window: false,
num_buffers: 0,
dpi_aware: true,
});

let num_buffers : u32 = 2;

let mut device = gfx_platform::Device::create(&gfx::DeviceInfo {
render_target_heap_size: num_buffers as usize,
..Default::default()
});
println!("{}", device.get_adapter_info());
println!("{:?}", device.get_feature_flags());

let mut window = app.create_window(os::WindowInfo {
title: String::from("raytraced_triangle!"),
..Default::default()
});

let swap_chain_info = gfx::SwapChainInfo {
num_buffers,
format: gfx::Format::RGBA8n,
clear_colour: Some(gfx::ClearColour {
r: 0.45,
g: 0.55,
b: 0.60,
a: 1.00,
}),
};

let mut swap_chain = device.create_swap_chain::<os_platform::App>(&swap_chain_info, &window)?;
let mut cmd = device.create_cmd_buf(num_buffers);

let vertices = [
Vertex {
position: [0.0, 0.25, 0.0],
color: [1.0, 0.0, 0.0, 1.0],
},
Vertex {
position: [0.25, -0.25, 0.0],
color: [0.0, 1.0, 0.0, 1.0],
},
Vertex {
position: [-0.25, -0.25, 0.0],
color: [0.0, 0.0, 1.0, 1.0],
},
];

let info = gfx::BufferInfo {
usage: gfx::BufferUsage::VERTEX,
cpu_access: gfx::CpuAccessFlags::NONE,
format: gfx::Format::Unknown,
stride: std::mem::size_of::<Vertex>(),
num_elements: 3,
initial_state: gfx::ResourceState::VertexConstantBuffer
};

let vertex_buffer = device.create_buffer(&info, Some(gfx::as_u8_slice(&vertices)))?;

let vsc_filepath = hotline_rs::get_data_path("shaders/triangle/vs_main.vsc");
let psc_filepath = hotline_rs::get_data_path("shaders/triangle/ps_main.psc");

let vsc_data = fs::read(vsc_filepath)?;
let psc_data = fs::read(psc_filepath)?;

let vsc_info = gfx::ShaderInfo {
shader_type: gfx::ShaderType::Vertex,
compile_info: None
};
let vs = device.create_shader(&vsc_info, &vsc_data)?;

let psc_info = gfx::ShaderInfo {
shader_type: gfx::ShaderType::Vertex,
compile_info: None
};
let fs = device.create_shader(&psc_info, &psc_data)?;

let pso = device.create_render_pipeline(&gfx::RenderPipelineInfo {
vs: Some(&vs),
fs: Some(&fs),
input_layout: vec![
gfx::InputElementInfo {
semantic: String::from("POSITION"),
index: 0,
format: gfx::Format::RGB32f,
input_slot: 0,
aligned_byte_offset: 0,
input_slot_class: gfx::InputSlotClass::PerVertex,
step_rate: 0,
},
gfx::InputElementInfo {
semantic: String::from("COLOR"),
index: 0,
format: gfx::Format::RGBA32f,
input_slot: 0,
aligned_byte_offset: 12,
input_slot_class: gfx::InputSlotClass::PerVertex,
step_rate: 0,
},
],
blend_info: gfx::BlendInfo {
alpha_to_coverage_enabled: false,
independent_blend_enabled: false,
render_target: vec![gfx::RenderTargetBlendInfo::default()],
},
topology: gfx::Topology::TriangleList,
pass: Some(swap_chain.get_backbuffer_pass()),
..Default::default()
})?;

while app.run() {
// update window and swap chain
window.update(&mut app);
swap_chain.update::<os_platform::App>(&mut device, &window, &mut cmd);

// update viewport from window size
let window_rect = window.get_viewport_rect();
let viewport = gfx::Viewport::from(window_rect);
let scissor = gfx::ScissorRect::from(window_rect);

// build command buffer and make draw calls
cmd.reset(&swap_chain);

cmd.transition_barrier(&gfx::TransitionBarrier {
texture: Some(swap_chain.get_backbuffer_texture()),
buffer: None,
state_before: gfx::ResourceState::Present,
state_after: gfx::ResourceState::RenderTarget,
});

cmd.begin_render_pass(swap_chain.get_backbuffer_pass_mut());
cmd.set_viewport(&viewport);
cmd.set_scissor_rect(&scissor);
cmd.set_render_pipeline(&pso);
cmd.set_vertex_buffer(&vertex_buffer, 0);
cmd.draw_instanced(3, 1, 0, 0);
cmd.end_render_pass();

cmd.transition_barrier(&gfx::TransitionBarrier {
texture: Some(swap_chain.get_backbuffer_texture()),
buffer: None,
state_before: gfx::ResourceState::RenderTarget,
state_after: gfx::ResourceState::Present,
});

cmd.close()?;

// execute command buffer
device.execute(&cmd);

// swap for the next frame
swap_chain.swap(&device);
}

// must wait for the final frame to be completed
swap_chain.wait_for_last_frame();

// resources now no longer in use they can be properly cleaned up
device.cleanup_dropped_resources(&swap_chain);

Ok(())
}
9 changes: 9 additions & 0 deletions src/gfx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,13 @@ pub enum ShaderType {
}

bitflags! {
/// Device feature flags.
pub struct DeviceFeatureFlags: u32 {
const NONE = 0;
const RAYTRACING = 1<<0;
const MESH_SAHDER = 1<<1;
}

/// Shader compilation flags.
pub struct ShaderCompileFlags: u32 {
/// No flags, default compilation.
Expand Down Expand Up @@ -1115,6 +1122,8 @@ pub trait Device: 'static + Send + Sync + Sized + Any + Clone {
fn cleanup_dropped_resources(&mut self, swap_chain: &Self::SwapChain);
/// Returns an `AdapterInfo` struct (info about GPU vendor, and HW statistics)
fn get_adapter_info(&self) -> &AdapterInfo;
/// Returns a `DeviceFeatureFlags` struct containing flags for supported hardware features
fn get_feature_flags(&self) -> &DeviceFeatureFlags;
/// Read data back from GPU buffer into CPU `ReadBackData` assumes the `Buffer` is created with `create_read_back_buffer`
/// None is returned if the buffer has yet to br written on the GPU
fn read_buffer(&self, swap_chain: &Self::SwapChain, buffer: &Self::Buffer, size_bytes: usize, frame_written_fence: u64) -> Option<ReadBackData>;
Expand Down
78 changes: 74 additions & 4 deletions src/gfx/d3d12.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ type D3D12DebugVersion = ID3D12Debug;
#[derive(Clone)]
pub struct Device {
adapter_info: super::AdapterInfo,
feature_flags: super::DeviceFeatureFlags,
dxgi_factory: IDXGIFactory4,
device: D3D12DeviceVersion,
command_allocator: ID3D12CommandAllocator,
Expand Down Expand Up @@ -833,6 +834,33 @@ fn create_generate_mip_maps_pipeline(device: &Device) -> result::Result<ComputeP
})
}

#[derive(Copy, Clone)]
enum Vendor
{
Unknown,
Intel,
Amd,
Nvidia
}

fn to_vendor(vendor_id: u32) -> Vendor {
match vendor_id {
0x163C | 0x8086 | 0x8087 => Vendor::Intel,
0x1002 | 0x1022 => Vendor::Amd,
0x10DE => Vendor::Nvidia,
_ => Vendor::Unknown
}
}

fn is_discrete_gpu(vendor: Vendor) -> bool {
match vendor {
Vendor::Unknown => false,
Vendor::Intel => false,
Vendor::Amd => true,
Vendor::Nvidia => true
}
}

pub fn get_hardware_adapter(
factory: &IDXGIFactory4,
adapter_name: &Option<String>,
Expand All @@ -849,6 +877,7 @@ pub fn get_hardware_adapter(

// enumerate info
let mut selected_index = -1;
let mut selected_vendor = Vendor::Unknown;
for i in 0.. {
let adapter = factory.EnumAdapters1(i);
if adapter.is_err() {
Expand All @@ -858,6 +887,7 @@ pub fn get_hardware_adapter(
let desc = adapter.unwrap().GetDesc1()?;

// decode utf-16 dfescription

let decoded1 = decode_utf16(desc.Description)
.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
.collect::<String>();
Expand All @@ -874,10 +904,20 @@ pub fn get_hardware_adapter(
}
} else {
// auto select first non software adapter
let adapter_flag = DXGI_ADAPTER_FLAG(desc.Flags as i32);
if (adapter_flag & DXGI_ADAPTER_FLAG_SOFTWARE) == DXGI_ADAPTER_FLAG_NONE &&
selected_index == -1 {
selected_index = i as i32;
let adapter_flag = DXGI_ADAPTER_FLAG(desc.Flags);
if (adapter_flag & DXGI_ADAPTER_FLAG_SOFTWARE) == DXGI_ADAPTER_FLAG_NONE {
let adpater_vendor = to_vendor(desc.VendorId);

// select first
if selected_index == -1 {
selected_index = i as i32;
selected_vendor = adpater_vendor;
}

// override rules to select discrete gpu
if !is_discrete_gpu(selected_vendor) && is_discrete_gpu(adpater_vendor) {
selected_index = i as i32;
}
}
}
}
Expand Down Expand Up @@ -1684,10 +1724,36 @@ impl super::Device for Device {
);
d3d12_debug_name!(dsv_heap.heap, "device_depth_stencil_heap");

// query feature flags
let mut feature_flags = DeviceFeatureFlags::NONE;

// ray tracing
let options5 = D3D12_FEATURE_DATA_D3D12_OPTIONS5::default();
if device.CheckFeatureSupport(
D3D12_FEATURE_D3D12_OPTIONS5,
std::ptr::addr_of!(options5) as *mut _,
std::mem::size_of::<D3D12_FEATURE_DATA_D3D12_OPTIONS5>() as u32).is_ok() {
if options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED {
feature_flags |= super::DeviceFeatureFlags::RAYTRACING;
}
}

// mesh shader
let options7 = D3D12_FEATURE_DATA_D3D12_OPTIONS7::default();
if device.CheckFeatureSupport(
D3D12_FEATURE_D3D12_OPTIONS7,
std::ptr::addr_of!(options7) as *mut _,
std::mem::size_of::<D3D12_FEATURE_DATA_D3D12_OPTIONS7>() as u32).is_ok() {
if options7.MeshShaderTier != D3D12_MESH_SHADER_TIER_NOT_SUPPORTED {
feature_flags |= super::DeviceFeatureFlags::MESH_SAHDER;
}
}

// initialise struct
let mut device = Device {
timestamp_frequency,
adapter_info,
feature_flags,
device,
dxgi_factory,
command_allocator,
Expand Down Expand Up @@ -3034,6 +3100,10 @@ impl super::Device for Device {
&self.adapter_info
}

fn get_feature_flags(&self) -> &DeviceFeatureFlags {
&self.feature_flags
}

fn read_buffer(&self, swap_chain: &SwapChain, buffer: &Buffer, size: usize, frame_written_fence: u64) -> Option<super::ReadBackData> {
let rr = ReadBackRequest {
resource: Some(buffer.resource.as_ref().unwrap().clone()),
Expand Down

0 comments on commit 6e5c3f1

Please sign in to comment.