Skip to content

Commit 0d14064

Browse files
authored
Merge pull request #27 from lambda-sh/vmarcella/repo-cleanup
Refactor the renderer & lambda-platform to include a surface implementation for rendering.
2 parents 20fef60 + 4eb2d72 commit 0d14064

11 files changed

Lines changed: 326 additions & 415 deletions

File tree

.vscode/launch.json

Lines changed: 0 additions & 25 deletions
This file was deleted.

.vscode/tasks.json

Lines changed: 0 additions & 29 deletions
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
struct Adapter;

crates/lambda-platform/src/gfx/gpu.rs

Lines changed: 22 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ use gfx_hal::{
5050
},
5151
};
5252

53-
use super::pipeline::GraphicsPipeline;
53+
use super::{
54+
pipeline::GraphicsPipeline,
55+
surface,
56+
};
5457

5558
///
5659
/// Commands oriented around creating resources on & for the GPU.
@@ -70,47 +73,18 @@ pub enum RenderQueueType {
7073
Transfer,
7174
}
7275

73-
/// Checks if queue_family is capable of supporting the requested queue type &
74-
/// Optional surface.
75-
fn is_queue_family_supported<B: gfx_hal::Backend>(
76-
queue_family: &B::QueueFamily,
77-
queue_type: RenderQueueType,
78-
surface: Option<&B::Surface>,
79-
) -> bool {
80-
match queue_type {
81-
RenderQueueType::Compute => queue_family.queue_type().supports_compute(),
82-
RenderQueueType::Graphical => match surface {
83-
Some(surface) => {
84-
surface.supports_queue_family(queue_family)
85-
&& queue_family.queue_type().supports_graphics()
86-
}
87-
None => false,
88-
},
89-
// TODO(vmarcella): These arms should be filled out to support the other kinds of queue types.
90-
RenderQueueType::GraphicalCompute => {
91-
todo!("GraphicalCompute RenderQueue's are not currently implemented.")
92-
}
93-
RenderQueueType::Transfer => {
94-
todo!("Transfer RenderQueues are not currently implemented.")
95-
}
96-
}
97-
}
98-
9976
impl<B: gfx_hal::Backend> GfxGpu<B> {
10077
/// Instantiates a new GPU given an adapter that is implemented by the GPUs
10178
/// current rendering backend B. A new GPU does not come with a command pool unless specified.
10279
pub fn new(
10380
adapter: Adapter<B>,
104-
queue_type: RenderQueueType,
105-
surface: Option<&B::Surface>,
81+
queue_family: gfx_hal::queue::QueueFamilyId,
10682
) -> Self {
10783
let queue_family = adapter
10884
.queue_families
10985
.iter()
110-
.find(|family| {
111-
return is_queue_family_supported::<B>(family, queue_type, surface);
112-
})
113-
.expect("No compatible queue family found.");
86+
.find(|family| family.id() == queue_family)
87+
.expect("Failed to find the queue family requested for the GPU.");
11488

11589
let mut gpu = unsafe {
11690
adapter
@@ -171,6 +145,14 @@ impl<B: gfx_hal::Backend> GfxGpu<B> {
171145
}
172146
}
173147

148+
pub fn get_logical_device(&self) -> &B::Device {
149+
return &self.gpu.device;
150+
}
151+
152+
pub fn get_physical_device(&self) -> &B::PhysicalDevice {
153+
return &self.adapter.physical_device;
154+
}
155+
174156
/// Render to the surface and return the result from the GPU.
175157
pub fn render_to_surface(
176158
&mut self,
@@ -186,40 +168,6 @@ impl<B: gfx_hal::Backend> GfxGpu<B> {
186168
}
187169
}
188170

189-
pub fn configure_swapchain_and_update_extent(
190-
&mut self,
191-
surface: &mut B::Surface,
192-
color_format: gfx_hal::format::Format,
193-
size: [u32; 2],
194-
) -> (Extent2D, gfx_hal::image::FramebufferAttachment) {
195-
let caps = surface.capabilities(&self.adapter.physical_device);
196-
let mut swapchain_config = SwapchainConfig::from_caps(
197-
&caps,
198-
color_format,
199-
Extent2D {
200-
width: size[0],
201-
height: size[1],
202-
},
203-
);
204-
205-
// TODO(vmarcella) Profile the performance on MacOS to see if this slows
206-
// down frame times.
207-
if caps.image_count.contains(&3) {
208-
swapchain_config.image_count = 3;
209-
}
210-
211-
let surface_extent = swapchain_config.extent;
212-
let fba = swapchain_config.framebuffer_attachment();
213-
214-
unsafe {
215-
surface
216-
.configure_swapchain(&self.gpu.device, swapchain_config)
217-
.expect("Failed to configure the swapchain");
218-
}
219-
220-
return (surface_extent, fba);
221-
}
222-
223171
/// Allocate's a command buffer through the GPU
224172
pub fn allocate_command_buffer(&mut self) -> B::CommandBuffer {
225173
// TODO(vmarcella): This function should probably not just panic and instead
@@ -237,10 +185,13 @@ impl<B: gfx_hal::Backend> GfxGpu<B> {
237185

238186
pub fn destroy_command_pool(&mut self) {
239187
unsafe {
240-
self
241-
.gpu
242-
.device
243-
.destroy_command_pool(self.command_pool.take().unwrap());
188+
match self.command_pool {
189+
Some(_) => self
190+
.gpu
191+
.device
192+
.destroy_command_pool(self.command_pool.take().unwrap()),
193+
None => {}
194+
}
244195
}
245196
}
246197

@@ -364,11 +315,6 @@ impl<B: gfx_hal::Backend> GfxGpu<B> {
364315
}
365316
}
366317

367-
/// Unconfigure the swapchain for a surface created from this GPU.
368-
pub fn unconfigure_swapchain(&mut self, surface: &mut B::Surface) {
369-
unsafe { surface.unconfigure_swapchain(&self.gpu.device) }
370-
}
371-
372318
pub fn create_shader_module(&mut self, binary: &Vec<u32>) -> B::ShaderModule {
373319
unsafe {
374320
let module = self
@@ -455,24 +401,4 @@ impl<B: gfx_hal::Backend> GfxGpu<B> {
455401
self.gpu.device.destroy_fence(submission_complete_fence);
456402
}
457403
}
458-
459-
/// Finds the first supported color format or default to Rgba8Srgb.
460-
pub fn find_supported_color_format(
461-
&mut self,
462-
surface: &B::Surface,
463-
) -> Format {
464-
// Define a surface color format compatible with the graphics device &
465-
// surface
466-
let supported_formats = surface
467-
.supported_formats(&self.adapter.physical_device)
468-
.unwrap_or(vec![]);
469-
470-
let default_format =
471-
*supported_formats.get(0).unwrap_or(&Format::Rgba8Srgb);
472-
473-
return supported_formats
474-
.into_iter()
475-
.find(|format| -> bool { format.base_format().1 == ChannelType::Srgb })
476-
.unwrap_or(default_format);
477-
}
478404
}

crates/lambda-platform/src/gfx/mod.rs

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
use gfx_hal::Instance;
1+
use gfx_hal::{
2+
queue::QueueFamily,
3+
Instance,
4+
};
25

6+
use self::gpu::RenderQueueType;
37
use super::winit::WindowHandle;
48

59
pub mod api;
610
pub mod gpu;
711
pub mod pipeline;
12+
pub mod surface;
813

914
use api::RenderingAPI;
1015

@@ -39,52 +44,87 @@ pub mod gfx_hal_exports {
3944
};
4045
}
4146

42-
pub struct GfxInstance<B: gfx_hal::Backend> {
43-
instance: B::Instance,
47+
pub struct GfxInstance<RenderBackend: gfx_hal::Backend> {
48+
instance: RenderBackend::Instance,
4449
}
4550

46-
impl<B: gfx_hal::Backend> GfxInstance<B> {
51+
impl<RenderBackend: gfx_hal::Backend> GfxInstance<RenderBackend> {
4752
/// Create a new GfxInstance connected to the platforms primary backend.
4853
pub fn new(name: &str) -> Self {
49-
let instance = B::Instance::create(name, 1)
54+
let instance = RenderBackend::Instance::create(name, 1)
5055
.expect("gfx backend not supported by the current platform");
5156

5257
return Self { instance };
5358
}
5459

5560
/// Create a surface for a given lambda window using it's underlying
5661
/// winit window handle.
57-
/// TODO(vmarcella): Wrap up the B::Surface type to a custom type of our own.
58-
pub fn create_surface(&self, window_handle: &WindowHandle) -> B::Surface {
59-
return unsafe {
60-
self
62+
pub fn create_surface(
63+
&self,
64+
window_handle: &WindowHandle,
65+
) -> surface::Surface<RenderBackend> {
66+
unsafe {
67+
let surface = self
6168
.instance
6269
.create_surface(&window_handle.window_handle)
63-
.unwrap()
70+
.unwrap();
71+
72+
return surface::Surface::new(surface);
6473
};
6574
}
6675

67-
/// Destroy a surface created by this graphical instance.
68-
pub fn destroy_surface(&self, mut surface: B::Surface) {
76+
pub fn destroy_surface(&self, surface: RenderBackend::Surface) {
6977
unsafe {
7078
self.instance.destroy_surface(surface);
7179
}
7280
}
81+
}
7382

74-
/// Open a connection to the primary GPU with an optional surface that the GPU
75-
/// can access for rendering.
76-
// TODO(vmarcella): This function should allow the RenderQueueType to be
77-
// optionally passed in with the default type being Graphical.
78-
pub fn open_primary_gpu(
79-
&self,
80-
surface: Option<&B::Surface>,
81-
) -> gpu::GfxGpu<B> {
82-
let adapter = self.instance.enumerate_adapters().remove(0);
83-
return gpu::GfxGpu::<B>::new(
83+
/// GpuBuilder for constructing a GPU
84+
pub struct GpuBuilder<RenderBackend: gfx_hal_exports::Backend> {
85+
adapter: gfx_hal::adapter::Adapter<RenderBackend>,
86+
render_queue_type: RenderQueueType,
87+
}
88+
89+
impl<RenderBackend: gfx_hal_exports::Backend> GpuBuilder<RenderBackend> {
90+
pub fn new(instance: &mut GfxInstance<RenderBackend>) -> Self {
91+
let adapter = instance.instance.enumerate_adapters().remove(0);
92+
return Self {
8493
adapter,
85-
gpu::RenderQueueType::Graphical,
86-
surface,
87-
);
94+
render_queue_type: RenderQueueType::Graphical,
95+
};
96+
}
97+
98+
pub fn with_render_queue_type(mut self, queue_type: RenderQueueType) -> Self {
99+
self.render_queue_type = queue_type;
100+
return self;
101+
}
102+
103+
/// Builds a GPU
104+
pub fn build(
105+
self,
106+
surface: Option<&surface::Surface<RenderBackend>>,
107+
) -> Result<gpu::GfxGpu<RenderBackend>, String> {
108+
match (surface, self.render_queue_type) {
109+
(Some(surface), RenderQueueType::Graphical) => {
110+
let adapter = self.adapter;
111+
let queue_family = adapter
112+
.queue_families
113+
.iter()
114+
.find(|family| {
115+
return surface.can_support_queue_family(family)
116+
&& family.queue_type().supports_graphics();
117+
})
118+
.expect("No compatible queue family found.")
119+
.id();
120+
121+
let formats =
122+
surface.get_first_supported_format(&adapter.physical_device);
123+
124+
return Ok(gpu::GfxGpu::new(adapter, queue_family));
125+
}
126+
(_, _) => return Err("Failed to build GPU.".to_string()),
127+
}
88128
}
89129
}
90130

0 commit comments

Comments
 (0)