resizes and everything... Big Big Moves
This commit is contained in:
parent
520d2e148b
commit
29a5c272b4
4 changed files with 1096 additions and 755 deletions
649
gb-emu/src/renderer/vulkan/types.rs
Normal file
649
gb-emu/src/renderer/vulkan/types.rs
Normal file
|
@ -0,0 +1,649 @@
|
|||
use ash::{
|
||||
extensions::khr::{Surface, Swapchain},
|
||||
vk, Device,
|
||||
};
|
||||
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
|
||||
use winit::window::Window;
|
||||
|
||||
use crate::window::ResolutionData;
|
||||
|
||||
use super::{
|
||||
utils::{find_memorytype_index, record_submit_commandbuffer},
|
||||
WindowDataManager,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Copy)]
|
||||
pub(super) struct Vertex(pub(super) f32, pub(super) f32);
|
||||
|
||||
pub(super) struct VulkanData {
|
||||
pub(super) pdevice: vk::PhysicalDevice,
|
||||
pub(super) device: Device,
|
||||
pub(super) device_memory_properties: vk::PhysicalDeviceMemoryProperties,
|
||||
pub(super) desc_set_layouts: [vk::DescriptorSetLayout; 1],
|
||||
pub(super) present_queue: vk::Queue,
|
||||
|
||||
pub(super) pool: vk::CommandPool,
|
||||
pub(super) draw_command_buffer: vk::CommandBuffer,
|
||||
pub(super) setup_command_buffer: vk::CommandBuffer,
|
||||
|
||||
pub(super) present_complete_semaphore: vk::Semaphore,
|
||||
pub(super) rendering_complete_semaphore: vk::Semaphore,
|
||||
|
||||
pub(super) draw_commands_reuse_fence: vk::Fence,
|
||||
pub(super) setup_commands_reuse_fence: vk::Fence,
|
||||
|
||||
pub(super) descriptor_sets: Vec<vk::DescriptorSet>,
|
||||
pub(super) descriptor_pool: vk::DescriptorPool,
|
||||
}
|
||||
|
||||
impl VulkanData {
|
||||
pub(super) unsafe fn new(manager: &WindowDataManager, surface: &SurfaceData) -> Self {
|
||||
let pdevices = manager
|
||||
.instance
|
||||
.enumerate_physical_devices()
|
||||
.expect("Physical device error");
|
||||
let (pdevice, queue_family_index) = pdevices
|
||||
.iter()
|
||||
.find_map(|pdevice| {
|
||||
manager
|
||||
.instance
|
||||
.get_physical_device_queue_family_properties(*pdevice)
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find_map(|(index, info)| {
|
||||
let supports_graphic_and_surface =
|
||||
info.queue_flags.contains(vk::QueueFlags::GRAPHICS)
|
||||
&& surface
|
||||
.surface_loader
|
||||
.get_physical_device_surface_support(
|
||||
*pdevice,
|
||||
index as u32,
|
||||
surface.surface,
|
||||
)
|
||||
.unwrap();
|
||||
if supports_graphic_and_surface {
|
||||
Some((*pdevice, index))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
.expect("Couldn't find suitable device.");
|
||||
let queue_family_index = queue_family_index as u32;
|
||||
let device_extension_names_raw = [
|
||||
Swapchain::name().as_ptr(),
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
vk::KhrPortabilitySubsetFn::name().as_ptr(),
|
||||
];
|
||||
let features = vk::PhysicalDeviceFeatures {
|
||||
shader_clip_distance: 1,
|
||||
..Default::default()
|
||||
};
|
||||
let priorities = [1.0];
|
||||
|
||||
let queue_info = vk::DeviceQueueCreateInfo::builder()
|
||||
.queue_family_index(queue_family_index)
|
||||
.queue_priorities(&priorities)
|
||||
.build();
|
||||
|
||||
let device_create_info = vk::DeviceCreateInfo::builder()
|
||||
.queue_create_infos(std::slice::from_ref(&queue_info))
|
||||
.enabled_extension_names(&device_extension_names_raw)
|
||||
.enabled_features(&features)
|
||||
.build();
|
||||
|
||||
let device = manager
|
||||
.instance
|
||||
.create_device(pdevice, &device_create_info, None)
|
||||
.unwrap();
|
||||
|
||||
let present_queue = device.get_device_queue(queue_family_index, 0);
|
||||
|
||||
let pool_create_info = vk::CommandPoolCreateInfo::builder()
|
||||
.flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER)
|
||||
.queue_family_index(queue_family_index)
|
||||
.build();
|
||||
|
||||
let pool = device.create_command_pool(&pool_create_info, None).unwrap();
|
||||
|
||||
let command_buffer_allocate_info = vk::CommandBufferAllocateInfo::builder()
|
||||
.command_buffer_count(2)
|
||||
.command_pool(pool)
|
||||
.level(vk::CommandBufferLevel::PRIMARY)
|
||||
.build();
|
||||
|
||||
let command_buffers = device
|
||||
.allocate_command_buffers(&command_buffer_allocate_info)
|
||||
.unwrap();
|
||||
let setup_command_buffer = command_buffers[0];
|
||||
let draw_command_buffer = command_buffers[1];
|
||||
|
||||
let device_memory_properties = manager
|
||||
.instance
|
||||
.get_physical_device_memory_properties(pdevice);
|
||||
|
||||
let fence_create_info = vk::FenceCreateInfo::builder()
|
||||
.flags(vk::FenceCreateFlags::SIGNALED)
|
||||
.build();
|
||||
|
||||
let draw_commands_reuse_fence = device
|
||||
.create_fence(&fence_create_info, None)
|
||||
.expect("Create fence failed.");
|
||||
let setup_commands_reuse_fence = device
|
||||
.create_fence(&fence_create_info, None)
|
||||
.expect("Create fence failed.");
|
||||
|
||||
let semaphore_create_info = vk::SemaphoreCreateInfo::default();
|
||||
|
||||
let present_complete_semaphore = device
|
||||
.create_semaphore(&semaphore_create_info, None)
|
||||
.unwrap();
|
||||
let rendering_complete_semaphore = device
|
||||
.create_semaphore(&semaphore_create_info, None)
|
||||
.unwrap();
|
||||
|
||||
let descriptor_sizes = [
|
||||
vk::DescriptorPoolSize {
|
||||
ty: vk::DescriptorType::UNIFORM_BUFFER,
|
||||
descriptor_count: 1,
|
||||
},
|
||||
vk::DescriptorPoolSize {
|
||||
ty: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
|
||||
descriptor_count: 1,
|
||||
},
|
||||
];
|
||||
let descriptor_pool_info = vk::DescriptorPoolCreateInfo::builder()
|
||||
.pool_sizes(&descriptor_sizes)
|
||||
.max_sets(1)
|
||||
.build();
|
||||
|
||||
let descriptor_pool = device
|
||||
.create_descriptor_pool(&descriptor_pool_info, None)
|
||||
.unwrap();
|
||||
let desc_layout_bindings = [
|
||||
vk::DescriptorSetLayoutBinding {
|
||||
descriptor_type: vk::DescriptorType::UNIFORM_BUFFER,
|
||||
descriptor_count: 1,
|
||||
stage_flags: vk::ShaderStageFlags::FRAGMENT,
|
||||
..Default::default()
|
||||
},
|
||||
vk::DescriptorSetLayoutBinding {
|
||||
binding: 1,
|
||||
descriptor_type: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
|
||||
descriptor_count: 1,
|
||||
stage_flags: vk::ShaderStageFlags::FRAGMENT,
|
||||
..Default::default()
|
||||
},
|
||||
];
|
||||
let descriptor_info = vk::DescriptorSetLayoutCreateInfo::builder()
|
||||
.bindings(&desc_layout_bindings)
|
||||
.build();
|
||||
|
||||
let desc_set_layouts = [device
|
||||
.create_descriptor_set_layout(&descriptor_info, None)
|
||||
.unwrap()];
|
||||
|
||||
let desc_alloc_info = vk::DescriptorSetAllocateInfo::builder()
|
||||
.descriptor_pool(descriptor_pool)
|
||||
.set_layouts(&desc_set_layouts)
|
||||
.build();
|
||||
|
||||
let descriptor_sets = device.allocate_descriptor_sets(&desc_alloc_info).unwrap();
|
||||
|
||||
Self {
|
||||
pdevice,
|
||||
device,
|
||||
device_memory_properties,
|
||||
present_queue,
|
||||
pool,
|
||||
draw_command_buffer,
|
||||
setup_command_buffer,
|
||||
present_complete_semaphore,
|
||||
rendering_complete_semaphore,
|
||||
draw_commands_reuse_fence,
|
||||
setup_commands_reuse_fence,
|
||||
descriptor_sets,
|
||||
desc_set_layouts,
|
||||
descriptor_pool,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct SurfaceData {
|
||||
pub(super) surface: vk::SurfaceKHR,
|
||||
pub(super) surface_loader: Surface,
|
||||
}
|
||||
|
||||
impl SurfaceData {
|
||||
pub(super) unsafe fn new(window: &Window, manager: &WindowDataManager) -> Self {
|
||||
let surface = ash_window::create_surface(
|
||||
&manager.entry,
|
||||
&manager.instance,
|
||||
window.raw_display_handle(),
|
||||
window.raw_window_handle(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let surface_loader = Surface::new(&manager.entry, &manager.instance);
|
||||
|
||||
Self {
|
||||
surface,
|
||||
surface_loader,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) unsafe fn manual_drop(&mut self) {
|
||||
self.surface_loader.destroy_surface(self.surface, None);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct SwapchainData {
|
||||
pub(super) swapchain_loader: Swapchain,
|
||||
pub(super) swapchain: vk::SwapchainKHR,
|
||||
pub(super) format: vk::SurfaceFormatKHR,
|
||||
pub(super) surface_resolution: vk::Extent2D,
|
||||
pub(super) present_image_views: Vec<vk::ImageView>,
|
||||
pub(super) viewports: [vk::Viewport; 1],
|
||||
pub(super) scissors: [vk::Rect2D; 1],
|
||||
pub(super) sampler: vk::Sampler,
|
||||
pub(super) texture_memory: vk::DeviceMemory,
|
||||
pub(super) tex_image_view: vk::ImageView,
|
||||
pub(super) image_buffer: vk::Buffer,
|
||||
pub(super) image_buffer_memory: vk::DeviceMemory,
|
||||
pub(super) image_buffer_memory_req: vk::MemoryRequirements,
|
||||
pub(super) image_extent: vk::Extent2D,
|
||||
pub(super) texture_image: vk::Image,
|
||||
}
|
||||
|
||||
impl SwapchainData {
|
||||
pub(super) unsafe fn new(
|
||||
resolutions: ResolutionData,
|
||||
manager: &WindowDataManager,
|
||||
|
||||
surface: &SurfaceData,
|
||||
vulkan: &VulkanData,
|
||||
) -> (Self, vk::PipelineViewportStateCreateInfo) {
|
||||
let format = surface
|
||||
.surface_loader
|
||||
.get_physical_device_surface_formats(vulkan.pdevice, surface.surface)
|
||||
.unwrap()[0];
|
||||
|
||||
let surface_capabilities = surface
|
||||
.surface_loader
|
||||
.get_physical_device_surface_capabilities(vulkan.pdevice, surface.surface)
|
||||
.unwrap();
|
||||
let mut desired_image_count = surface_capabilities.min_image_count + 1;
|
||||
if surface_capabilities.max_image_count > 0
|
||||
&& desired_image_count > surface_capabilities.max_image_count
|
||||
{
|
||||
desired_image_count = surface_capabilities.max_image_count;
|
||||
}
|
||||
let surface_resolution = match surface_capabilities.current_extent.width {
|
||||
std::u32::MAX => vk::Extent2D {
|
||||
width: resolutions.real_width,
|
||||
height: resolutions.real_height,
|
||||
},
|
||||
_ => surface_capabilities.current_extent,
|
||||
};
|
||||
let pre_transform = if surface_capabilities
|
||||
.supported_transforms
|
||||
.contains(vk::SurfaceTransformFlagsKHR::IDENTITY)
|
||||
{
|
||||
vk::SurfaceTransformFlagsKHR::IDENTITY
|
||||
} else {
|
||||
surface_capabilities.current_transform
|
||||
};
|
||||
let present_modes = surface
|
||||
.surface_loader
|
||||
.get_physical_device_surface_present_modes(vulkan.pdevice, surface.surface)
|
||||
.unwrap();
|
||||
let present_mode = present_modes
|
||||
.iter()
|
||||
.cloned()
|
||||
.find(|&mode| mode == vk::PresentModeKHR::MAILBOX)
|
||||
.unwrap_or(vk::PresentModeKHR::FIFO);
|
||||
let swapchain_loader = Swapchain::new(&manager.instance, &vulkan.device);
|
||||
|
||||
let swapchain_create_info = vk::SwapchainCreateInfoKHR::builder()
|
||||
.surface(surface.surface)
|
||||
.min_image_count(desired_image_count)
|
||||
.image_color_space(format.color_space)
|
||||
.image_format(format.format)
|
||||
.image_extent(surface_resolution)
|
||||
.image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
|
||||
.image_sharing_mode(vk::SharingMode::EXCLUSIVE)
|
||||
.pre_transform(pre_transform)
|
||||
.composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
|
||||
.present_mode(present_mode)
|
||||
.clipped(true)
|
||||
.image_array_layers(1)
|
||||
.build();
|
||||
|
||||
let swapchain = swapchain_loader
|
||||
.create_swapchain(&swapchain_create_info, None)
|
||||
.unwrap();
|
||||
|
||||
let present_images = swapchain_loader.get_swapchain_images(swapchain).unwrap();
|
||||
let present_image_views: Vec<vk::ImageView> = present_images
|
||||
.iter()
|
||||
.map(|&image| {
|
||||
let create_view_info = vk::ImageViewCreateInfo::builder()
|
||||
.view_type(vk::ImageViewType::TYPE_2D)
|
||||
.format(format.format)
|
||||
.components(vk::ComponentMapping {
|
||||
r: vk::ComponentSwizzle::R,
|
||||
g: vk::ComponentSwizzle::G,
|
||||
b: vk::ComponentSwizzle::B,
|
||||
a: vk::ComponentSwizzle::A,
|
||||
})
|
||||
.subresource_range(vk::ImageSubresourceRange {
|
||||
aspect_mask: vk::ImageAspectFlags::COLOR,
|
||||
base_mip_level: 0,
|
||||
level_count: 1,
|
||||
base_array_layer: 0,
|
||||
layer_count: 1,
|
||||
})
|
||||
.image(image)
|
||||
.build();
|
||||
vulkan
|
||||
.device
|
||||
.create_image_view(&create_view_info, None)
|
||||
.unwrap()
|
||||
})
|
||||
.collect();
|
||||
|
||||
let viewports = [vk::Viewport {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
width: surface_resolution.width as f32,
|
||||
height: surface_resolution.height as f32,
|
||||
min_depth: 0.0,
|
||||
max_depth: 1.0,
|
||||
}];
|
||||
let scissors = [surface_resolution.into()];
|
||||
let viewport_state_info = vk::PipelineViewportStateCreateInfo::builder()
|
||||
.scissors(&scissors)
|
||||
.viewports(&viewports)
|
||||
.build();
|
||||
|
||||
let image_extent = vk::Extent2D {
|
||||
width: resolutions.scaled_width,
|
||||
height: resolutions.scaled_height,
|
||||
};
|
||||
|
||||
let image_buffer_info = vk::BufferCreateInfo {
|
||||
size: (std::mem::size_of::<u8>()
|
||||
* (resolutions.scaled_width * resolutions.scaled_height * 4) as usize)
|
||||
as u64,
|
||||
usage: vk::BufferUsageFlags::TRANSFER_SRC,
|
||||
sharing_mode: vk::SharingMode::EXCLUSIVE,
|
||||
..Default::default()
|
||||
};
|
||||
let image_buffer = vulkan
|
||||
.device
|
||||
.create_buffer(&image_buffer_info, None)
|
||||
.unwrap();
|
||||
let image_buffer_memory_req = vulkan.device.get_buffer_memory_requirements(image_buffer);
|
||||
let image_buffer_memory_index = find_memorytype_index(
|
||||
&image_buffer_memory_req,
|
||||
&vulkan.device_memory_properties,
|
||||
vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
|
||||
)
|
||||
.expect("Unable to find suitable memorytype for the image buffer.");
|
||||
|
||||
let image_buffer_allocate_info = vk::MemoryAllocateInfo {
|
||||
allocation_size: image_buffer_memory_req.size,
|
||||
memory_type_index: image_buffer_memory_index,
|
||||
..Default::default()
|
||||
};
|
||||
let image_buffer_memory = vulkan
|
||||
.device
|
||||
.allocate_memory(&image_buffer_allocate_info, None)
|
||||
.unwrap();
|
||||
|
||||
vulkan
|
||||
.device
|
||||
.bind_buffer_memory(image_buffer, image_buffer_memory, 0)
|
||||
.unwrap();
|
||||
|
||||
let texture_create_info = vk::ImageCreateInfo {
|
||||
image_type: vk::ImageType::TYPE_2D,
|
||||
format: vk::Format::R8G8B8A8_UNORM,
|
||||
extent: image_extent.into(),
|
||||
mip_levels: 1,
|
||||
array_layers: 1,
|
||||
samples: vk::SampleCountFlags::TYPE_1,
|
||||
tiling: vk::ImageTiling::OPTIMAL,
|
||||
usage: vk::ImageUsageFlags::TRANSFER_DST | vk::ImageUsageFlags::SAMPLED,
|
||||
sharing_mode: vk::SharingMode::EXCLUSIVE,
|
||||
..Default::default()
|
||||
};
|
||||
let texture_image = vulkan
|
||||
.device
|
||||
.create_image(&texture_create_info, None)
|
||||
.unwrap();
|
||||
let texture_memory_req = vulkan.device.get_image_memory_requirements(texture_image);
|
||||
let texture_memory_index = find_memorytype_index(
|
||||
&texture_memory_req,
|
||||
&vulkan.device_memory_properties,
|
||||
vk::MemoryPropertyFlags::DEVICE_LOCAL,
|
||||
)
|
||||
.expect("Unable to find suitable memory index for depth image.");
|
||||
|
||||
let texture_allocate_info = vk::MemoryAllocateInfo {
|
||||
allocation_size: texture_memory_req.size,
|
||||
memory_type_index: texture_memory_index,
|
||||
..Default::default()
|
||||
};
|
||||
let texture_memory = vulkan
|
||||
.device
|
||||
.allocate_memory(&texture_allocate_info, None)
|
||||
.unwrap();
|
||||
vulkan
|
||||
.device
|
||||
.bind_image_memory(texture_image, texture_memory, 0)
|
||||
.expect("Unable to bind depth image memory");
|
||||
|
||||
record_submit_commandbuffer(
|
||||
&vulkan.device,
|
||||
vulkan.setup_command_buffer,
|
||||
vulkan.setup_commands_reuse_fence,
|
||||
vulkan.present_queue,
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
|device, texture_command_buffer| {
|
||||
let texture_barrier = vk::ImageMemoryBarrier {
|
||||
dst_access_mask: vk::AccessFlags::TRANSFER_WRITE,
|
||||
new_layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
image: texture_image,
|
||||
subresource_range: vk::ImageSubresourceRange {
|
||||
aspect_mask: vk::ImageAspectFlags::COLOR,
|
||||
level_count: 1,
|
||||
layer_count: 1,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
device.cmd_pipeline_barrier(
|
||||
texture_command_buffer,
|
||||
vk::PipelineStageFlags::BOTTOM_OF_PIPE,
|
||||
vk::PipelineStageFlags::TRANSFER,
|
||||
vk::DependencyFlags::empty(),
|
||||
&[],
|
||||
&[],
|
||||
&[texture_barrier],
|
||||
);
|
||||
let buffer_copy_regions = vk::BufferImageCopy::builder()
|
||||
.image_subresource(
|
||||
vk::ImageSubresourceLayers::builder()
|
||||
.aspect_mask(vk::ImageAspectFlags::COLOR)
|
||||
.layer_count(1)
|
||||
.build(),
|
||||
)
|
||||
.image_extent(image_extent.into())
|
||||
.build();
|
||||
|
||||
device.cmd_copy_buffer_to_image(
|
||||
texture_command_buffer,
|
||||
image_buffer,
|
||||
texture_image,
|
||||
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
&[buffer_copy_regions],
|
||||
);
|
||||
let texture_barrier_end = vk::ImageMemoryBarrier {
|
||||
src_access_mask: vk::AccessFlags::TRANSFER_WRITE,
|
||||
dst_access_mask: vk::AccessFlags::SHADER_READ,
|
||||
old_layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
new_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
|
||||
image: texture_image,
|
||||
subresource_range: vk::ImageSubresourceRange {
|
||||
aspect_mask: vk::ImageAspectFlags::COLOR,
|
||||
level_count: 1,
|
||||
layer_count: 1,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
device.cmd_pipeline_barrier(
|
||||
texture_command_buffer,
|
||||
vk::PipelineStageFlags::TRANSFER,
|
||||
vk::PipelineStageFlags::FRAGMENT_SHADER,
|
||||
vk::DependencyFlags::empty(),
|
||||
&[],
|
||||
&[],
|
||||
&[texture_barrier_end],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
let tex_image_view_info = vk::ImageViewCreateInfo {
|
||||
view_type: vk::ImageViewType::TYPE_2D,
|
||||
format: texture_create_info.format,
|
||||
components: vk::ComponentMapping {
|
||||
r: vk::ComponentSwizzle::R,
|
||||
g: vk::ComponentSwizzle::G,
|
||||
b: vk::ComponentSwizzle::B,
|
||||
a: vk::ComponentSwizzle::A,
|
||||
},
|
||||
subresource_range: vk::ImageSubresourceRange {
|
||||
aspect_mask: vk::ImageAspectFlags::COLOR,
|
||||
level_count: 1,
|
||||
layer_count: 1,
|
||||
..Default::default()
|
||||
},
|
||||
image: texture_image,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let sampler_info = vk::SamplerCreateInfo {
|
||||
mag_filter: vk::Filter::NEAREST,
|
||||
min_filter: vk::Filter::NEAREST,
|
||||
mipmap_mode: vk::SamplerMipmapMode::NEAREST,
|
||||
address_mode_u: vk::SamplerAddressMode::MIRRORED_REPEAT,
|
||||
address_mode_v: vk::SamplerAddressMode::MIRRORED_REPEAT,
|
||||
address_mode_w: vk::SamplerAddressMode::MIRRORED_REPEAT,
|
||||
max_anisotropy: 1.0,
|
||||
border_color: vk::BorderColor::FLOAT_OPAQUE_WHITE,
|
||||
compare_op: vk::CompareOp::NEVER,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let sampler = vulkan.device.create_sampler(&sampler_info, None).unwrap();
|
||||
|
||||
let tex_image_view = vulkan
|
||||
.device
|
||||
.create_image_view(&tex_image_view_info, None)
|
||||
.unwrap();
|
||||
|
||||
let tex_descriptor = vk::DescriptorImageInfo {
|
||||
image_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
|
||||
image_view: tex_image_view,
|
||||
sampler,
|
||||
};
|
||||
|
||||
let write_desc_sets = [vk::WriteDescriptorSet {
|
||||
dst_set: vulkan.descriptor_sets[0],
|
||||
dst_binding: 1,
|
||||
descriptor_count: 1,
|
||||
descriptor_type: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
|
||||
p_image_info: &tex_descriptor,
|
||||
..Default::default()
|
||||
}];
|
||||
vulkan.device.update_descriptor_sets(&write_desc_sets, &[]);
|
||||
|
||||
(
|
||||
Self {
|
||||
swapchain_loader,
|
||||
swapchain,
|
||||
format,
|
||||
surface_resolution,
|
||||
present_image_views,
|
||||
viewports,
|
||||
scissors,
|
||||
sampler,
|
||||
texture_memory,
|
||||
tex_image_view,
|
||||
|
||||
image_buffer,
|
||||
image_buffer_memory,
|
||||
image_buffer_memory_req,
|
||||
image_extent,
|
||||
texture_image,
|
||||
},
|
||||
viewport_state_info,
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) unsafe fn manual_drop(&mut self, vulkan: &VulkanData) {
|
||||
vulkan.device.free_memory(self.image_buffer_memory, None);
|
||||
vulkan.device.destroy_buffer(self.image_buffer, None);
|
||||
vulkan.device.free_memory(self.texture_memory, None);
|
||||
vulkan.device.destroy_image_view(self.tex_image_view, None);
|
||||
vulkan.device.destroy_image(self.texture_image, None);
|
||||
|
||||
vulkan.device.destroy_sampler(self.sampler, None);
|
||||
|
||||
for &image_view in self.present_image_views.iter() {
|
||||
vulkan.device.destroy_image_view(image_view, None);
|
||||
}
|
||||
|
||||
self.swapchain_loader
|
||||
.destroy_swapchain(self.swapchain, None);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct FramebufferData {
|
||||
pub(super) framebuffers: Vec<vk::Framebuffer>,
|
||||
}
|
||||
|
||||
impl FramebufferData {
|
||||
pub(super) unsafe fn new(
|
||||
swapchain: &SwapchainData,
|
||||
vulkan: &VulkanData,
|
||||
renderpass: vk::RenderPass,
|
||||
) -> Self {
|
||||
let framebuffers: Vec<vk::Framebuffer> = swapchain
|
||||
.present_image_views
|
||||
.iter()
|
||||
.map(|&present_image_view| {
|
||||
let framebuffer_attachments = [present_image_view];
|
||||
let frame_buffer_create_info = vk::FramebufferCreateInfo::builder()
|
||||
.render_pass(renderpass)
|
||||
.attachments(&framebuffer_attachments)
|
||||
.width(swapchain.surface_resolution.width)
|
||||
.height(swapchain.surface_resolution.height)
|
||||
.layers(1)
|
||||
.build();
|
||||
|
||||
vulkan
|
||||
.device
|
||||
.create_framebuffer(&frame_buffer_create_info, None)
|
||||
.unwrap()
|
||||
})
|
||||
.collect();
|
||||
|
||||
Self { framebuffers }
|
||||
}
|
||||
}
|
98
gb-emu/src/renderer/vulkan/utils.rs
Normal file
98
gb-emu/src/renderer/vulkan/utils.rs
Normal file
|
@ -0,0 +1,98 @@
|
|||
use ash::{vk, Device};
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(super) unsafe fn record_submit_commandbuffer<F: FnOnce(&Device, vk::CommandBuffer)>(
|
||||
device: &Device,
|
||||
command_buffer: vk::CommandBuffer,
|
||||
command_buffer_reuse_fence: vk::Fence,
|
||||
submit_queue: vk::Queue,
|
||||
wait_mask: &[vk::PipelineStageFlags],
|
||||
wait_semaphores: &[vk::Semaphore],
|
||||
signal_semaphores: &[vk::Semaphore],
|
||||
f: F,
|
||||
) {
|
||||
record_commandbuffer(device, command_buffer, command_buffer_reuse_fence, f);
|
||||
submit_commandbuffer(
|
||||
device,
|
||||
command_buffer,
|
||||
command_buffer_reuse_fence,
|
||||
submit_queue,
|
||||
wait_mask,
|
||||
wait_semaphores,
|
||||
signal_semaphores,
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(super) unsafe fn record_commandbuffer<F: FnOnce(&Device, vk::CommandBuffer)>(
|
||||
device: &Device,
|
||||
command_buffer: vk::CommandBuffer,
|
||||
command_buffer_reuse_fence: vk::Fence,
|
||||
f: F,
|
||||
) {
|
||||
device
|
||||
.wait_for_fences(&[command_buffer_reuse_fence], true, std::u64::MAX)
|
||||
.expect("Wait for fence failed.");
|
||||
|
||||
device
|
||||
.reset_fences(&[command_buffer_reuse_fence])
|
||||
.expect("Reset fences failed.");
|
||||
|
||||
device
|
||||
.reset_command_buffer(
|
||||
command_buffer,
|
||||
vk::CommandBufferResetFlags::RELEASE_RESOURCES,
|
||||
)
|
||||
.expect("Reset command buffer failed.");
|
||||
|
||||
let command_buffer_begin_info = vk::CommandBufferBeginInfo::builder()
|
||||
.flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT)
|
||||
.build();
|
||||
|
||||
device
|
||||
.begin_command_buffer(command_buffer, &command_buffer_begin_info)
|
||||
.expect("Begin commandbuffer");
|
||||
f(device, command_buffer);
|
||||
}
|
||||
|
||||
pub(super) unsafe fn submit_commandbuffer(
|
||||
device: &Device,
|
||||
command_buffer: vk::CommandBuffer,
|
||||
command_buffer_reuse_fence: vk::Fence,
|
||||
submit_queue: vk::Queue,
|
||||
wait_mask: &[vk::PipelineStageFlags],
|
||||
wait_semaphores: &[vk::Semaphore],
|
||||
signal_semaphores: &[vk::Semaphore],
|
||||
) {
|
||||
device
|
||||
.end_command_buffer(command_buffer)
|
||||
.expect("End commandbuffer");
|
||||
|
||||
let command_buffers = vec![command_buffer];
|
||||
|
||||
let submit_info = vk::SubmitInfo::builder()
|
||||
.wait_semaphores(wait_semaphores)
|
||||
.wait_dst_stage_mask(wait_mask)
|
||||
.command_buffers(&command_buffers)
|
||||
.signal_semaphores(signal_semaphores)
|
||||
.build();
|
||||
|
||||
device
|
||||
.queue_submit(submit_queue, &[submit_info], command_buffer_reuse_fence)
|
||||
.expect("queue submit failed.");
|
||||
}
|
||||
|
||||
pub(super) fn find_memorytype_index(
|
||||
memory_req: &vk::MemoryRequirements,
|
||||
memory_prop: &vk::PhysicalDeviceMemoryProperties,
|
||||
flags: vk::MemoryPropertyFlags,
|
||||
) -> Option<u32> {
|
||||
memory_prop.memory_types[..memory_prop.memory_type_count as _]
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(index, memory_type)| {
|
||||
(1 << index) & memory_req.memory_type_bits != 0
|
||||
&& memory_type.property_flags & flags == flags
|
||||
})
|
||||
.map(|(index, _memory_type)| index as _)
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -8,6 +8,7 @@ use gilrs::{
|
|||
ff::{BaseEffect, BaseEffectType, EffectBuilder, Replay, Ticks},
|
||||
Button, Gilrs,
|
||||
};
|
||||
use raw_window_handle::HasRawDisplayHandle;
|
||||
use winit::{
|
||||
dpi::PhysicalSize,
|
||||
event::{Event, VirtualKeyCode, WindowEvent},
|
||||
|
@ -23,7 +24,15 @@ mod renderer;
|
|||
|
||||
use renderer::WindowData;
|
||||
|
||||
use self::renderer::WindowOptions;
|
||||
use self::renderer::{WindowDataManager, WindowOptions};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ResolutionData {
|
||||
real_width: u32,
|
||||
real_height: u32,
|
||||
scaled_width: u32,
|
||||
scaled_height: u32,
|
||||
}
|
||||
|
||||
pub struct WindowInfo {
|
||||
id: WindowId,
|
||||
|
@ -33,15 +42,22 @@ pub struct WindowInfo {
|
|||
pub struct WindowManager {
|
||||
event_loop: EventLoop<()>,
|
||||
windows: HashMap<WindowId, Arc<Mutex<WindowData>>>,
|
||||
window_data_manager: Arc<WindowDataManager>,
|
||||
input: Arc<Mutex<WinitInputHelper>>,
|
||||
sender: Sender<EmulatorMessage>,
|
||||
}
|
||||
|
||||
impl WindowManager {
|
||||
pub(crate) fn new(sender: Sender<EmulatorMessage>) -> Self {
|
||||
let event_loop = EventLoop::new();
|
||||
#[cfg(feature = "vulkan")]
|
||||
let window_data_manager = Arc::new(WindowDataManager::new(event_loop.raw_display_handle()));
|
||||
#[cfg(feature = "pixels")]
|
||||
let window_data_manager = Arc::new(WindowDataManager::new());
|
||||
Self {
|
||||
event_loop: EventLoop::new(),
|
||||
event_loop,
|
||||
windows: HashMap::new(),
|
||||
window_data_manager,
|
||||
input: Arc::new(Mutex::new(WinitInputHelper::new())),
|
||||
sender,
|
||||
}
|
||||
|
@ -53,6 +69,7 @@ impl WindowManager {
|
|||
gamepad_handler,
|
||||
self.input.clone(),
|
||||
&self.event_loop,
|
||||
self.window_data_manager.clone(),
|
||||
);
|
||||
self.windows.insert(info.id, info.data);
|
||||
r
|
||||
|
@ -95,7 +112,7 @@ pub struct WindowRenderer {
|
|||
width: usize,
|
||||
height: usize,
|
||||
factor: usize,
|
||||
real_factor: usize,
|
||||
real_factor: u32,
|
||||
gamepad_handler: Option<Gilrs>,
|
||||
joypad_state: JoypadState,
|
||||
current_rumble: bool,
|
||||
|
@ -107,6 +124,7 @@ impl WindowRenderer {
|
|||
gamepad_handler: Option<Gilrs>,
|
||||
input: Arc<Mutex<WinitInputHelper>>,
|
||||
event_loop: &EventLoop<()>,
|
||||
manager: Arc<WindowDataManager>,
|
||||
) -> (Self, WindowInfo) {
|
||||
let window = WindowBuilder::new()
|
||||
.with_title("Gameboy")
|
||||
|
@ -114,7 +132,14 @@ impl WindowRenderer {
|
|||
.build(event_loop)
|
||||
.unwrap();
|
||||
|
||||
let real_factor = (window.scale_factor() * factor as f64) as usize;
|
||||
let real_factor = (window.scale_factor() * factor as f64) as u32;
|
||||
let inner_size = window.inner_size();
|
||||
let resolutions = ResolutionData {
|
||||
real_width: inner_size.width,
|
||||
real_height: inner_size.height,
|
||||
scaled_width: inner_size.width / real_factor,
|
||||
scaled_height: inner_size.height / real_factor,
|
||||
};
|
||||
|
||||
let options = WindowOptions {
|
||||
shader_path: std::path::PathBuf::from(
|
||||
|
@ -123,9 +148,10 @@ impl WindowRenderer {
|
|||
};
|
||||
|
||||
let data = Arc::new(Mutex::new(WindowData::new(
|
||||
real_factor as u32,
|
||||
resolutions,
|
||||
&window,
|
||||
options,
|
||||
manager,
|
||||
)));
|
||||
let info = WindowInfo {
|
||||
id: window.id(),
|
||||
|
@ -154,20 +180,23 @@ impl Renderer<[u8; 4]> for WindowRenderer {
|
|||
fn prepare(&mut self, width: usize, height: usize) {
|
||||
self.width = width;
|
||||
self.height = height;
|
||||
self.real_factor = (self.window.scale_factor() * self.factor as f64) as usize;
|
||||
self.real_factor = (self.window.scale_factor() * self.factor as f64) as u32;
|
||||
|
||||
let w = (width * self.real_factor) as u32;
|
||||
let h = (height * self.real_factor) as u32;
|
||||
let real_width = (width as u32) * self.real_factor;
|
||||
let real_height = (height as u32) * self.real_factor;
|
||||
|
||||
self.window.set_inner_size(PhysicalSize::new(w, h));
|
||||
self.window
|
||||
.set_inner_size(PhysicalSize::new(real_width, real_height));
|
||||
|
||||
let resolutions = ResolutionData {
|
||||
real_width,
|
||||
real_height,
|
||||
scaled_width: width as u32,
|
||||
scaled_height: height as u32,
|
||||
};
|
||||
|
||||
if let Ok(mut data) = self.data.lock() {
|
||||
data.resize(
|
||||
width as u32,
|
||||
height as u32,
|
||||
self.real_factor as u32,
|
||||
&self.window,
|
||||
);
|
||||
data.resize(resolutions, &self.window);
|
||||
}
|
||||
self.window.request_redraw();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue