Skip to content

Object management improvements #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 48 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
5894cb7
Added surface structs
CodingRays Jan 10, 2022
1e1d52d
Doc improvements
CodingRays Jan 10, 2022
7a97949
Added surface capabilities utility struct
CodingRays Jan 10, 2022
8c73102
Added loading of surface and swapchain extensions
CodingRays Jan 11, 2022
4c67c4e
Sort devices by number of features
CodingRays Jan 11, 2022
9c89537
Moved old main to examples directory
CodingRays Jan 12, 2022
c41eed9
Remove instance version of timeline semaphore. It's a device extension
CodingRays Jan 12, 2022
39a8ffb
Separate ObjectId from uuid system
CodingRays Jan 13, 2022
0439f8e
Added xoshiro256++ random number generator utility.
CodingRays Jan 14, 2022
3324c8d
Fix doc error
CodingRays Jan 14, 2022
a63e99c
UUID change
CodingRays Jan 14, 2022
c545e9c
Test
CodingRays Jan 14, 2022
2994afb
Instance and Device comparability
CodingRays Jan 14, 2022
405eef1
Fixed overflow add bug
CodingRays Jan 14, 2022
5f214a1
Added semaphore, event and fence to objet set
CodingRays Jan 15, 2022
0f9c19c
New object set structs
CodingRays Jan 27, 2022
edffdd1
Object Set refactor
CodingRays Jan 28, 2022
5626de5
Fix temporary naming
CodingRays Jan 28, 2022
7400939
Fix warnings
CodingRays Jan 28, 2022
5af64a9
Added tests
CodingRays Jan 28, 2022
dac948c
Added info struct for all objects
CodingRays Jan 28, 2022
1ce82a7
Rename object description structs
CodingRays Jan 28, 2022
9436622
Added documentation
CodingRays Jan 28, 2022
e3c847e
More documentation
CodingRays Jan 28, 2022
06019d6
Even more documentation
CodingRays Jan 28, 2022
738fab9
Added validation of the synchronization group when creating a resourc…
CodingRays Jan 28, 2022
c8e99ea
Added SwapchainId
CodingRays Jan 28, 2022
cbbc971
Improved surface code
CodingRays Jan 28, 2022
a377952
Added basic swapchain code
CodingRays Jan 28, 2022
b2980ec
Added error handling during swapchain build
CodingRays Jan 29, 2022
393c3a9
Added basic build function for SwapchainObjectSetBuilder
CodingRays Jan 30, 2022
9d86d97
Fix lots of windowing issues
CodingRays Jan 30, 2022
40a9ed7
Update dependencies
CodingRays Jan 30, 2022
272b723
Very crude swapchain tests
CodingRays Jan 30, 2022
d2041f7
Removed ObjectManager
CodingRays Jan 30, 2022
ac4422f
Cleanup
CodingRays Jan 30, 2022
fa6784c
Cleanup resource_object_set.rs
CodingRays Jan 30, 2022
fea4f0f
more cleanup
CodingRays Jan 30, 2022
2166b9c
Add back some resource object set tests
CodingRays Jan 31, 2022
16117cd
Add back remaining tests
CodingRays Feb 1, 2022
1823ef0
Add semaphore and fences to swapchain object set
CodingRays Feb 1, 2022
7621a26
Added image views to swapchain object set
CodingRays Feb 1, 2022
10acb04
Swapchain test in old main
CodingRays Feb 1, 2022
3b7d32c
Declare public functions returning handles as unsafe
CodingRays Feb 1, 2022
bcccf16
ResourceObjectSet documentation
CodingRays Feb 2, 2022
bb2878a
Uses
CodingRays Feb 2, 2022
9d9525b
SwapchainObjectSet documentation
CodingRays Feb 2, 2022
4667c28
Fixes for doctest
CodingRays Feb 3, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@ name = "rosella-rs"
version = "0.1.0"
edition = "2018"

[features]
__internal_doc_test = []
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
ash = "0.34.0"
ash-window = "0.8.0"
ash = "0.35.1+1.2.203.0"
ash-window = "0.9.0"
concurrent-queue = "1.2.2"
gpu-allocator = "0.12.0"
gpu-allocator = "0.16.0"
lazy_static = "1.4.0"
log = "0.4.14"
topological-sort = "0.1.0"
shaderc = "0.7.3"
topological-sort = "0.1.0"
nalgebra = "0.29.0"
paste = "1.0.6"
winit = "0.25.0"
winit = "0.26.1"
xxhash-rust = { version="0.8.2", features=["xxh3", "const_xxh3"] }

[dev-dependencies]
Expand Down
44 changes: 37 additions & 7 deletions tests/old_main.rs → examples/old_main.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
mod test_common;

extern crate ash_window;
extern crate winit;

use ash::vk;
use winit::event::{Event, WindowEvent};
use winit::event_loop::ControlFlow;

use rosella_rs::init::initialization_registry::InitializationRegistry;
use rosella_rs::init::rosella_features::{register_rosella_debug, register_rosella_headless};
use rosella_rs::init::rosella_features::{register_rosella_debug, register_rosella_headless, register_rosella_present};
use rosella_rs::objects::Format;
use rosella_rs::objects::image::ImageViewDescription;
use rosella_rs::objects::swapchain::{SwapchainCreateDesc, SwapchainImageSpec};
use rosella_rs::objects::swapchain_object_set::SwapchainObjectSetBuilder;
use rosella_rs::rosella::Rosella;
use rosella_rs::window::RosellaWindow;
use rosella_rs::shader::{GraphicsContext, GraphicsShader};
Expand All @@ -18,6 +21,7 @@ fn setup_rosella(window: &RosellaWindow) -> Rosella {
let mut registry = InitializationRegistry::new();

register_rosella_headless(&mut registry);
register_rosella_present(&mut registry);
register_rosella_debug(&mut registry, false);

match Rosella::new(registry, window, "new_new_rosella_example_scene_1") {
Expand All @@ -29,22 +33,46 @@ fn setup_rosella(window: &RosellaWindow) -> Rosella {
fn main() {
env_logger::init();

let window = RosellaWindow::new("New New Rosella in Rust tm", 1396.0, 752.0);
let window = RosellaWindow::new("New New Rosella in Rust tm", 1000.0, 700.0);
let rosella = setup_rosella(&window);
window.handle.set_visible(true);

// Application Setup usually goes here. Anything in the window loop is either for closing or for looping.
let basic_vertex_format = VertexFormatBuilder::new()
.element(data_type::FLOAT, 3)
.build();

GraphicsShader::new(rosella.device.clone(), include_str!("test_resources/triangle.vert").to_string(), include_str!("test_resources/triangle.frag").to_string(), GraphicsContext {
GraphicsShader::new(rosella.device.clone(), include_str!("resources/triangle.vert").to_string(), include_str!("resources/triangle.frag").to_string(), GraphicsContext {
mutable_uniforms: Default::default(),
push_uniforms: Default::default(),
vertex_format: basic_vertex_format,
});
println!("Successfully created shaders.");

/*window.event_loop.run(move |event, _, control_flow| {
let capabilities = rosella.device.get_surface_capabilities(rosella.surface).unwrap();
println!("Capabilities: {:?}", capabilities.get_capabilities());

let surface_format = capabilities.get_surface_formats().get(0).unwrap();

let desc = SwapchainCreateDesc::make(
SwapchainImageSpec::make(
Format::format_for(surface_format.format),
surface_format.color_space,
1000,
700,
),
capabilities.get_capabilities().min_image_count,
vk::ImageUsageFlags::COLOR_ATTACHMENT,
*capabilities.get_present_modes().get(0).unwrap()
);

let mut swapchain_set_builder = SwapchainObjectSetBuilder::new(rosella.device.clone(), rosella.surface, desc, None).unwrap();

swapchain_set_builder.add_views(ImageViewDescription::make_full(vk::ImageViewType::TYPE_2D, Format::format_for(surface_format.format), vk::ImageAspectFlags::COLOR));

let swapchain_set = swapchain_set_builder.build();

window.event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;

match event {
Expand All @@ -60,5 +88,7 @@ fn main() {
}
_ => (),
}
});*/
});

drop(swapchain_set);
}
File renamed without changes.
File renamed without changes.
70 changes: 67 additions & 3 deletions src/device.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,35 @@
use std::cmp::Ordering;
use std::collections::HashMap;
use std::fmt::{Debug, Formatter, Pointer};
use std::mem::ManuallyDrop;
use std::sync::Arc;

use ash::vk;

use crate::init::EnabledFeatures;
use crate::instance::InstanceContext;
use crate::objects::id::SurfaceId;
use crate::objects::surface::{Surface, SurfaceCapabilities};
use crate::util::extensions::{AsRefOption, ExtensionFunctionSet, VkExtensionInfo, VkExtensionFunctions};
use crate::UUID;
use crate::{NamedUUID, UUID};
use crate::objects::allocator::Allocator;

pub struct DeviceContextImpl {
struct DeviceContextImpl {
id: NamedUUID,
instance: InstanceContext,
device: ash::Device,
physical_device: vk::PhysicalDevice,
extensions: ExtensionFunctionSet,
allocator: ManuallyDrop<Allocator>, // We need manually drop to ensure it is dropped before the device
features: EnabledFeatures,
surfaces: HashMap<SurfaceId, (Surface, SurfaceCapabilities)>,
}

impl Drop for DeviceContextImpl {
fn drop(&mut self) {
unsafe {
ManuallyDrop::drop(&mut self.allocator);

self.device.destroy_device(None);
}
}
Expand All @@ -27,16 +39,29 @@ impl Drop for DeviceContextImpl {
pub struct DeviceContext(Arc<DeviceContextImpl>);

impl DeviceContext {
pub fn new(instance: InstanceContext, device: ash::Device, physical_device: vk::PhysicalDevice, extensions: ExtensionFunctionSet, features: EnabledFeatures) -> Self {
pub fn new(instance: InstanceContext, device: ash::Device, physical_device: vk::PhysicalDevice, extensions: ExtensionFunctionSet, features: EnabledFeatures, surfaces: &[Surface]) -> Self {
let surfaces : HashMap<_, _> = surfaces.iter().map(|surface| {
(surface.get_id(), (surface.clone(), SurfaceCapabilities::new(&instance, physical_device, surface.get_handle()).unwrap()))
}).collect();

let allocator = Allocator::new(instance.vk().clone(), device.clone(), physical_device);

Self(Arc::new(DeviceContextImpl{
id: NamedUUID::with_str("Device"),
instance,
device,
physical_device,
extensions,
allocator: ManuallyDrop::new(allocator),
features,
surfaces,
}))
}

pub fn get_uuid(&self) -> &NamedUUID {
&self.0.id
}

pub fn get_entry(&self) -> &ash::Entry {
self.0.instance.get_entry()
}
Expand All @@ -61,7 +86,46 @@ impl DeviceContext {
self.0.extensions.contains(uuid)
}

pub fn get_allocator(&self) -> &Allocator {
&self.0.allocator
}

pub fn get_enabled_features(&self) -> &EnabledFeatures {
&self.0.features
}

pub fn get_surface(&self, id: SurfaceId) -> Option<Surface> {
self.0.surfaces.get(&id).map(|data| data.0.clone())
}

pub fn get_surface_capabilities(&self, id: SurfaceId) -> Option<&SurfaceCapabilities> {
self.0.surfaces.get(&id).map(|(_, cap)| cap)
}
}

impl PartialEq for DeviceContext {
fn eq(&self, other: &Self) -> bool {
self.0.id.eq(&other.0.id)
}
}

impl Eq for DeviceContext {
}

impl PartialOrd for DeviceContext {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.0.id.partial_cmp(&other.0.id)
}
}

impl Ord for DeviceContext {
fn cmp(&self, other: &Self) -> Ordering {
self.0.id.cmp(&other.0.id)
}
}

impl Debug for DeviceContext {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
4 changes: 2 additions & 2 deletions src/init/application_feature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub trait ApplicationInstanceFeature : FeatureBase {
fn enable(&mut self, features: &mut dyn FeatureAccess, info: &instance::InstanceInfo, config: &mut instance::InstanceConfigurator);

/// Performs any necessary post creation steps and generates the data that is sent back to the application
fn finish(&mut self, _: &ash::Instance, _: &ExtensionFunctionSet) -> Option<Box<dyn Any>> {
fn finish(&mut self, _: &ash::Instance, _: &ExtensionFunctionSet) -> Option<Box<dyn Any + Send + Sync>> {
None
}
}
Expand All @@ -59,7 +59,7 @@ pub trait ApplicationDeviceFeature: Send + FeatureBase {
/// Configures the device
fn enable(&mut self, features: &mut dyn FeatureAccess, info: &device::DeviceInfo, config: &mut device::DeviceConfigurator);

fn finish(&mut self, _: &InstanceContext, _: &ash::Device, _: &ExtensionFunctionSet) -> Option<Box<dyn Any>> {
fn finish(&mut self, _: &InstanceContext, _: &ash::Device, _: &ExtensionFunctionSet) -> Option<Box<dyn Any + Sync + Send>> {
None
}
}
Expand Down
41 changes: 34 additions & 7 deletions src/init/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use crate::init::initialization_registry::InitializationRegistry;
use crate::init::utils::{ExtensionProperties, Feature, FeatureProcessor};
use crate::{NamedUUID, UUID};
use crate::init::EnabledFeatures;
use crate::objects::surface::{Surface, SurfaceCapabilities};
use crate::util::extensions::{DeviceExtensionLoader, DeviceExtensionLoaderFn, ExtensionFunctionSet, VkExtensionInfo};
use crate::rosella::{DeviceContext, InstanceContext, VulkanVersion};

Expand Down Expand Up @@ -93,6 +94,7 @@ impl VulkanQueue {
pub enum DeviceCreateError {
VulkanError(vk::Result),
RequiredFeatureNotSupported(NamedUUID),
SurfaceNotSupported,
Utf8Error(std::str::Utf8Error),
NulError(std::ffi::NulError),
ExtensionNotSupported,
Expand Down Expand Up @@ -122,8 +124,7 @@ impl From<std::ffi::NulError> for DeviceCreateError {
/// This function will consume the device features stored in the registry.
///
/// All discovered physical devices will be processed and the most suitable device will be selected.
/// (TODO not implemented yet)
pub fn create_device(registry: &mut InitializationRegistry, instance: InstanceContext) -> Result<DeviceContext, DeviceCreateError> {
pub fn create_device(registry: &mut InitializationRegistry, instance: InstanceContext, surfaces: &[Surface]) -> Result<DeviceContext, DeviceCreateError> {
let (graph, features) : (Vec<_>, Vec<_>) = registry.take_device_features().into_iter().map(
|(name, dependencies, feature, required)| {
((name.clone(), dependencies), (name, feature, required))
Expand All @@ -149,7 +150,7 @@ pub fn create_device(registry: &mut InitializationRegistry, instance: InstanceCo
(name.clone(), feature.make_instance(), *required)
}).collect();

DeviceBuilder::new(instance.clone(), device, ordering.clone().into_boxed_slice(), feature_instances)
DeviceBuilder::new(instance.clone(), device, ordering.clone().into_boxed_slice(), feature_instances, surfaces)
}).collect();

let mut devices : Vec<_> = devices.into_iter().filter_map(|mut device| {
Expand All @@ -166,7 +167,9 @@ pub fn create_device(registry: &mut InitializationRegistry, instance: InstanceCo
return Err(DeviceCreateError::NoSuitableDeviceFound);
}

let device = devices.remove(0).build()?;
devices.sort_by(|a, b| b.get_enabled_feature_count().cmp(&a.get_enabled_feature_count())); // Need to reverse ordering to have highest first

let device = devices.remove(0).build(surfaces)?;

Ok(device)
}
Expand Down Expand Up @@ -221,13 +224,15 @@ struct DeviceBuilder {
physical_device: vk::PhysicalDevice,
info: Option<DeviceInfo>,
config: Option<DeviceConfigurator>,
enabled_features: u32,
surfaces_supported: bool,
}

impl DeviceBuilder {
/// Generates a new builder for some feature set and physical device.
///
/// No vulkan functions will be called here.
fn new(instance: InstanceContext, physical_device: vk::PhysicalDevice, order: Box<[NamedUUID]>, features: Vec<(NamedUUID, Box<dyn ApplicationDeviceFeature>, bool)>) -> Self {
fn new(instance: InstanceContext, physical_device: vk::PhysicalDevice, order: Box<[NamedUUID]>, features: Vec<(NamedUUID, Box<dyn ApplicationDeviceFeature>, bool)>, surfaces: &[Surface]) -> Self {
let processor = FeatureProcessor::new(features.into_iter().map(
|(name, feature, required)|
(name.get_uuid(),
Expand All @@ -239,12 +244,16 @@ impl DeviceBuilder {
})
), order);

let surfaces_supported = surfaces.iter().map(|surface| SurfaceCapabilities::new(&instance, physical_device, surface.get_handle()).is_some()).all(|v| v);

Self {
processor,
instance,
physical_device,
info: None,
config: None,
enabled_features: 0,
surfaces_supported
}
}

Expand All @@ -261,6 +270,14 @@ impl DeviceBuilder {
self.info = Some(DeviceInfo::new(self.instance.clone(), self.physical_device)?);
let info = self.info.as_ref().unwrap();

let device_name = unsafe { std::ffi::CStr::from_ptr(info.properties_1_0.device_name.as_ptr()).to_str()? };
log::info!("Found vulkan device \"{}\"({:#8X}) {:?}", device_name, info.properties_1_0.device_id ,info.properties_1_0.device_type);

if !self.surfaces_supported {
return Err(DeviceCreateError::SurfaceNotSupported)
}

let mut enabled_features = 0;
self.processor.run_pass::<DeviceCreateError, _>(
DeviceFeatureState::Initialized,
|feature, access| {
Expand All @@ -271,6 +288,7 @@ impl DeviceBuilder {
InitResult::Ok => {
log::debug!("Initialized feature {:?}", feature.name);
feature.state = DeviceFeatureState::Initialized;
enabled_features += 1;
}
InitResult::Disable => {
feature.state = DeviceFeatureState::Disabled;
Expand All @@ -285,6 +303,8 @@ impl DeviceBuilder {
}
)?;

self.enabled_features = enabled_features;

Ok(())
}

Expand Down Expand Up @@ -321,19 +341,26 @@ impl DeviceBuilder {
}

/// Creates the vulkan device
fn build(self) -> Result<DeviceContext, DeviceCreateError> {
fn build(self, surfaces: &[Surface]) -> Result<DeviceContext, DeviceCreateError> {
let instance = self.instance;

let info = self.info.expect("Called build but info is none");
let (device, function_set) = self.config.expect("Called build but config is none")
.build_device(&info)?;

let device_name = unsafe { std::ffi::CStr::from_ptr(info.properties_1_0.device_name.as_ptr()).to_str()? };
log::info!("Creating vulkan device \"{}\"({:#8X}) {:?}", device_name, info.properties_1_0.device_id ,info.properties_1_0.device_type);

let features = EnabledFeatures::new(self.processor.into_iter().filter_map(
|mut info| {
Some((info.name.get_uuid(), info.feature.as_mut().finish(&instance, &device, &function_set)))
}));

Ok(DeviceContext::new(instance, device, self.physical_device, function_set, features))
Ok(DeviceContext::new(instance, device, self.physical_device, function_set, features, surfaces))
}

fn get_enabled_feature_count(&self) -> u32 {
self.enabled_features
}
}

Expand Down
Loading