texture loading and depth buffer
This commit is contained in:
parent
0137d21406
commit
f6276bfdf6
14 changed files with 695 additions and 159 deletions
BIN
resources/texture.png
Normal file
BIN
resources/texture.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 350 KiB |
|
@ -1,3 +1,2 @@
|
||||||
C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/shader.vert -o shaders/vert.spv
|
C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/shader.vert -o shaders/vert.spv
|
||||||
C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/shader.frag -o shaders/frag.spv
|
C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/shader.frag -o shaders/frag.spv
|
||||||
pause
|
|
BIN
shaders/frag.spv
BIN
shaders/frag.spv
Binary file not shown.
|
@ -1,9 +1,11 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
layout(location = 0) in vec3 fragColor;
|
layout(location = 0) in vec3 fragColor;
|
||||||
|
layout(location = 1) in vec2 fragTexCoord;
|
||||||
|
|
||||||
layout(location = 0) out vec4 outColor;
|
layout(location = 0) out vec4 outColor;
|
||||||
|
layout(binding = 1) uniform sampler2D texSampler;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
outColor = vec4(fragColor, 1.0);
|
outColor = texture(texSampler, fragTexCoord);
|
||||||
}
|
}
|
|
@ -7,12 +7,15 @@ layout(binding = 0) uniform UniformBufferObject {
|
||||||
} ubo;
|
} ubo;
|
||||||
|
|
||||||
|
|
||||||
layout(location = 0) in vec2 inPosition;
|
layout(location = 0) in vec3 inPosition;
|
||||||
layout(location = 1) in vec3 inColor;
|
layout(location = 1) in vec3 inColor;
|
||||||
|
layout(location = 2) in vec2 inTexCoord;
|
||||||
|
|
||||||
layout(location = 0) out vec3 fragColor;
|
layout(location = 0) out vec3 fragColor;
|
||||||
|
layout(location = 1) out vec2 fragTexCoord;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0);
|
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0);
|
||||||
fragColor = inColor;
|
fragColor = inColor;
|
||||||
|
fragTexCoord = inTexCoord;
|
||||||
}
|
}
|
BIN
shaders/vert.spv
BIN
shaders/vert.spv
Binary file not shown.
|
@ -34,11 +34,19 @@ pub struct AppData {
|
||||||
|
|
||||||
pub index_buffer: vk::Buffer,
|
pub index_buffer: vk::Buffer,
|
||||||
pub index_buffer_memory: vk::DeviceMemory,
|
pub index_buffer_memory: vk::DeviceMemory,
|
||||||
|
|
||||||
|
|
||||||
pub uniform_buffers: Vec<vk::Buffer>,
|
pub uniform_buffers: Vec<vk::Buffer>,
|
||||||
pub uniform_buffers_memory: Vec<vk::DeviceMemory>,
|
pub uniform_buffers_memory: Vec<vk::DeviceMemory>,
|
||||||
|
|
||||||
pub descriptor_pool: vk::DescriptorPool,
|
pub descriptor_pool: vk::DescriptorPool,
|
||||||
pub descriptor_sets: Vec<vk::DescriptorSet>,
|
pub descriptor_sets: Vec<vk::DescriptorSet>,
|
||||||
|
|
||||||
|
pub texture_image: vk::Image,
|
||||||
|
pub texture_image_memory: vk::DeviceMemory,
|
||||||
|
pub texture_image_view: vk::ImageView,
|
||||||
|
pub texture_sampler: vk::Sampler,
|
||||||
|
|
||||||
|
pub depth_image: vk::Image,
|
||||||
|
pub depth_image_memory: vk::DeviceMemory,
|
||||||
|
pub depth_image_view: vk::ImageView,
|
||||||
}
|
}
|
|
@ -11,15 +11,25 @@ pub type Mat4 = cgmath::Matrix4<f32>;
|
||||||
|
|
||||||
use crate::app_data;
|
use crate::app_data;
|
||||||
use crate::vertex;
|
use crate::vertex;
|
||||||
|
use crate::command_buffer;
|
||||||
|
|
||||||
static VERTICES: [vertex::Vertex; 4] = [
|
static VERTICES: [vertex::Vertex; 8] = [
|
||||||
vertex::Vertex::new(vec2(-0.5, -0.5), vec3(1.0, 0.0, 0.0)),
|
vertex::Vertex::new(vec3(-0.5, -0.5, 0.0), vec3(1.0, 0.0, 0.0), vec2(1.0, 0.0)),
|
||||||
vertex::Vertex::new(vec2(0.5, -0.5), vec3(0.0, 1.0, 0.0)),
|
vertex::Vertex::new(vec3(0.5, -0.5, 0.0), vec3(0.0, 1.0, 0.0), vec2(0.0, 0.0)),
|
||||||
vertex::Vertex::new(vec2(0.5, 0.5), vec3(0.0, 0.0, 1.0)),
|
vertex::Vertex::new(vec3(0.5, 0.5, 0.0), vec3(0.0, 0.0, 1.0), vec2(0.0, 1.0)),
|
||||||
vertex::Vertex::new(vec2(-0.5, 0.5), vec3(1.0, 1.0, 1.0)),
|
vertex::Vertex::new(vec3(-0.5, 0.5, 0.0), vec3(1.0, 1.0, 1.0), vec2(1.0, 1.0)),
|
||||||
|
vertex::Vertex::new(vec3(-0.5, -0.5, -0.5), vec3(1.0, 0.0, 0.0), vec2(1.0, 0.0)),
|
||||||
|
vertex::Vertex::new(vec3(0.5, -0.5, -0.5), vec3(0.0, 1.0, 0.0), vec2(0.0, 0.0)),
|
||||||
|
vertex::Vertex::new(vec3(0.5, 0.5, -0.5), vec3(0.0, 0.0, 1.0), vec2(0.0, 1.0)),
|
||||||
|
vertex::Vertex::new(vec3(-0.5, 0.5, -0.5), vec3(1.0, 1.0, 1.0), vec2(1.0, 1.0)),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const INDICES: &[u16] = &[0, 1, 2, 2, 3, 0];
|
pub const INDICES: &[u16] = &[
|
||||||
|
0, 1, 2,
|
||||||
|
2, 3, 0,
|
||||||
|
4, 5, 6,
|
||||||
|
6, 7, 4,
|
||||||
|
];
|
||||||
|
|
||||||
pub unsafe fn create_buffer(
|
pub unsafe fn create_buffer(
|
||||||
instance: &Instance,
|
instance: &Instance,
|
||||||
|
@ -125,30 +135,12 @@ pub unsafe fn copy_buffer(
|
||||||
destination: vk::Buffer,
|
destination: vk::Buffer,
|
||||||
size: vk::DeviceSize,
|
size: vk::DeviceSize,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let info = vk::CommandBufferAllocateInfo::builder()
|
let command_buffer = command_buffer::begin_single_time_commands(device, data)?;
|
||||||
.level(vk::CommandBufferLevel::PRIMARY)
|
|
||||||
.command_pool(data.command_pool)
|
|
||||||
.command_buffer_count(1);
|
|
||||||
|
|
||||||
let command_buffer = device.allocate_command_buffers(&info)?[0];
|
|
||||||
|
|
||||||
let info = vk::CommandBufferBeginInfo::builder()
|
|
||||||
.flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT);
|
|
||||||
|
|
||||||
device.begin_command_buffer(command_buffer, &info)?;
|
|
||||||
let regions = vk::BufferCopy::builder().size(size);
|
let regions = vk::BufferCopy::builder().size(size);
|
||||||
device.cmd_copy_buffer(command_buffer, source, destination, &[regions]);
|
device.cmd_copy_buffer(command_buffer, source, destination, &[regions]);
|
||||||
|
|
||||||
device.end_command_buffer(command_buffer)?;
|
command_buffer::end_single_time_commands(device, data, command_buffer)?;
|
||||||
|
|
||||||
let command_buffers = &[command_buffer];
|
|
||||||
let info = vk::SubmitInfo::builder()
|
|
||||||
.command_buffers(command_buffers);
|
|
||||||
|
|
||||||
device.queue_submit(data.graphics_queue, &[info], vk::Fence::null())?;
|
|
||||||
device.queue_wait_idle(data.graphics_queue)?;
|
|
||||||
|
|
||||||
device.free_command_buffers(data.command_pool, &[command_buffer]);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -218,7 +210,13 @@ pub unsafe fn create_descriptor_set_layout(
|
||||||
.descriptor_count(1)
|
.descriptor_count(1)
|
||||||
.stage_flags(vk::ShaderStageFlags::VERTEX);
|
.stage_flags(vk::ShaderStageFlags::VERTEX);
|
||||||
|
|
||||||
let bindings = &[ubo_binding];
|
let sampler_binding = vk::DescriptorSetLayoutBinding::builder()
|
||||||
|
.binding(1)
|
||||||
|
.descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
|
||||||
|
.descriptor_count(1)
|
||||||
|
.stage_flags(vk::ShaderStageFlags::FRAGMENT);
|
||||||
|
|
||||||
|
let bindings = &[ubo_binding, sampler_binding];
|
||||||
let info = vk::DescriptorSetLayoutCreateInfo::builder()
|
let info = vk::DescriptorSetLayoutCreateInfo::builder()
|
||||||
.bindings(bindings);
|
.bindings(bindings);
|
||||||
|
|
||||||
|
@ -256,7 +254,12 @@ pub unsafe fn create_descriptor_pool(device: &Device, data: &mut app_data::AppDa
|
||||||
let ubo_size = vk::DescriptorPoolSize::builder()
|
let ubo_size = vk::DescriptorPoolSize::builder()
|
||||||
.type_(vk::DescriptorType::UNIFORM_BUFFER)
|
.type_(vk::DescriptorType::UNIFORM_BUFFER)
|
||||||
.descriptor_count(data.swapchain_images.len() as u32);
|
.descriptor_count(data.swapchain_images.len() as u32);
|
||||||
let pool_sizes = &[ubo_size];
|
|
||||||
|
let sampler_size = vk::DescriptorPoolSize::builder()
|
||||||
|
.type_(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
|
||||||
|
.descriptor_count(data.swapchain_images.len() as u32);
|
||||||
|
|
||||||
|
let pool_sizes = &[ubo_size, sampler_size];
|
||||||
let info = vk::DescriptorPoolCreateInfo::builder()
|
let info = vk::DescriptorPoolCreateInfo::builder()
|
||||||
.pool_sizes(pool_sizes)
|
.pool_sizes(pool_sizes)
|
||||||
.max_sets(data.swapchain_images.len() as u32);
|
.max_sets(data.swapchain_images.len() as u32);
|
||||||
|
@ -278,13 +281,31 @@ pub unsafe fn create_descriptor_sets(device: &Device, data: &mut app_data::AppDa
|
||||||
.offset(0)
|
.offset(0)
|
||||||
.range(size_of::<UniformBufferObject>() as u64);
|
.range(size_of::<UniformBufferObject>() as u64);
|
||||||
let buffer_info = &[info];
|
let buffer_info = &[info];
|
||||||
|
|
||||||
let ubo_write = vk::WriteDescriptorSet::builder()
|
let ubo_write = vk::WriteDescriptorSet::builder()
|
||||||
.dst_set(data.descriptor_sets[i])
|
.dst_set(data.descriptor_sets[i])
|
||||||
.dst_binding(0)
|
.dst_binding(0)
|
||||||
.dst_array_element(0)
|
.dst_array_element(0)
|
||||||
.descriptor_type(vk::DescriptorType::UNIFORM_BUFFER)
|
.descriptor_type(vk::DescriptorType::UNIFORM_BUFFER)
|
||||||
.buffer_info(buffer_info);
|
.buffer_info(buffer_info);
|
||||||
device.update_descriptor_sets(&[ubo_write], &[] as &[vk::CopyDescriptorSet]);
|
|
||||||
|
let info = vk::DescriptorImageInfo::builder()
|
||||||
|
.image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)
|
||||||
|
.image_view(data.texture_image_view)
|
||||||
|
.sampler(data.texture_sampler);
|
||||||
|
|
||||||
|
let image_info = &[info];
|
||||||
|
let sampler_write = vk::WriteDescriptorSet::builder()
|
||||||
|
.dst_set(data.descriptor_sets[i])
|
||||||
|
.dst_binding(1)
|
||||||
|
.dst_array_element(0)
|
||||||
|
.descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
|
||||||
|
.image_info(image_info);
|
||||||
|
|
||||||
|
device.update_descriptor_sets(
|
||||||
|
&[ubo_write, sampler_write],
|
||||||
|
&[] as &[vk::CopyDescriptorSet],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
131
src/command_buffer.rs
Normal file
131
src/command_buffer.rs
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use vulkanalia::prelude::v1_0::*;
|
||||||
|
|
||||||
|
|
||||||
|
use crate::app_data;
|
||||||
|
use crate::buffer;
|
||||||
|
use crate::queue_family_indices;
|
||||||
|
|
||||||
|
pub unsafe fn create_command_pool(
|
||||||
|
instance: &Instance,
|
||||||
|
device: &Device,
|
||||||
|
data: &mut app_data::AppData,
|
||||||
|
) -> Result<()> {
|
||||||
|
let indices = queue_family_indices::QueueFamilyIndices::get(instance, data, data.physical_device)?;
|
||||||
|
|
||||||
|
let info = vk::CommandPoolCreateInfo::builder()
|
||||||
|
.flags(vk::CommandPoolCreateFlags::empty()) // Optional.
|
||||||
|
.queue_family_index(indices.graphics);
|
||||||
|
|
||||||
|
data.command_pool = device.create_command_pool(&info, None)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn create_command_buffers(device: &Device, data: &mut app_data::AppData) -> Result<()> {
|
||||||
|
let allocate_info = vk::CommandBufferAllocateInfo::builder()
|
||||||
|
.command_pool(data.command_pool)
|
||||||
|
.level(vk::CommandBufferLevel::PRIMARY)
|
||||||
|
.command_buffer_count(data.framebuffers.len() as u32);
|
||||||
|
|
||||||
|
data.command_buffers = device.allocate_command_buffers(&allocate_info)?;
|
||||||
|
|
||||||
|
for (i, command_buffer) in data.command_buffers.iter().enumerate() {
|
||||||
|
let inheritance = vk::CommandBufferInheritanceInfo::builder();
|
||||||
|
|
||||||
|
let info = vk::CommandBufferBeginInfo::builder()
|
||||||
|
.flags(vk::CommandBufferUsageFlags::empty()) // Optional.
|
||||||
|
.inheritance_info(&inheritance); // Optional.
|
||||||
|
|
||||||
|
device.begin_command_buffer(*command_buffer, &info)?;
|
||||||
|
|
||||||
|
let render_area = vk::Rect2D::builder()
|
||||||
|
.offset(vk::Offset2D::default())
|
||||||
|
.extent(data.swapchain_extent);
|
||||||
|
|
||||||
|
let color_clear_value = vk::ClearValue {
|
||||||
|
color: vk::ClearColorValue {
|
||||||
|
float32: [0.0, 0.0, 0.0, 1.0],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let depth_clear_value = vk::ClearValue {
|
||||||
|
depth_stencil: vk::ClearDepthStencilValue {
|
||||||
|
depth: 1.0,
|
||||||
|
stencil: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let clear_values = &[color_clear_value, depth_clear_value];
|
||||||
|
let info = vk::RenderPassBeginInfo::builder()
|
||||||
|
.render_pass(data.render_pass)
|
||||||
|
.framebuffer(data.framebuffers[i])
|
||||||
|
.render_area(render_area)
|
||||||
|
.clear_values(clear_values);
|
||||||
|
|
||||||
|
device.cmd_begin_render_pass(
|
||||||
|
*command_buffer, &info, vk::SubpassContents::INLINE);
|
||||||
|
|
||||||
|
device.cmd_bind_pipeline(
|
||||||
|
*command_buffer, vk::PipelineBindPoint::GRAPHICS, data.pipeline);
|
||||||
|
|
||||||
|
device.cmd_bind_vertex_buffers(*command_buffer, 0, &[data.vertex_buffer], &[0]);
|
||||||
|
device.cmd_bind_index_buffer(*command_buffer, data.index_buffer, 0, vk::IndexType::UINT16);
|
||||||
|
|
||||||
|
device.cmd_bind_descriptor_sets(
|
||||||
|
*command_buffer,
|
||||||
|
vk::PipelineBindPoint::GRAPHICS,
|
||||||
|
data.pipeline_layout,
|
||||||
|
0,
|
||||||
|
&[data.descriptor_sets[i]],
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
|
||||||
|
device.cmd_draw_indexed(*command_buffer, buffer::INDICES.len() as u32, 1, 0, 0, 0);
|
||||||
|
|
||||||
|
device.cmd_end_render_pass(*command_buffer);
|
||||||
|
|
||||||
|
device.end_command_buffer(*command_buffer)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn begin_single_time_commands(
|
||||||
|
device: &Device,
|
||||||
|
data: &app_data::AppData,
|
||||||
|
) -> Result<vk::CommandBuffer> {
|
||||||
|
let info = vk::CommandBufferAllocateInfo::builder()
|
||||||
|
.level(vk::CommandBufferLevel::PRIMARY)
|
||||||
|
.command_pool(data.command_pool)
|
||||||
|
.command_buffer_count(1);
|
||||||
|
|
||||||
|
let command_buffer = device.allocate_command_buffers(&info)?[0];
|
||||||
|
|
||||||
|
let info = vk::CommandBufferBeginInfo::builder()
|
||||||
|
.flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT);
|
||||||
|
|
||||||
|
device.begin_command_buffer(command_buffer, &info)?;
|
||||||
|
|
||||||
|
Ok(command_buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn end_single_time_commands(
|
||||||
|
device: &Device,
|
||||||
|
data: &app_data::AppData,
|
||||||
|
command_buffer: vk::CommandBuffer,
|
||||||
|
) -> Result<()> {
|
||||||
|
device.end_command_buffer(command_buffer)?;
|
||||||
|
|
||||||
|
let command_buffers = &[command_buffer];
|
||||||
|
let info = vk::SubmitInfo::builder()
|
||||||
|
.command_buffers(command_buffers);
|
||||||
|
|
||||||
|
device.queue_submit(data.graphics_queue, &[info], vk::Fence::null())?;
|
||||||
|
device.queue_wait_idle(data.graphics_queue)?;
|
||||||
|
|
||||||
|
device.free_command_buffers(data.command_pool, &[command_buffer]);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
82
src/depth_buffer.rs
Normal file
82
src/depth_buffer.rs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use vulkanalia::prelude::v1_0::*;
|
||||||
|
|
||||||
|
use crate::app_data;
|
||||||
|
use crate::image;
|
||||||
|
|
||||||
|
pub unsafe fn create_depth_objects(
|
||||||
|
instance: &Instance,
|
||||||
|
device: &Device,
|
||||||
|
data: &mut app_data::AppData,
|
||||||
|
) -> Result<()> {
|
||||||
|
let format = get_depth_format(instance, data)?;
|
||||||
|
let (depth_image, depth_image_memory) = image::create_image(
|
||||||
|
instance,
|
||||||
|
device,
|
||||||
|
data,
|
||||||
|
data.swapchain_extent.width,
|
||||||
|
data.swapchain_extent.height,
|
||||||
|
format,
|
||||||
|
vk::ImageTiling::OPTIMAL,
|
||||||
|
vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT,
|
||||||
|
vk::MemoryPropertyFlags::DEVICE_LOCAL,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
data.depth_image = depth_image;
|
||||||
|
data.depth_image_memory = depth_image_memory;
|
||||||
|
|
||||||
|
// Image View
|
||||||
|
|
||||||
|
data.depth_image_view = image::create_image_view(device, data.depth_image, format, vk::ImageAspectFlags::DEPTH)?;
|
||||||
|
|
||||||
|
image::transition_image_layout(
|
||||||
|
device,
|
||||||
|
data,
|
||||||
|
data.depth_image,
|
||||||
|
format,
|
||||||
|
vk::ImageLayout::UNDEFINED,
|
||||||
|
vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get_supported_format(
|
||||||
|
instance: &Instance,
|
||||||
|
data: &app_data::AppData,
|
||||||
|
candidates: &[vk::Format],
|
||||||
|
tiling: vk::ImageTiling,
|
||||||
|
features: vk::FormatFeatureFlags,
|
||||||
|
) -> Result<vk::Format> {
|
||||||
|
candidates
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.find(|f| {
|
||||||
|
let properties = instance.get_physical_device_format_properties(
|
||||||
|
data.physical_device,
|
||||||
|
*f,
|
||||||
|
);
|
||||||
|
match tiling {
|
||||||
|
vk::ImageTiling::LINEAR => properties.linear_tiling_features.contains(features),
|
||||||
|
vk::ImageTiling::OPTIMAL => properties.optimal_tiling_features.contains(features),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ok_or_else(|| anyhow!("Failed to find supported format!"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_depth_format(instance: &Instance, data: &app_data::AppData) -> Result<vk::Format> {
|
||||||
|
let candidates = &[
|
||||||
|
vk::Format::D32_SFLOAT,
|
||||||
|
vk::Format::D32_SFLOAT_S8_UINT,
|
||||||
|
vk::Format::D24_UNORM_S8_UINT,
|
||||||
|
];
|
||||||
|
|
||||||
|
get_supported_format(
|
||||||
|
instance,
|
||||||
|
data,
|
||||||
|
candidates,
|
||||||
|
vk::ImageTiling::OPTIMAL,
|
||||||
|
vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT,
|
||||||
|
)
|
||||||
|
}
|
317
src/image.rs
Normal file
317
src/image.rs
Normal file
|
@ -0,0 +1,317 @@
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
|
||||||
|
use vulkanalia::prelude::v1_0::*;
|
||||||
|
|
||||||
|
use std::ptr::copy_nonoverlapping as memcpy;
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
|
||||||
|
pub type Mat4 = cgmath::Matrix4<f32>;
|
||||||
|
|
||||||
|
use crate::app_data;
|
||||||
|
use crate::buffer;
|
||||||
|
use crate::command_buffer;
|
||||||
|
|
||||||
|
|
||||||
|
pub unsafe fn create_texture_image(
|
||||||
|
instance: &Instance,
|
||||||
|
device: &Device,
|
||||||
|
data: &mut app_data::AppData,
|
||||||
|
) -> Result<()> {
|
||||||
|
let image = File::open("resources/texture.png")?;
|
||||||
|
|
||||||
|
let decoder = png::Decoder::new(image);
|
||||||
|
let mut reader = decoder.read_info()?;
|
||||||
|
|
||||||
|
let mut pixels = vec![0; reader.info().raw_bytes()];
|
||||||
|
reader.next_frame(&mut pixels)?;
|
||||||
|
|
||||||
|
let size = reader.info().raw_bytes() as u64;
|
||||||
|
let (width, height) = reader.info().size();
|
||||||
|
|
||||||
|
let (staging_buffer, staging_buffer_memory) = buffer::create_buffer(
|
||||||
|
instance,
|
||||||
|
device,
|
||||||
|
data,
|
||||||
|
size,
|
||||||
|
vk::BufferUsageFlags::TRANSFER_SRC,
|
||||||
|
vk::MemoryPropertyFlags::HOST_COHERENT | vk::MemoryPropertyFlags::HOST_VISIBLE,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let memory = device.map_memory(
|
||||||
|
staging_buffer_memory,
|
||||||
|
0,
|
||||||
|
size,
|
||||||
|
vk::MemoryMapFlags::empty(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
memcpy(pixels.as_ptr(), memory.cast(), pixels.len());
|
||||||
|
|
||||||
|
device.unmap_memory(staging_buffer_memory);
|
||||||
|
|
||||||
|
let (texture_image, texture_image_memory) = create_image(
|
||||||
|
instance,
|
||||||
|
device,
|
||||||
|
data,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
vk::Format::R8G8B8A8_SRGB,
|
||||||
|
vk::ImageTiling::OPTIMAL,
|
||||||
|
vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::TRANSFER_DST,
|
||||||
|
vk::MemoryPropertyFlags::DEVICE_LOCAL,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
data.texture_image = texture_image;
|
||||||
|
data.texture_image_memory = texture_image_memory;
|
||||||
|
|
||||||
|
transition_image_layout(
|
||||||
|
device,
|
||||||
|
data,
|
||||||
|
data.texture_image,
|
||||||
|
vk::Format::R8G8B8A8_SRGB,
|
||||||
|
vk::ImageLayout::UNDEFINED,
|
||||||
|
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
copy_buffer_to_image(
|
||||||
|
device,
|
||||||
|
data,
|
||||||
|
staging_buffer,
|
||||||
|
data.texture_image,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
transition_image_layout(
|
||||||
|
device,
|
||||||
|
data,
|
||||||
|
data.texture_image,
|
||||||
|
vk::Format::R8G8B8A8_SRGB,
|
||||||
|
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||||
|
vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
device.destroy_buffer(staging_buffer, None);
|
||||||
|
device.free_memory(staging_buffer_memory, None);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn create_image(
|
||||||
|
instance: &Instance,
|
||||||
|
device: &Device,
|
||||||
|
data: &app_data::AppData,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
format: vk::Format,
|
||||||
|
tiling: vk::ImageTiling,
|
||||||
|
usage: vk::ImageUsageFlags,
|
||||||
|
properties: vk::MemoryPropertyFlags,
|
||||||
|
) -> Result<(vk::Image, vk::DeviceMemory)> {
|
||||||
|
let info = vk::ImageCreateInfo::builder()
|
||||||
|
.image_type(vk::ImageType::_2D)
|
||||||
|
.extent(vk::Extent3D {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
depth: 1,
|
||||||
|
})
|
||||||
|
.mip_levels(1)
|
||||||
|
.array_layers(1)
|
||||||
|
.format(format)
|
||||||
|
.tiling(tiling)
|
||||||
|
.initial_layout(vk::ImageLayout::UNDEFINED)
|
||||||
|
.usage(usage)
|
||||||
|
.samples(vk::SampleCountFlags::_1)
|
||||||
|
.sharing_mode(vk::SharingMode::EXCLUSIVE);
|
||||||
|
|
||||||
|
let image = device.create_image(&info, None)?;
|
||||||
|
|
||||||
|
let requirements = device.get_image_memory_requirements(image);
|
||||||
|
|
||||||
|
let info = vk::MemoryAllocateInfo::builder()
|
||||||
|
.allocation_size(requirements.size)
|
||||||
|
.memory_type_index(buffer::get_memory_type_index(
|
||||||
|
instance,
|
||||||
|
data,
|
||||||
|
properties,
|
||||||
|
requirements,
|
||||||
|
)?);
|
||||||
|
|
||||||
|
let image_memory = device.allocate_memory(&info, None)?;
|
||||||
|
|
||||||
|
device.bind_image_memory(image, image_memory, 0)?;
|
||||||
|
|
||||||
|
Ok((image, image_memory))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn transition_image_layout(
|
||||||
|
device: &Device,
|
||||||
|
data: &app_data::AppData,
|
||||||
|
image: vk::Image,
|
||||||
|
format: vk::Format,
|
||||||
|
old_layout: vk::ImageLayout,
|
||||||
|
new_layout: vk::ImageLayout,
|
||||||
|
) -> Result<()> {
|
||||||
|
let command_buffer = command_buffer::begin_single_time_commands(device, data)?;
|
||||||
|
|
||||||
|
let (
|
||||||
|
src_access_mask,
|
||||||
|
dst_access_mask,
|
||||||
|
src_stage_mask,
|
||||||
|
dst_stage_mask,
|
||||||
|
) = match (old_layout, new_layout) {
|
||||||
|
(vk::ImageLayout::UNDEFINED, vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL) => (
|
||||||
|
vk::AccessFlags::empty(),
|
||||||
|
vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ | vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE,
|
||||||
|
vk::PipelineStageFlags::TOP_OF_PIPE,
|
||||||
|
vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS,
|
||||||
|
),
|
||||||
|
(vk::ImageLayout::UNDEFINED, vk::ImageLayout::TRANSFER_DST_OPTIMAL) => (
|
||||||
|
vk::AccessFlags::empty(),
|
||||||
|
vk::AccessFlags::TRANSFER_WRITE,
|
||||||
|
vk::PipelineStageFlags::TOP_OF_PIPE,
|
||||||
|
vk::PipelineStageFlags::TRANSFER,
|
||||||
|
),
|
||||||
|
(vk::ImageLayout::TRANSFER_DST_OPTIMAL, vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) => (
|
||||||
|
vk::AccessFlags::TRANSFER_WRITE,
|
||||||
|
vk::AccessFlags::SHADER_READ,
|
||||||
|
vk::PipelineStageFlags::TRANSFER,
|
||||||
|
vk::PipelineStageFlags::FRAGMENT_SHADER,
|
||||||
|
),
|
||||||
|
_ => return Err(anyhow!("Unsupported image layout transition!")),
|
||||||
|
};
|
||||||
|
|
||||||
|
let aspect_mask = if new_layout == vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL {
|
||||||
|
match format {
|
||||||
|
vk::Format::D32_SFLOAT_S8_UINT | vk::Format::D24_UNORM_S8_UINT =>
|
||||||
|
vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL,
|
||||||
|
_ => vk::ImageAspectFlags::DEPTH
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vk::ImageAspectFlags::COLOR
|
||||||
|
};
|
||||||
|
|
||||||
|
let subresource = vk::ImageSubresourceRange::builder()
|
||||||
|
.aspect_mask(aspect_mask)
|
||||||
|
.base_mip_level(0)
|
||||||
|
.level_count(1)
|
||||||
|
.base_array_layer(0)
|
||||||
|
.layer_count(1);
|
||||||
|
|
||||||
|
let barrier = vk::ImageMemoryBarrier::builder()
|
||||||
|
.old_layout(old_layout)
|
||||||
|
.new_layout(new_layout)
|
||||||
|
.src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
|
||||||
|
.dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
|
||||||
|
.image(image)
|
||||||
|
.subresource_range(subresource)
|
||||||
|
.src_access_mask(src_access_mask)
|
||||||
|
.dst_access_mask(dst_access_mask);
|
||||||
|
|
||||||
|
device.cmd_pipeline_barrier(
|
||||||
|
command_buffer,
|
||||||
|
src_stage_mask,
|
||||||
|
dst_stage_mask,
|
||||||
|
vk::DependencyFlags::empty(),
|
||||||
|
&[] as &[vk::MemoryBarrier],
|
||||||
|
&[] as &[vk::BufferMemoryBarrier],
|
||||||
|
&[barrier],
|
||||||
|
);
|
||||||
|
|
||||||
|
command_buffer::end_single_time_commands(device, data, command_buffer)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn copy_buffer_to_image(
|
||||||
|
device: &Device,
|
||||||
|
data: &app_data::AppData,
|
||||||
|
buffer: vk::Buffer,
|
||||||
|
image: vk::Image,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
) -> Result<()> {
|
||||||
|
let command_buffer = command_buffer::begin_single_time_commands(device, data)?;
|
||||||
|
|
||||||
|
let subresource = vk::ImageSubresourceLayers::builder()
|
||||||
|
.aspect_mask(vk::ImageAspectFlags::COLOR)
|
||||||
|
.mip_level(0)
|
||||||
|
.base_array_layer(0)
|
||||||
|
.layer_count(1);
|
||||||
|
|
||||||
|
let region = vk::BufferImageCopy::builder()
|
||||||
|
.buffer_offset(0)
|
||||||
|
.buffer_row_length(0)
|
||||||
|
.buffer_image_height(0)
|
||||||
|
.image_subresource(subresource)
|
||||||
|
.image_offset(vk::Offset3D { x: 0, y: 0, z: 0 })
|
||||||
|
.image_extent(vk::Extent3D { width, height, depth: 1 });
|
||||||
|
|
||||||
|
device.cmd_copy_buffer_to_image(
|
||||||
|
command_buffer,
|
||||||
|
buffer,
|
||||||
|
image,
|
||||||
|
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||||
|
&[region],
|
||||||
|
);
|
||||||
|
|
||||||
|
command_buffer::end_single_time_commands(device, data, command_buffer)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn create_image_view(
|
||||||
|
device: &Device,
|
||||||
|
image: vk::Image,
|
||||||
|
format: vk::Format,
|
||||||
|
aspects: vk::ImageAspectFlags,
|
||||||
|
) -> Result<vk::ImageView> {
|
||||||
|
let subresource_range = vk::ImageSubresourceRange::builder()
|
||||||
|
.aspect_mask(aspects)
|
||||||
|
.base_mip_level(0)
|
||||||
|
.level_count(1)
|
||||||
|
.base_array_layer(0)
|
||||||
|
.layer_count(1);
|
||||||
|
|
||||||
|
let info = vk::ImageViewCreateInfo::builder()
|
||||||
|
.image(image)
|
||||||
|
.view_type(vk::ImageViewType::_2D)
|
||||||
|
.format(format)
|
||||||
|
.subresource_range(subresource_range);
|
||||||
|
|
||||||
|
Ok(device.create_image_view(&info, None)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn create_texture_image_view(device: &Device, data: &mut app_data::AppData) -> Result<()> {
|
||||||
|
data.texture_image_view = create_image_view(
|
||||||
|
device,
|
||||||
|
data.texture_image,
|
||||||
|
vk::Format::R8G8B8A8_SRGB,
|
||||||
|
vk::ImageAspectFlags::COLOR
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub unsafe fn create_texture_sampler(device: &Device, data: &mut app_data::AppData) -> Result<()> {
|
||||||
|
let info = vk::SamplerCreateInfo::builder()
|
||||||
|
.mag_filter(vk::Filter::LINEAR)
|
||||||
|
.min_filter(vk::Filter::LINEAR)
|
||||||
|
.address_mode_u(vk::SamplerAddressMode::REPEAT)
|
||||||
|
.address_mode_v(vk::SamplerAddressMode::REPEAT)
|
||||||
|
.address_mode_w(vk::SamplerAddressMode::REPEAT)
|
||||||
|
.anisotropy_enable(true)
|
||||||
|
.max_anisotropy(16.0)
|
||||||
|
.border_color(vk::BorderColor::INT_OPAQUE_BLACK)
|
||||||
|
.unnormalized_coordinates(false)
|
||||||
|
.compare_enable(false)
|
||||||
|
.compare_op(vk::CompareOp::ALWAYS)
|
||||||
|
.mipmap_mode(vk::SamplerMipmapMode::LINEAR)
|
||||||
|
.mip_lod_bias(0.0)
|
||||||
|
.min_lod(0.0)
|
||||||
|
.max_lod(0.0);
|
||||||
|
|
||||||
|
data.texture_sampler = device.create_sampler(&info, None)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
179
src/main.rs
179
src/main.rs
|
@ -27,7 +27,7 @@ use vulkanalia::vk::ExtDebugUtilsExtension;
|
||||||
use vulkanalia::vk::KhrSurfaceExtension;
|
use vulkanalia::vk::KhrSurfaceExtension;
|
||||||
use vulkanalia::vk::KhrSwapchainExtension;
|
use vulkanalia::vk::KhrSwapchainExtension;
|
||||||
|
|
||||||
use cgmath::{vec2, vec3};
|
use cgmath::vec3;
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
use std::ptr::copy_nonoverlapping as memcpy;
|
use std::ptr::copy_nonoverlapping as memcpy;
|
||||||
|
|
||||||
|
@ -39,6 +39,9 @@ pub mod swapchain;
|
||||||
pub mod queue_family_indices;
|
pub mod queue_family_indices;
|
||||||
pub mod vertex;
|
pub mod vertex;
|
||||||
pub mod buffer;
|
pub mod buffer;
|
||||||
|
pub mod image;
|
||||||
|
pub mod command_buffer;
|
||||||
|
pub mod depth_buffer;
|
||||||
|
|
||||||
const PORTABILITY_MACOS_VERSION: Version = Version::new(1, 3, 216);
|
const PORTABILITY_MACOS_VERSION: Version = Version::new(1, 3, 216);
|
||||||
const VALIDATION_ENABLED: bool =
|
const VALIDATION_ENABLED: bool =
|
||||||
|
@ -123,10 +126,16 @@ impl App {
|
||||||
|
|
||||||
buffer::create_descriptor_set_layout(&device, &mut data)?;
|
buffer::create_descriptor_set_layout(&device, &mut data)?;
|
||||||
create_pipeline(&device, &mut data)?;
|
create_pipeline(&device, &mut data)?;
|
||||||
|
|
||||||
|
command_buffer::create_command_pool(&instance, &device, &mut data)?;
|
||||||
|
|
||||||
|
depth_buffer::create_depth_objects(&instance, &device, &mut data)?;
|
||||||
create_framebuffers(&device, &mut data)?;
|
create_framebuffers(&device, &mut data)?;
|
||||||
|
|
||||||
create_command_pool(&instance, &device, &mut data)?;
|
|
||||||
|
image::create_texture_image(&instance, &device, &mut data)?;
|
||||||
|
image::create_texture_image_view(&device, &mut data)?;
|
||||||
|
image::create_texture_sampler(&device, &mut data)?;
|
||||||
|
|
||||||
buffer::create_vertex_buffer(&instance, &device, &mut data)?;
|
buffer::create_vertex_buffer(&instance, &device, &mut data)?;
|
||||||
buffer::create_index_buffer(&instance, &device, &mut data)?;
|
buffer::create_index_buffer(&instance, &device, &mut data)?;
|
||||||
|
@ -135,7 +144,7 @@ impl App {
|
||||||
buffer::create_descriptor_pool(&device, &mut data)?;
|
buffer::create_descriptor_pool(&device, &mut data)?;
|
||||||
buffer::create_descriptor_sets(&device, &mut data)?;
|
buffer::create_descriptor_sets(&device, &mut data)?;
|
||||||
|
|
||||||
create_command_buffers(&device, &mut data)?;
|
command_buffer::create_command_buffers(&device, &mut data)?;
|
||||||
|
|
||||||
create_sync_objects(&device, &mut data)?;
|
create_sync_objects(&device, &mut data)?;
|
||||||
|
|
||||||
|
@ -210,6 +219,13 @@ impl App {
|
||||||
unsafe fn destroy(&mut self) {
|
unsafe fn destroy(&mut self) {
|
||||||
self.destroy_swapchain();
|
self.destroy_swapchain();
|
||||||
|
|
||||||
|
self.device.destroy_sampler(self.data.texture_sampler, None);
|
||||||
|
|
||||||
|
self.device.destroy_image_view(self.data.texture_image_view, None);
|
||||||
|
|
||||||
|
self.device.destroy_image(self.data.texture_image, None);
|
||||||
|
self.device.free_memory(self.data.texture_image_memory, None);
|
||||||
|
|
||||||
self.device.destroy_descriptor_set_layout(self.data.descriptor_set_layout, None);
|
self.device.destroy_descriptor_set_layout(self.data.descriptor_set_layout, None);
|
||||||
|
|
||||||
self.device.destroy_buffer(self.data.index_buffer, None);
|
self.device.destroy_buffer(self.data.index_buffer, None);
|
||||||
|
@ -245,11 +261,12 @@ impl App {
|
||||||
swapchain::create_swapchain_image_views(&self.device, &mut self.data)?;
|
swapchain::create_swapchain_image_views(&self.device, &mut self.data)?;
|
||||||
create_render_pass(&self.instance, &self.device, &mut self.data)?;
|
create_render_pass(&self.instance, &self.device, &mut self.data)?;
|
||||||
create_pipeline(&self.device, &mut self.data)?;
|
create_pipeline(&self.device, &mut self.data)?;
|
||||||
|
buffer::create_descriptor_pool(&self.device, &mut self.data)?;
|
||||||
|
depth_buffer::create_depth_objects(&self.instance, &self.device, &mut self.data)?;
|
||||||
create_framebuffers(&self.device, &mut self.data)?;
|
create_framebuffers(&self.device, &mut self.data)?;
|
||||||
buffer::create_uniform_buffers(&self.instance, &self.device, &mut self.data)?;
|
buffer::create_uniform_buffers(&self.instance, &self.device, &mut self.data)?;
|
||||||
buffer::create_descriptor_pool(&self.device, &mut self.data)?;
|
|
||||||
buffer::create_descriptor_sets(&self.device, &mut self.data)?;
|
buffer::create_descriptor_sets(&self.device, &mut self.data)?;
|
||||||
create_command_buffers(&self.device, &mut self.data)?;
|
command_buffer::create_command_buffers(&self.device, &mut self.data)?;
|
||||||
self.data
|
self.data
|
||||||
.images_in_flight
|
.images_in_flight
|
||||||
.resize(self.data.swapchain_images.len(), vk::Fence::null());
|
.resize(self.data.swapchain_images.len(), vk::Fence::null());
|
||||||
|
@ -257,6 +274,11 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn destroy_swapchain(&mut self) {
|
unsafe fn destroy_swapchain(&mut self) {
|
||||||
|
self.device.destroy_image_view(self.data.depth_image_view, None);
|
||||||
|
|
||||||
|
self.device.destroy_image(self.data.depth_image, None);
|
||||||
|
self.device.free_memory(self.data.depth_image_memory, None);
|
||||||
|
|
||||||
self.device.destroy_descriptor_pool(self.data.descriptor_pool, None);
|
self.device.destroy_descriptor_pool(self.data.descriptor_pool, None);
|
||||||
self.data.uniform_buffers
|
self.data.uniform_buffers
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -292,14 +314,21 @@ impl App {
|
||||||
vec3(0.0, 0.0, 1.0),
|
vec3(0.0, 0.0, 1.0),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut proj = cgmath::perspective(
|
let correction = buffer::Mat4::new( //column major order, matrix looks transposed
|
||||||
cgmath::Deg(45.0),
|
1.0, 0.0, 0.0, 0.0,
|
||||||
self.data.swapchain_extent.width as f32 / self.data.swapchain_extent.height as f32,
|
// We're also flipping the Y-axis with this line's `-1.0`.
|
||||||
0.1,
|
0.0, -1.0, 0.0, 0.0,
|
||||||
10.0,
|
0.0, 0.0, 1.0 / 2.0, 0.0,
|
||||||
|
0.0, 0.0, 1.0 / 2.0, 1.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
proj[1][1] *= -1.0;
|
let proj = correction
|
||||||
|
* cgmath::perspective(
|
||||||
|
cgmath::Deg(45.0),
|
||||||
|
self.data.swapchain_extent.width as f32 / self.data.swapchain_extent.height as f32,
|
||||||
|
0.1,
|
||||||
|
10.0,
|
||||||
|
);
|
||||||
|
|
||||||
let ubo = buffer::UniformBufferObject { model, view, proj };
|
let ubo = buffer::UniformBufferObject { model, view, proj };
|
||||||
|
|
||||||
|
@ -447,6 +476,9 @@ unsafe fn check_physical_device(
|
||||||
if features.geometry_shader != vk::TRUE {
|
if features.geometry_shader != vk::TRUE {
|
||||||
return Err(anyhow!(errors::SuitabilityError("Missing geometry shader support.")));
|
return Err(anyhow!(errors::SuitabilityError("Missing geometry shader support.")));
|
||||||
}
|
}
|
||||||
|
if features.sampler_anisotropy != vk::TRUE {
|
||||||
|
return Err(anyhow!(errors::SuitabilityError("No sampler anisotropy.")));
|
||||||
|
}
|
||||||
|
|
||||||
queue_family_indices::QueueFamilyIndices::get(instance, data, physical_device)?;
|
queue_family_indices::QueueFamilyIndices::get(instance, data, physical_device)?;
|
||||||
check_physical_device_extensions(instance, physical_device)?;
|
check_physical_device_extensions(instance, physical_device)?;
|
||||||
|
@ -504,7 +536,8 @@ unsafe fn create_logical_device(
|
||||||
extensions.push(vk::KHR_PORTABILITY_SUBSET_EXTENSION.name.as_ptr());
|
extensions.push(vk::KHR_PORTABILITY_SUBSET_EXTENSION.name.as_ptr());
|
||||||
};
|
};
|
||||||
|
|
||||||
let features = vk::PhysicalDeviceFeatures::builder();
|
let features = vk::PhysicalDeviceFeatures::builder()
|
||||||
|
.sampler_anisotropy(true);
|
||||||
|
|
||||||
let indices = queue_family_indices::QueueFamilyIndices::get(instance, data, data.physical_device)?;
|
let indices = queue_family_indices::QueueFamilyIndices::get(instance, data, data.physical_device)?;
|
||||||
|
|
||||||
|
@ -594,6 +627,15 @@ unsafe fn create_pipeline(device: &Device, data: &mut app_data::AppData) -> Resu
|
||||||
.sample_shading_enable(false)
|
.sample_shading_enable(false)
|
||||||
.rasterization_samples(vk::SampleCountFlags::_1);
|
.rasterization_samples(vk::SampleCountFlags::_1);
|
||||||
|
|
||||||
|
let depth_stencil_state = vk::PipelineDepthStencilStateCreateInfo::builder()
|
||||||
|
.depth_test_enable(true)
|
||||||
|
.depth_write_enable(true)
|
||||||
|
.depth_compare_op(vk::CompareOp::LESS)
|
||||||
|
.depth_bounds_test_enable(false)
|
||||||
|
.min_depth_bounds(0.0) // Optional.
|
||||||
|
.max_depth_bounds(1.0) // Optional.
|
||||||
|
.stencil_test_enable(false);
|
||||||
|
|
||||||
let attachment = vk::PipelineColorBlendAttachmentState::builder()
|
let attachment = vk::PipelineColorBlendAttachmentState::builder()
|
||||||
.color_write_mask(vk::ColorComponentFlags::all())
|
.color_write_mask(vk::ColorComponentFlags::all())
|
||||||
.blend_enable(false)
|
.blend_enable(false)
|
||||||
|
@ -625,6 +667,7 @@ unsafe fn create_pipeline(device: &Device, data: &mut app_data::AppData) -> Resu
|
||||||
.viewport_state(&viewport_state)
|
.viewport_state(&viewport_state)
|
||||||
.rasterization_state(&rasterization_state)
|
.rasterization_state(&rasterization_state)
|
||||||
.multisample_state(&multisample_state)
|
.multisample_state(&multisample_state)
|
||||||
|
.depth_stencil_state(&depth_stencil_state)
|
||||||
.color_blend_state(&color_blend_state)
|
.color_blend_state(&color_blend_state)
|
||||||
.layout(data.pipeline_layout)
|
.layout(data.pipeline_layout)
|
||||||
.render_pass(data.render_pass)
|
.render_pass(data.render_pass)
|
||||||
|
@ -670,20 +713,38 @@ unsafe fn create_render_pass(
|
||||||
.attachment(0)
|
.attachment(0)
|
||||||
.layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL);
|
.layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL);
|
||||||
|
|
||||||
|
let depth_stencil_attachment = vk::AttachmentDescription::builder()
|
||||||
|
.format(depth_buffer::get_depth_format(instance, data)?)
|
||||||
|
.samples(vk::SampleCountFlags::_1)
|
||||||
|
.load_op(vk::AttachmentLoadOp::CLEAR)
|
||||||
|
.store_op(vk::AttachmentStoreOp::DONT_CARE)
|
||||||
|
.stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
|
||||||
|
.stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
|
||||||
|
.initial_layout(vk::ImageLayout::UNDEFINED)
|
||||||
|
.final_layout(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||||
|
|
||||||
|
let depth_stencil_attachment_ref = vk::AttachmentReference::builder()
|
||||||
|
.attachment(1)
|
||||||
|
.layout(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||||
|
|
||||||
let color_attachments = &[color_attachment_ref];
|
let color_attachments = &[color_attachment_ref];
|
||||||
let subpass = vk::SubpassDescription::builder()
|
let subpass = vk::SubpassDescription::builder()
|
||||||
.pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
|
.pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
|
||||||
.color_attachments(color_attachments);
|
.color_attachments(color_attachments)
|
||||||
|
.depth_stencil_attachment(&depth_stencil_attachment_ref);
|
||||||
|
|
||||||
let dependency = vk::SubpassDependency::builder()
|
let dependency = vk::SubpassDependency::builder()
|
||||||
.src_subpass(vk::SUBPASS_EXTERNAL)
|
.src_subpass(vk::SUBPASS_EXTERNAL)
|
||||||
.dst_subpass(0)
|
.dst_subpass(0)
|
||||||
.src_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT)
|
.src_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT
|
||||||
|
| vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS)
|
||||||
.src_access_mask(vk::AccessFlags::empty())
|
.src_access_mask(vk::AccessFlags::empty())
|
||||||
.dst_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT)
|
.dst_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT
|
||||||
.dst_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE);
|
| vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS)
|
||||||
|
.dst_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE
|
||||||
|
| vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE);
|
||||||
|
|
||||||
let attachments = &[color_attachment];
|
let attachments = &[color_attachment, depth_stencil_attachment];
|
||||||
let subpasses = &[subpass];
|
let subpasses = &[subpass];
|
||||||
let dependencies = &[dependency];
|
let dependencies = &[dependency];
|
||||||
let info = vk::RenderPassCreateInfo::builder()
|
let info = vk::RenderPassCreateInfo::builder()
|
||||||
|
@ -701,7 +762,7 @@ unsafe fn create_framebuffers(device: &Device, data: &mut app_data::AppData) ->
|
||||||
.swapchain_image_views
|
.swapchain_image_views
|
||||||
.iter()
|
.iter()
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
let attachments = &[*i];
|
let attachments = &[*i, data.depth_image_view];
|
||||||
let create_info = vk::FramebufferCreateInfo::builder()
|
let create_info = vk::FramebufferCreateInfo::builder()
|
||||||
.render_pass(data.render_pass)
|
.render_pass(data.render_pass)
|
||||||
.attachments(attachments)
|
.attachments(attachments)
|
||||||
|
@ -716,84 +777,6 @@ unsafe fn create_framebuffers(device: &Device, data: &mut app_data::AppData) ->
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn create_command_pool(
|
|
||||||
instance: &Instance,
|
|
||||||
device: &Device,
|
|
||||||
data: &mut app_data::AppData,
|
|
||||||
) -> Result<()> {
|
|
||||||
let indices = queue_family_indices::QueueFamilyIndices::get(instance, data, data.physical_device)?;
|
|
||||||
|
|
||||||
let info = vk::CommandPoolCreateInfo::builder()
|
|
||||||
.flags(vk::CommandPoolCreateFlags::empty()) // Optional.
|
|
||||||
.queue_family_index(indices.graphics);
|
|
||||||
|
|
||||||
data.command_pool = device.create_command_pool(&info, None)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn create_command_buffers(device: &Device, data: &mut app_data::AppData) -> Result<()> {
|
|
||||||
let allocate_info = vk::CommandBufferAllocateInfo::builder()
|
|
||||||
.command_pool(data.command_pool)
|
|
||||||
.level(vk::CommandBufferLevel::PRIMARY)
|
|
||||||
.command_buffer_count(data.framebuffers.len() as u32);
|
|
||||||
|
|
||||||
data.command_buffers = device.allocate_command_buffers(&allocate_info)?;
|
|
||||||
|
|
||||||
for (i, command_buffer) in data.command_buffers.iter().enumerate() {
|
|
||||||
let inheritance = vk::CommandBufferInheritanceInfo::builder();
|
|
||||||
|
|
||||||
let info = vk::CommandBufferBeginInfo::builder()
|
|
||||||
.flags(vk::CommandBufferUsageFlags::empty()) // Optional.
|
|
||||||
.inheritance_info(&inheritance); // Optional.
|
|
||||||
|
|
||||||
device.begin_command_buffer(*command_buffer, &info)?;
|
|
||||||
|
|
||||||
let render_area = vk::Rect2D::builder()
|
|
||||||
.offset(vk::Offset2D::default())
|
|
||||||
.extent(data.swapchain_extent);
|
|
||||||
|
|
||||||
let color_clear_value = vk::ClearValue {
|
|
||||||
color: vk::ClearColorValue {
|
|
||||||
float32: [0.0, 0.0, 0.0, 1.0],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let clear_values = &[color_clear_value];
|
|
||||||
let info = vk::RenderPassBeginInfo::builder()
|
|
||||||
.render_pass(data.render_pass)
|
|
||||||
.framebuffer(data.framebuffers[i])
|
|
||||||
.render_area(render_area)
|
|
||||||
.clear_values(clear_values);
|
|
||||||
|
|
||||||
device.cmd_begin_render_pass(
|
|
||||||
*command_buffer, &info, vk::SubpassContents::INLINE);
|
|
||||||
|
|
||||||
device.cmd_bind_pipeline(
|
|
||||||
*command_buffer, vk::PipelineBindPoint::GRAPHICS, data.pipeline);
|
|
||||||
|
|
||||||
device.cmd_bind_vertex_buffers(*command_buffer, 0, &[data.vertex_buffer], &[0]);
|
|
||||||
device.cmd_bind_index_buffer(*command_buffer, data.index_buffer, 0, vk::IndexType::UINT16);
|
|
||||||
|
|
||||||
device.cmd_bind_descriptor_sets(
|
|
||||||
*command_buffer,
|
|
||||||
vk::PipelineBindPoint::GRAPHICS,
|
|
||||||
data.pipeline_layout,
|
|
||||||
0,
|
|
||||||
&[data.descriptor_sets[i]],
|
|
||||||
&[],
|
|
||||||
);
|
|
||||||
|
|
||||||
device.cmd_draw_indexed(*command_buffer, buffer::INDICES.len() as u32, 1, 0, 0, 0);
|
|
||||||
|
|
||||||
device.cmd_end_render_pass(*command_buffer);
|
|
||||||
|
|
||||||
device.end_command_buffer(*command_buffer)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn create_sync_objects(device: &Device, data: &mut app_data::AppData) -> Result<()> {
|
unsafe fn create_sync_objects(device: &Device, data: &mut app_data::AppData) -> Result<()> {
|
||||||
let semaphore_info = vk::SemaphoreCreateInfo::builder();
|
let semaphore_info = vk::SemaphoreCreateInfo::builder();
|
||||||
let fence_info = vk::FenceCreateInfo::builder()
|
let fence_info = vk::FenceCreateInfo::builder()
|
||||||
|
|
|
@ -10,6 +10,7 @@ use vulkanalia::vk::KhrSwapchainExtension;
|
||||||
|
|
||||||
use crate::app_data;
|
use crate::app_data;
|
||||||
use crate::queue_family_indices;
|
use crate::queue_family_indices;
|
||||||
|
use crate::image;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SwapchainSupport {
|
pub struct SwapchainSupport {
|
||||||
|
@ -140,26 +141,7 @@ pub unsafe fn create_swapchain_image_views(
|
||||||
data.swapchain_image_views = data
|
data.swapchain_image_views = data
|
||||||
.swapchain_images
|
.swapchain_images
|
||||||
.iter()
|
.iter()
|
||||||
.map(|i| {
|
.map(|i| image::create_image_view(device, *i, data.swapchain_format, vk::ImageAspectFlags::COLOR))
|
||||||
let components = vk::ComponentMapping::builder()
|
|
||||||
.r(vk::ComponentSwizzle::IDENTITY)
|
|
||||||
.g(vk::ComponentSwizzle::IDENTITY)
|
|
||||||
.b(vk::ComponentSwizzle::IDENTITY)
|
|
||||||
.a(vk::ComponentSwizzle::IDENTITY);
|
|
||||||
let subresource_range = vk::ImageSubresourceRange::builder()
|
|
||||||
.aspect_mask(vk::ImageAspectFlags::COLOR)
|
|
||||||
.base_mip_level(0)
|
|
||||||
.level_count(1)
|
|
||||||
.base_array_layer(0)
|
|
||||||
.layer_count(1);
|
|
||||||
let info = vk::ImageViewCreateInfo::builder()
|
|
||||||
.image(*i)
|
|
||||||
.view_type(vk::ImageViewType::_2D)
|
|
||||||
.format(data.swapchain_format)
|
|
||||||
.components(components)
|
|
||||||
.subresource_range(subresource_range);
|
|
||||||
device.create_image_view(&info, None)
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -10,13 +10,14 @@ type Vec3 = cgmath::Vector3<f32>;
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Vertex {
|
pub struct Vertex {
|
||||||
pub pos: Vec2,
|
pub pos: Vec3,
|
||||||
pub color: Vec3,
|
pub color: Vec3,
|
||||||
|
pub tex_coord: Vec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vertex {
|
impl Vertex {
|
||||||
pub const fn new(pos: Vec2, color: Vec3) -> Self {
|
pub const fn new(pos: Vec3, color: Vec3, tex_coord: Vec2) -> Self {
|
||||||
Self { pos, color }
|
Self { pos, color, tex_coord }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn binding_description() -> vk::VertexInputBindingDescription {
|
pub fn binding_description() -> vk::VertexInputBindingDescription {
|
||||||
|
@ -27,11 +28,11 @@ impl Vertex {
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attribute_descriptions() -> [vk::VertexInputAttributeDescription; 2] {
|
pub fn attribute_descriptions() -> [vk::VertexInputAttributeDescription; 3] {
|
||||||
let pos = vk::VertexInputAttributeDescription::builder()
|
let pos = vk::VertexInputAttributeDescription::builder()
|
||||||
.binding(0)
|
.binding(0)
|
||||||
.location(0)
|
.location(0)
|
||||||
.format(vk::Format::R32G32_SFLOAT)
|
.format(vk::Format::R32G32B32_SFLOAT)
|
||||||
.offset(0)
|
.offset(0)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -41,6 +42,13 @@ impl Vertex {
|
||||||
.format(vk::Format::R32G32B32_SFLOAT)
|
.format(vk::Format::R32G32B32_SFLOAT)
|
||||||
.offset(size_of::<Vec2>() as u32)
|
.offset(size_of::<Vec2>() as u32)
|
||||||
.build();
|
.build();
|
||||||
[pos, color]
|
|
||||||
|
let tex_coord = vk::VertexInputAttributeDescription::builder()
|
||||||
|
.binding(0)
|
||||||
|
.location(2)
|
||||||
|
.format(vk::Format::R32G32_SFLOAT)
|
||||||
|
.offset((size_of::<Vec2>() + size_of::<Vec3>()) as u32)
|
||||||
|
.build();
|
||||||
|
[pos, color, tex_coord]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue