Skip to content

Commit

Permalink
Update shader creation in tutorial (#182)
Browse files Browse the repository at this point in the history
  • Loading branch information
KyleMayes committed Sep 15, 2023
1 parent f66a484 commit e84e77d
Show file tree
Hide file tree
Showing 26 changed files with 108 additions and 177 deletions.
1 change: 1 addition & 0 deletions tutorial/book/preprocessor/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ fn load_index() -> HashMap<&'static str, &'static str> {
info!("Loaded index has {} entries.", index.len());

// Add entries for non-generated items.
index.insert("Bytecode", "https://docs.rs/vulkanalia/%VERSION%/vulkanalia/bytecode/struct.Bytecode.html");
index.insert("Device", "https://docs.rs/vulkanalia/%VERSION%/vulkanalia/struct.Device.html");
index.insert("Entry", "https://docs.rs/vulkanalia/%VERSION%/vulkanalia/struct.Entry.html");
index.insert("Instance", "https://docs.rs/vulkanalia/%VERSION%/vulkanalia/struct.Instance.html");
Expand Down
20 changes: 11 additions & 9 deletions tutorial/book/src/pipeline/shader_modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,24 +204,26 @@ unsafe fn create_shader_module(

The function will take a slice containing the bytecode as parameter and create a `vk::ShaderModule` from it using our logical device.

Creating a shader module is simple, we only need to specify the length of our bytecode slice and the bytecode slice itself. This information is specified in a `vk::ShaderModuleCreateInfo` structure. The one catch is that the size of the bytecode is specified in bytes, but the bytecode slice expected by this struct is a `&[u32]` instead of a `&[u8]`. Therefore we will first need to convert our `&[u8]` into an `&[u32]`. We will accomplish this with [`slice::align_to`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.align_to) which can be used to convert a slice into a slice containing a type with a different size and/or alignment requirements. However, the `&[u8]` returned by `include_bytes!` may not meet our alignment requirements, so we'll first copy it into a `Vec`.
Creating a shader module is simple, we only need to specify the length of our bytecode slice and the bytecode slice itself. This information is specified in a `vk::ShaderModuleCreateInfo` structure. The one catch is that the size of the bytecode is specified in bytes, but the bytecode slice expected by this struct is a `&[u32]` instead of a `&[u8]`. Therefore we will first need to convert our `&[u8]` into an `&[u32]`.

`vulkanalia` has a helper struct called `Bytecode` that we will use to copy the shader bytecode into a new buffer that is guaranteed to have the correct alignment for an array of `u32`s. Add an import for this helper struct:

```rust,noplaypen
let bytecode = Vec::<u8>::from(bytecode);
let (prefix, code, suffix) = bytecode.align_to::<u32>();
if !prefix.is_empty() || !suffix.is_empty() {
return Err(anyhow!("Shader bytecode is not properly aligned."));
}
use vulkanalia::bytecode::Bytecode;
```

The middle slice returned by this method (`code`) is a `&[u32]` and is guaranteed to be correctly aligned. Any `u8`s in our `bytecode` slice that fell outside this alignment guarantee will appear in the first or third slices returned (`prefix` and `suffix`). We'll require that both of these slices are empty to ensure that our entire `bytecode` slice has been converted to a `&[u32]` though you shouldn't have to worry about this failure case in practice.
Getting back to our `create_shader_module` function, `Bytecode::new` will return an error if the supplied byte slice has a length that is not a multiple of 4 or if the allocation of the aligned buffer fails. As long as you are providing valid shader bytecode this should never be a problem, so we'll just `unwrap` the result.

```rust,noplaypen
let bytecode = Bytecode::new(bytecode).unwrap();
```

We can then construct a `vk::ShaderModuleCreateInfo` and use it to call `create_shader_module` to create the shader module:

```rust,noplaypen
let info = vk::ShaderModuleCreateInfo::builder()
.code_size(bytecode.len())
.code(code);
.code_size(bytecode.code_size())
.code(bytecode.code());
Ok(device.create_shader_module(&info, None)?)
```
Expand Down
11 changes: 4 additions & 7 deletions tutorial/src/09_shader_modules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::os::raw::c_void;
use anyhow::{anyhow, Result};
use log::*;
use thiserror::Error;
use vulkanalia::bytecode::Bytecode;
use vulkanalia::loader::{LibloadingLoader, LIBRARY};
use vulkanalia::prelude::v1_0::*;
use vulkanalia::window as vk_window;
Expand Down Expand Up @@ -517,15 +518,11 @@ unsafe fn create_pipeline(device: &Device, data: &mut AppData) -> Result<()> {
}

unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::ShaderModule> {
let bytecode = Vec::<u8>::from(bytecode);
let (prefix, code, suffix) = bytecode.align_to::<u32>();
if !prefix.is_empty() || !suffix.is_empty() {
return Err(anyhow!("Shader bytecode is not properly aligned."));
}
let bytecode = Bytecode::new(bytecode).unwrap();

let info = vk::ShaderModuleCreateInfo::builder()
.code_size(bytecode.len())
.code(code);
.code_size(bytecode.code_size())
.code(bytecode.code());

Ok(device.create_shader_module(&info, None)?)
}
Expand Down
11 changes: 4 additions & 7 deletions tutorial/src/10_fixed_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::os::raw::c_void;
use anyhow::{anyhow, Result};
use log::*;
use thiserror::Error;
use vulkanalia::bytecode::Bytecode;
use vulkanalia::loader::{LibloadingLoader, LIBRARY};
use vulkanalia::prelude::v1_0::*;
use vulkanalia::window as vk_window;
Expand Down Expand Up @@ -586,15 +587,11 @@ unsafe fn create_pipeline(device: &Device, data: &mut AppData) -> Result<()> {
}

unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::ShaderModule> {
let bytecode = Vec::<u8>::from(bytecode);
let (prefix, code, suffix) = bytecode.align_to::<u32>();
if !prefix.is_empty() || !suffix.is_empty() {
return Err(anyhow!("Shader bytecode is not properly aligned."));
}
let bytecode = Bytecode::new(bytecode).unwrap();

let info = vk::ShaderModuleCreateInfo::builder()
.code_size(bytecode.len())
.code(code);
.code_size(bytecode.code_size())
.code(bytecode.code());

Ok(device.create_shader_module(&info, None)?)
}
Expand Down
11 changes: 4 additions & 7 deletions tutorial/src/11_render_passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::os::raw::c_void;
use anyhow::{anyhow, Result};
use log::*;
use thiserror::Error;
use vulkanalia::bytecode::Bytecode;
use vulkanalia::loader::{LibloadingLoader, LIBRARY};
use vulkanalia::prelude::v1_0::*;
use vulkanalia::window as vk_window;
Expand Down Expand Up @@ -626,15 +627,11 @@ unsafe fn create_pipeline(device: &Device, data: &mut AppData) -> Result<()> {
}

unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::ShaderModule> {
let bytecode = Vec::<u8>::from(bytecode);
let (prefix, code, suffix) = bytecode.align_to::<u32>();
if !prefix.is_empty() || !suffix.is_empty() {
return Err(anyhow!("Shader bytecode is not properly aligned."));
}
let bytecode = Bytecode::new(bytecode).unwrap();

let info = vk::ShaderModuleCreateInfo::builder()
.code_size(bytecode.len())
.code(code);
.code_size(bytecode.code_size())
.code(bytecode.code());

Ok(device.create_shader_module(&info, None)?)
}
Expand Down
11 changes: 4 additions & 7 deletions tutorial/src/12_graphics_pipeline_complete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::os::raw::c_void;
use anyhow::{anyhow, Result};
use log::*;
use thiserror::Error;
use vulkanalia::bytecode::Bytecode;
use vulkanalia::loader::{LibloadingLoader, LIBRARY};
use vulkanalia::prelude::v1_0::*;
use vulkanalia::window as vk_window;
Expand Down Expand Up @@ -647,15 +648,11 @@ unsafe fn create_pipeline(device: &Device, data: &mut AppData) -> Result<()> {
}

unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::ShaderModule> {
let bytecode = Vec::<u8>::from(bytecode);
let (prefix, code, suffix) = bytecode.align_to::<u32>();
if !prefix.is_empty() || !suffix.is_empty() {
return Err(anyhow!("Shader bytecode is not properly aligned."));
}
let bytecode = Bytecode::new(bytecode).unwrap();

let info = vk::ShaderModuleCreateInfo::builder()
.code_size(bytecode.len())
.code(code);
.code_size(bytecode.code_size())
.code(bytecode.code());

Ok(device.create_shader_module(&info, None)?)
}
Expand Down
11 changes: 4 additions & 7 deletions tutorial/src/13_framebuffers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::os::raw::c_void;
use anyhow::{anyhow, Result};
use log::*;
use thiserror::Error;
use vulkanalia::bytecode::Bytecode;
use vulkanalia::loader::{LibloadingLoader, LIBRARY};
use vulkanalia::prelude::v1_0::*;
use vulkanalia::window as vk_window;
Expand Down Expand Up @@ -651,15 +652,11 @@ unsafe fn create_pipeline(device: &Device, data: &mut AppData) -> Result<()> {
}

unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::ShaderModule> {
let bytecode = Vec::<u8>::from(bytecode);
let (prefix, code, suffix) = bytecode.align_to::<u32>();
if !prefix.is_empty() || !suffix.is_empty() {
return Err(anyhow!("Shader bytecode is not properly aligned."));
}
let bytecode = Bytecode::new(bytecode).unwrap();

let info = vk::ShaderModuleCreateInfo::builder()
.code_size(bytecode.len())
.code(code);
.code_size(bytecode.code_size())
.code(bytecode.code());

Ok(device.create_shader_module(&info, None)?)
}
Expand Down
11 changes: 4 additions & 7 deletions tutorial/src/14_command_buffers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::os::raw::c_void;
use anyhow::{anyhow, Result};
use log::*;
use thiserror::Error;
use vulkanalia::bytecode::Bytecode;
use vulkanalia::loader::{LibloadingLoader, LIBRARY};
use vulkanalia::prelude::v1_0::*;
use vulkanalia::window as vk_window;
Expand Down Expand Up @@ -658,15 +659,11 @@ unsafe fn create_pipeline(device: &Device, data: &mut AppData) -> Result<()> {
}

unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::ShaderModule> {
let bytecode = Vec::<u8>::from(bytecode);
let (prefix, code, suffix) = bytecode.align_to::<u32>();
if !prefix.is_empty() || !suffix.is_empty() {
return Err(anyhow!("Shader bytecode is not properly aligned."));
}
let bytecode = Bytecode::new(bytecode).unwrap();

let info = vk::ShaderModuleCreateInfo::builder()
.code_size(bytecode.len())
.code(code);
.code_size(bytecode.code_size())
.code(bytecode.code());

Ok(device.create_shader_module(&info, None)?)
}
Expand Down
11 changes: 4 additions & 7 deletions tutorial/src/15_hello_triangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::os::raw::c_void;
use anyhow::{anyhow, Result};
use log::*;
use thiserror::Error;
use vulkanalia::bytecode::Bytecode;
use vulkanalia::loader::{LibloadingLoader, LIBRARY};
use vulkanalia::prelude::v1_0::*;
use vulkanalia::window as vk_window;
Expand Down Expand Up @@ -735,15 +736,11 @@ unsafe fn create_pipeline(device: &Device, data: &mut AppData) -> Result<()> {
}

unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::ShaderModule> {
let bytecode = Vec::<u8>::from(bytecode);
let (prefix, code, suffix) = bytecode.align_to::<u32>();
if !prefix.is_empty() || !suffix.is_empty() {
return Err(anyhow!("Shader bytecode is not properly aligned."));
}
let bytecode = Bytecode::new(bytecode).unwrap();

let info = vk::ShaderModuleCreateInfo::builder()
.code_size(bytecode.len())
.code(code);
.code_size(bytecode.code_size())
.code(bytecode.code());

Ok(device.create_shader_module(&info, None)?)
}
Expand Down
11 changes: 4 additions & 7 deletions tutorial/src/16_swapchain_recreation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::os::raw::c_void;
use anyhow::{anyhow, Result};
use log::*;
use thiserror::Error;
use vulkanalia::bytecode::Bytecode;
use vulkanalia::loader::{LibloadingLoader, LIBRARY};
use vulkanalia::prelude::v1_0::*;
use vulkanalia::window as vk_window;
Expand Down Expand Up @@ -780,15 +781,11 @@ unsafe fn create_pipeline(device: &Device, data: &mut AppData) -> Result<()> {
}

unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::ShaderModule> {
let bytecode = Vec::<u8>::from(bytecode);
let (prefix, code, suffix) = bytecode.align_to::<u32>();
if !prefix.is_empty() || !suffix.is_empty() {
return Err(anyhow!("Shader bytecode is not properly aligned."));
}
let bytecode = Bytecode::new(bytecode).unwrap();

let info = vk::ShaderModuleCreateInfo::builder()
.code_size(bytecode.len())
.code(code);
.code_size(bytecode.code_size())
.code(bytecode.code());

Ok(device.create_shader_module(&info, None)?)
}
Expand Down
11 changes: 4 additions & 7 deletions tutorial/src/17_vertex_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use anyhow::{anyhow, Result};
use cgmath::{vec2, vec3};
use log::*;
use thiserror::Error;
use vulkanalia::bytecode::Bytecode;
use vulkanalia::loader::{LibloadingLoader, LIBRARY};
use vulkanalia::prelude::v1_0::*;
use vulkanalia::window as vk_window;
Expand Down Expand Up @@ -796,15 +797,11 @@ unsafe fn create_pipeline(device: &Device, data: &mut AppData) -> Result<()> {
}

unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::ShaderModule> {
let bytecode = Vec::<u8>::from(bytecode);
let (prefix, code, suffix) = bytecode.align_to::<u32>();
if !prefix.is_empty() || !suffix.is_empty() {
return Err(anyhow!("Shader bytecode is not properly aligned."));
}
let bytecode = Bytecode::new(bytecode).unwrap();

let info = vk::ShaderModuleCreateInfo::builder()
.code_size(bytecode.len())
.code(code);
.code_size(bytecode.code_size())
.code(bytecode.code());

Ok(device.create_shader_module(&info, None)?)
}
Expand Down
11 changes: 4 additions & 7 deletions tutorial/src/18_vertex_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use anyhow::{anyhow, Result};
use cgmath::{vec2, vec3};
use log::*;
use thiserror::Error;
use vulkanalia::bytecode::Bytecode;
use vulkanalia::loader::{LibloadingLoader, LIBRARY};
use vulkanalia::prelude::v1_0::*;
use vulkanalia::window as vk_window;
Expand Down Expand Up @@ -803,15 +804,11 @@ unsafe fn create_pipeline(device: &Device, data: &mut AppData) -> Result<()> {
}

unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::ShaderModule> {
let bytecode = Vec::<u8>::from(bytecode);
let (prefix, code, suffix) = bytecode.align_to::<u32>();
if !prefix.is_empty() || !suffix.is_empty() {
return Err(anyhow!("Shader bytecode is not properly aligned."));
}
let bytecode = Bytecode::new(bytecode).unwrap();

let info = vk::ShaderModuleCreateInfo::builder()
.code_size(bytecode.len())
.code(code);
.code_size(bytecode.code_size())
.code(bytecode.code());

Ok(device.create_shader_module(&info, None)?)
}
Expand Down
11 changes: 4 additions & 7 deletions tutorial/src/19_staging_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use anyhow::{anyhow, Result};
use cgmath::{vec2, vec3};
use log::*;
use thiserror::Error;
use vulkanalia::bytecode::Bytecode;
use vulkanalia::loader::{LibloadingLoader, LIBRARY};
use vulkanalia::prelude::v1_0::*;
use vulkanalia::window as vk_window;
Expand Down Expand Up @@ -803,15 +804,11 @@ unsafe fn create_pipeline(device: &Device, data: &mut AppData) -> Result<()> {
}

unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::ShaderModule> {
let bytecode = Vec::<u8>::from(bytecode);
let (prefix, code, suffix) = bytecode.align_to::<u32>();
if !prefix.is_empty() || !suffix.is_empty() {
return Err(anyhow!("Shader bytecode is not properly aligned."));
}
let bytecode = Bytecode::new(bytecode).unwrap();

let info = vk::ShaderModuleCreateInfo::builder()
.code_size(bytecode.len())
.code(code);
.code_size(bytecode.code_size())
.code(bytecode.code());

Ok(device.create_shader_module(&info, None)?)
}
Expand Down
11 changes: 4 additions & 7 deletions tutorial/src/20_index_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use anyhow::{anyhow, Result};
use cgmath::{vec2, vec3};
use log::*;
use thiserror::Error;
use vulkanalia::bytecode::Bytecode;
use vulkanalia::loader::{LibloadingLoader, LIBRARY};
use vulkanalia::prelude::v1_0::*;
use vulkanalia::window as vk_window;
Expand Down Expand Up @@ -811,15 +812,11 @@ unsafe fn create_pipeline(device: &Device, data: &mut AppData) -> Result<()> {
}

unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::ShaderModule> {
let bytecode = Vec::<u8>::from(bytecode);
let (prefix, code, suffix) = bytecode.align_to::<u32>();
if !prefix.is_empty() || !suffix.is_empty() {
return Err(anyhow!("Shader bytecode is not properly aligned."));
}
let bytecode = Bytecode::new(bytecode).unwrap();

let info = vk::ShaderModuleCreateInfo::builder()
.code_size(bytecode.len())
.code(code);
.code_size(bytecode.code_size())
.code(bytecode.code());

Ok(device.create_shader_module(&info, None)?)
}
Expand Down
11 changes: 4 additions & 7 deletions tutorial/src/21_descriptor_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use anyhow::{anyhow, Result};
use cgmath::{point3, vec2, vec3, Deg};
use log::*;
use thiserror::Error;
use vulkanalia::bytecode::Bytecode;
use vulkanalia::loader::{LibloadingLoader, LIBRARY};
use vulkanalia::prelude::v1_0::*;
use vulkanalia::window as vk_window;
Expand Down Expand Up @@ -883,15 +884,11 @@ unsafe fn create_pipeline(device: &Device, data: &mut AppData) -> Result<()> {
}

unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::ShaderModule> {
let bytecode = Vec::<u8>::from(bytecode);
let (prefix, code, suffix) = bytecode.align_to::<u32>();
if !prefix.is_empty() || !suffix.is_empty() {
return Err(anyhow!("Shader bytecode is not properly aligned."));
}
let bytecode = Bytecode::new(bytecode).unwrap();

let info = vk::ShaderModuleCreateInfo::builder()
.code_size(bytecode.len())
.code(code);
.code_size(bytecode.code_size())
.code(bytecode.code());

Ok(device.create_shader_module(&info, None)?)
}
Expand Down
Loading

0 comments on commit e84e77d

Please sign in to comment.