aboutsummaryrefslogtreecommitdiff
path: root/stockton-render
diff options
context:
space:
mode:
authortcmal <me@aria.rip>2024-08-25 17:44:22 +0100
committertcmal <me@aria.rip>2024-08-25 17:44:22 +0100
commite8126750633fd9ed3e682a2c889740a1f51a86f7 (patch)
treed2da548230f9ff3703fbf7f60f52f575f43d360d /stockton-render
parent6793abcd3bb054ff4c6dc0e6b97a76d463730deb (diff)
feat(render): rendy-memory for textures
unfortunately this involves downgrading gfx-hal
Diffstat (limited to 'stockton-render')
-rw-r--r--stockton-render/Cargo.toml5
-rw-r--r--stockton-render/src/draw/buffer.rs4
-rw-r--r--stockton-render/src/draw/context.rs60
-rw-r--r--stockton-render/src/draw/mod.rs1
-rw-r--r--stockton-render/src/draw/pipeline.rs1
-rw-r--r--stockton-render/src/draw/target.rs22
-rw-r--r--stockton-render/src/draw/texture/chunk.rs16
-rw-r--r--stockton-render/src/draw/texture/image.rs346
-rw-r--r--stockton-render/src/draw/texture/loader.rs42
-rw-r--r--stockton-render/src/draw/ui/pipeline.rs3
-rwxr-xr-xstockton-render/src/draw/ui/texture.rs3
-rw-r--r--stockton-render/src/draw/utils.rs38
-rw-r--r--stockton-render/src/error.rs2
-rw-r--r--stockton-render/src/types.rs3
14 files changed, 460 insertions, 86 deletions
diff --git a/stockton-render/Cargo.toml b/stockton-render/Cargo.toml
index 7c69be6..2840015 100644
--- a/stockton-render/Cargo.toml
+++ b/stockton-render/Cargo.toml
@@ -9,7 +9,7 @@ stockton-input = { path = "../stockton-input" }
stockton-levels = { path = "../stockton-levels" }
stockton-types = { path = "../stockton-types" }
winit = "^0.21"
-gfx-hal = "^0.5"
+gfx-hal = "0.4.1"
arrayvec = "0.4.10"
nalgebra-glm = "^0.6"
shaderc = "^0.7"
@@ -17,12 +17,13 @@ log = "0.4.0"
image = "0.23.11"
legion = { version = "^0.3" }
egui = "^0.2"
+rendy-memory = "0.5.2"
[features]
default = ["vulkan"]
vulkan = ["gfx-backend-vulkan"]
[dependencies.gfx-backend-vulkan]
-version = "^0.5"
+version = "0.4.1"
features = ["x11"]
optional = true
diff --git a/stockton-render/src/draw/buffer.rs b/stockton-render/src/draw/buffer.rs
index c202d04..5d88e25 100644
--- a/stockton-render/src/draw/buffer.rs
+++ b/stockton-render/src/draw/buffer.rs
@@ -23,7 +23,7 @@ use std::ops::{Index, IndexMut};
use hal::prelude::*;
use hal::{
buffer::Usage,
- memory::{Properties, Segment},
+ memory::Properties,
queue::Submission,
MemoryTypeId,
};
@@ -134,7 +134,7 @@ impl<'a, T: Sized> StagedBuffer<'a, T> {
// Map it somewhere and get a slice to that memory
let staged_mapped_memory = unsafe {
- let ptr = device.map_memory(&staged_memory, Segment::ALL).unwrap(); // TODO
+ let ptr = device.map_memory(&staged_memory, 0..size_bytes).unwrap(); // TODO
std::slice::from_raw_parts_mut(ptr as *mut T, size.try_into().unwrap())
};
diff --git a/stockton-render/src/draw/context.rs b/stockton-render/src/draw/context.rs
index 4d700e5..8f4b549 100644
--- a/stockton-render/src/draw/context.rs
+++ b/stockton-render/src/draw/context.rs
@@ -26,6 +26,7 @@ use hal::{pool::CommandPoolCreateFlags, prelude::*};
use log::debug;
use na::Mat4;
use winit::window::Window;
+use rendy_memory::DynamicConfig;
use super::{
buffer::ModifiableBuffer,
@@ -35,6 +36,7 @@ use super::{
target::{SwapchainProperties, TargetChain},
texture::TextureStore,
ui::{do_render as do_render_ui, ensure_textures as ensure_textures_ui, UIPipeline, UIPoint},
+ utils::find_memory_type_id,
};
use crate::{error, types::*, window::UIState};
use stockton_levels::prelude::*;
@@ -85,6 +87,10 @@ pub struct RenderingContext<'a> {
/// Buffers used for drawing the UI
ui_draw_buffers: ManuallyDrop<DrawBuffers<'a, UIPoint>>,
+ /// Memory allocator used for any sort of textures / maps
+ /// Guaranteed suitable for 2D RGBA images with `Optimal` tiling and `Usage::Sampled`
+ texture_allocator: ManuallyDrop<DynamicAllocator>,
+
/// View projection matrix
pub(crate) vp_matrix: Mat4,
@@ -152,10 +158,54 @@ impl<'a> RenderingContext<'a> {
// UI Vertex and index buffers
let ui_draw_buffers = DrawBuffers::new(&mut device, &adapter)?;
+ // Memory allocators
+ let mut texture_allocator = unsafe {
+ use hal::{
+ memory::Properties,
+ image::{Kind, Tiling, Usage, ViewCapabilities},
+ format::Format,
+ };
+
+ // We create an empty image with the same format as used for textures
+ // this is to get the type_mask required, which will stay the same for
+ // all colour images of the same tiling. (certain memory flags excluded).
+
+ // Size and alignment don't necessarily stay the same, so we're forced to
+ // guess at the alignment for our allocator.
+
+ // TODO: Way to tune these options
+
+ let img = device.create_image(
+ Kind::D2(16 as u32, 16 as u32, 1, 1),
+ 1,
+ Format::Rgba8Srgb,
+ Tiling::Optimal,
+ Usage::SAMPLED,
+ ViewCapabilities::empty()
+ ).map_err(|_| error::CreationError::OutOfMemoryError)?;
+
+ let type_mask = device.get_image_requirements(&img).type_mask;
+
+ device.destroy_image(img);
+
+ let props = Properties::DEVICE_LOCAL;
+
+ DynamicAllocator::new(
+ find_memory_type_id(&adapter, type_mask, props).ok_or(error::CreationError::OutOfMemoryError)?,
+ props,
+ DynamicConfig {
+ block_size_granularity: 4 * 32 * 32, // 32x32 image
+ max_chunk_size: u64::pow(2, 63),
+ min_device_allocation: 4 * 32 * 32,
+ }
+ )
+ };
+
// Texture store
let texture_store = TextureStore::new(
&mut device,
&mut adapter,
+ &mut texture_allocator,
&mut queue_group.queues[0],
&mut cmd_pool,
file,
@@ -165,6 +215,7 @@ impl<'a> RenderingContext<'a> {
let ui_texture_store = TextureStore::new_empty(
&mut device,
&mut adapter,
+ &mut texture_allocator,
&mut queue_group.queues[0],
&mut cmd_pool,
1, // TODO
@@ -225,6 +276,8 @@ impl<'a> RenderingContext<'a> {
ui_draw_buffers: ManuallyDrop::new(ui_draw_buffers),
ui_texture_store: ManuallyDrop::new(ui_texture_store),
+
+ texture_allocator: ManuallyDrop::new(texture_allocator),
vp_matrix: Mat4::identity(),
@@ -305,6 +358,7 @@ impl<'a> RenderingContext<'a> {
ui,
&mut self.device,
&mut self.adapter,
+ &mut self.texture_allocator,
&mut self.queue_group.queues[0],
&mut self.cmd_pool,
);
@@ -379,8 +433,10 @@ impl<'a> core::ops::Drop for RenderingContext<'a> {
ManuallyDrop::into_inner(read(&self.draw_buffers)).deactivate(&mut self.device);
ManuallyDrop::into_inner(read(&self.ui_draw_buffers)).deactivate(&mut self.device);
- ManuallyDrop::into_inner(read(&self.texture_store)).deactivate(&mut self.device);
- ManuallyDrop::into_inner(read(&self.ui_texture_store)).deactivate(&mut self.device);
+ ManuallyDrop::into_inner(read(&self.texture_store)).deactivate(&mut self.device, &mut self.texture_allocator);
+ ManuallyDrop::into_inner(read(&self.ui_texture_store)).deactivate(&mut self.device, &mut self.texture_allocator);
+
+ ManuallyDrop::into_inner(read(&self.texture_allocator)).dispose();
ManuallyDrop::into_inner(read(&self.target_chain))
.deactivate(&mut self.device, &mut self.cmd_pool);
diff --git a/stockton-render/src/draw/mod.rs b/stockton-render/src/draw/mod.rs
index c96fc10..27e41cf 100644
--- a/stockton-render/src/draw/mod.rs
+++ b/stockton-render/src/draw/mod.rs
@@ -29,6 +29,7 @@ mod pipeline;
mod render;
mod texture;
mod ui;
+mod utils;
pub use self::camera::calc_vp_matrix_system;
pub use self::context::RenderingContext;
diff --git a/stockton-render/src/draw/pipeline.rs b/stockton-render/src/draw/pipeline.rs
index 2e45b61..df7ee4b 100644
--- a/stockton-render/src/draw/pipeline.rs
+++ b/stockton-render/src/draw/pipeline.rs
@@ -196,7 +196,6 @@ impl CompletePipeline {
depth_clamping: false,
depth_bias: None,
conservative: true,
- line_width: hal::pso::State::Static(1.0),
};
// Depth stencil
diff --git a/stockton-render/src/draw/target.rs b/stockton-render/src/draw/target.rs
index daf9942..02a7f84 100644
--- a/stockton-render/src/draw/target.rs
+++ b/stockton-render/src/draw/target.rs
@@ -32,7 +32,7 @@ use na::Mat4;
use super::{
buffer::ModifiableBuffer, draw_buffers::{DrawBuffers, UVPoint}, pipeline::CompletePipeline,
- texture::image::LoadedImage, ui::{UIPipeline, UIPoint},
+ texture::image::DedicatedLoadedImage, ui::{UIPipeline, UIPoint},
};
use crate::types::*;
@@ -134,7 +134,7 @@ pub struct TargetChain {
pub properties: SwapchainProperties,
/// The depth buffer/image used for drawing
- pub depth_buffer: ManuallyDrop<LoadedImage>,
+ pub depth_buffer: ManuallyDrop<DedicatedLoadedImage>,
/// Resources tied to each target frame in the swapchain
pub targets: Box<[TargetResources]>,
@@ -192,11 +192,11 @@ impl TargetChain {
.map_err(|_| TargetChainCreationError::Todo)?
};
- let depth_buffer: LoadedImage = {
+ let depth_buffer = {
use hal::format::Aspects;
use hal::image::SubresourceRange;
- LoadedImage::new(
+ DedicatedLoadedImage::new(
device,
adapter,
properties.depth_format,
@@ -306,7 +306,7 @@ impl TargetChain {
// Record commands
unsafe {
- use hal::buffer::{IndexBufferView, SubRange};
+ use hal::buffer::IndexBufferView;
use hal::command::{
ClearColor, ClearDepthStencil, ClearValue, CommandBufferFlags, SubpassContents,
};
@@ -332,7 +332,7 @@ impl TargetChain {
let vbufref: &<back::Backend as hal::Backend>::Buffer =
draw_buffers.vertex_buffer.get_buffer();
- let vbufs: ArrayVec<[_; 1]> = [(vbufref, SubRange::WHOLE)].into();
+ let vbufs: ArrayVec<[_; 1]> = [(vbufref, 0)].into();
let ibuf = draw_buffers.index_buffer.get_buffer();
(vbufs, ibuf)
@@ -363,7 +363,7 @@ impl TargetChain {
target.cmd_buffer.bind_vertex_buffers(0, vbufs);
target.cmd_buffer.bind_index_buffer(IndexBufferView {
buffer: ibuf,
- range: SubRange::WHOLE,
+ offset: 0,
index_type: hal::IndexType::U16,
});
};
@@ -391,7 +391,7 @@ impl TargetChain {
// Record commands
unsafe {
- use hal::buffer::{IndexBufferView, SubRange};
+ use hal::buffer::IndexBufferView;
use hal::command::{ClearColor, ClearValue, SubpassContents};
// Colour to clear window to
@@ -406,7 +406,7 @@ impl TargetChain {
let vbufref: &<back::Backend as hal::Backend>::Buffer =
draw_buffers.vertex_buffer.get_buffer();
- let vbufs: ArrayVec<[_; 1]> = [(vbufref, SubRange::WHOLE)].into();
+ let vbufs: ArrayVec<[_; 1]> = [(vbufref, 0)].into();
let ibuf = draw_buffers.index_buffer.get_buffer();
(vbufs, ibuf)
@@ -426,7 +426,7 @@ impl TargetChain {
target.cmd_buffer.bind_vertex_buffers(0, vbufs);
target.cmd_buffer.bind_index_buffer(IndexBufferView {
buffer: ibuf,
- range: SubRange::WHOLE,
+ offset: 0,
index_type: hal::IndexType::U16,
});
};
@@ -611,7 +611,7 @@ pub enum TargetChainCreationError {
#[derive(Debug)]
pub enum TargetResourcesCreationError {
- ImageViewError(hal::image::ViewCreationError),
+ ImageViewError(hal::image::ViewError),
FrameBufferNoMemory,
SyncObjectsNoMemory,
}
diff --git a/stockton-render/src/draw/texture/chunk.rs b/stockton-render/src/draw/texture/chunk.rs
index f1b88e9..b95e863 100644
--- a/stockton-render/src/draw/texture/chunk.rs
+++ b/stockton-render/src/draw/texture/chunk.rs
@@ -47,6 +47,7 @@ impl TextureChunk {
pub fn new_empty(
device: &mut Device,
adapter: &mut Adapter,
+ allocator: &mut DynamicAllocator,
command_queue: &mut CommandQueue,
command_pool: &mut CommandPool,
descriptor_set: DescriptorSet,
@@ -64,6 +65,7 @@ impl TextureChunk {
i,
device,
adapter,
+ allocator,
command_queue,
command_pool,
)
@@ -78,6 +80,7 @@ impl TextureChunk {
pub fn new<'a, I, R: TextureResolver<T>, T: LoadableImage>(
device: &mut Device,
adapter: &mut Adapter,
+ allocator: &mut DynamicAllocator,
command_queue: &mut CommandQueue,
command_pool: &mut CommandPool,
descriptor_set: DescriptorSet,
@@ -98,11 +101,11 @@ impl TextureChunk {
for tex in textures {
if let Some(img) = resolver.resolve(tex) {
store
- .put_texture(img, local_idx, device, adapter, command_queue, command_pool)
+ .put_texture(img, local_idx, device, adapter, allocator, command_queue, command_pool)
.unwrap();
} else {
// Texture not found. For now, tear everything down.
- store.deactivate(device);
+ store.deactivate(device, allocator);
return Err(error::CreationError::BadDataError);
}
@@ -119,6 +122,7 @@ impl TextureChunk {
local_idx,
device,
adapter,
+ allocator,
command_queue,
command_pool,
)
@@ -136,6 +140,7 @@ impl TextureChunk {
idx: usize,
device: &mut Device,
adapter: &mut Adapter,
+ allocator: &mut DynamicAllocator,
command_queue: &mut CommandQueue,
command_pool: &mut CommandPool,
) -> Result<(), &'static str> {
@@ -144,6 +149,7 @@ impl TextureChunk {
image,
device,
adapter,
+ allocator,
command_queue,
command_pool,
hal::format::Format::Rgba8Srgb, // TODO
@@ -177,7 +183,7 @@ impl TextureChunk {
// Store it so we can safely deactivate it when we need to
// Deactivate the old image if we need to
if idx < self.sampled_images.len() {
- replace(&mut self.sampled_images[idx], texture).deactivate(device);
+ replace(&mut self.sampled_images[idx], texture).deactivate(device, allocator);
} else {
self.sampled_images.push(texture);
}
@@ -185,9 +191,9 @@ impl TextureChunk {
Ok(())
}
- pub fn deactivate(mut self, device: &mut Device) {
+ pub fn deactivate(mut self, device: &mut Device, allocator: &mut DynamicAllocator) {
for img in self.sampled_images.drain(..) {
- img.deactivate(device);
+ img.deactivate(device, allocator);
}
}
}
diff --git a/stockton-render/src/draw/texture/image.rs b/stockton-render/src/draw/texture/image.rs
index 37e8ce8..bd8058b 100644
--- a/stockton-render/src/draw/texture/image.rs
+++ b/stockton-render/src/draw/texture/image.rs
@@ -23,13 +23,14 @@ use hal::{
buffer::Usage as BufUsage,
format::{Aspects, Format, Swizzle},
image::{SubresourceRange, Usage as ImgUsage, ViewKind},
- memory::{Dependencies as MemDependencies, Properties as MemProperties, Segment},
+ memory::{Dependencies as MemDependencies, Properties as MemProperties},
prelude::*,
queue::Submission,
MemoryTypeId,
};
use image::RgbaImage;
use std::{convert::TryInto, iter::once};
+use rendy_memory::{Allocator, Block};
use crate::draw::buffer::create_buffer;
use crate::types::*;
@@ -73,17 +74,18 @@ pub struct LoadedImage {
pub image_view: ManuallyDrop<ImageView>,
/// The memory backing the image
- memory: ManuallyDrop<Memory>,
+ memory: ManuallyDrop<DynamicBlock>,
}
pub fn create_image_view(
device: &mut Device,
adapter: &Adapter,
+ allocator: &mut DynamicAllocator,
format: Format,
usage: ImgUsage,
width: usize,
height: usize,
-) -> Result<(Memory, Image), &'static str> {
+) -> Result<(DynamicBlock, Image), &'static str> {
// Round up the size to align properly
let initial_row_size = PIXEL_SIZE * width;
let limits = adapter.physical_device.limits();
@@ -108,47 +110,37 @@ pub fn create_image_view(
.map_err(|_| "Couldn't create image")?;
// Allocate memory
- let memory = unsafe {
+ let (block, _) = unsafe {
let requirements = device.get_image_requirements(&image_ref);
- let memory_type_id = adapter
- .physical_device
- .memory_properties()
- .memory_types
- .iter()
- .enumerate()
- .find(|&(id, memory_type)| {
- requirements.type_mask & (1 << id) != 0
- && memory_type.properties.contains(MemProperties::DEVICE_LOCAL)
- })
- .map(|(id, _)| MemoryTypeId(id))
- .ok_or("Couldn't find a memory type for image memory")?;
-
- let memory = device
- .allocate_memory(memory_type_id, requirements.size)
- .map_err(|_| "Couldn't allocate image memory")?;
+ allocator.alloc(
+ device,
+ requirements.size,
+ requirements.alignment
+ )
+ }.map_err(|_| "Out of memory")?;
+ unsafe {
device
- .bind_image_memory(&memory, 0, &mut image_ref)
+ .bind_image_memory(&block.memory(), block.range().start, &mut image_ref)
.map_err(|_| "Couldn't bind memory to image")?;
+ }
- Ok(memory)
- }?;
-
- Ok((memory, image_ref))
+ Ok((block, image_ref))
}
impl LoadedImage {
pub fn new(
device: &mut Device,
adapter: &Adapter,
+ allocator: &mut DynamicAllocator,
format: Format,
usage: ImgUsage,
resources: SubresourceRange,
width: usize,
height: usize,
) -> Result<LoadedImage, &'static str> {
- let (memory, image_ref) = create_image_view(device, adapter, format, usage, width, height)?;
+ let (memory, image_ref) = create_image_view(device, adapter, allocator, format, usage, width, height)?;
// Create ImageView and sampler
let image_view = unsafe {
@@ -169,6 +161,7 @@ impl LoadedImage {
img: T,
device: &mut Device,
adapter: &Adapter,
+ allocator: &mut DynamicAllocator,
command_queue: &mut CommandQueue,
command_pool: &mut CommandPool,
) -> Result<(), &'static str> {
@@ -194,7 +187,7 @@ impl LoadedImage {
// Copy everything into it
unsafe {
let mapped_memory: *mut u8 = std::mem::transmute(device
- .map_memory(&staging_memory, Segment::ALL)
+ .map_memory(&staging_memory, 0..total_size)
.map_err(|_| "Couldn't map buffer memory")?);
for y in 0..img.height() as usize {
@@ -315,6 +308,7 @@ impl LoadedImage {
img: T,
device: &mut Device,
adapter: &Adapter,
+ allocator: &mut DynamicAllocator,
command_queue: &mut CommandQueue,
command_pool: &mut CommandPool,
format: Format,
@@ -323,6 +317,7 @@ impl LoadedImage {
let mut loaded_image = Self::new(
device,
adapter,
+ allocator,
format,
usage | ImgUsage::TRANSFER_DST,
SubresourceRange {
@@ -333,20 +328,20 @@ impl LoadedImage {
img.width() as usize,
img.height() as usize,
)?;
- loaded_image.load(img, device, adapter, command_queue, command_pool)?;
+ loaded_image.load(img, device, adapter, allocator, command_queue, command_pool)?;
Ok(loaded_image)
}
/// Properly frees/destroys all the objects in this struct
/// Dropping without doing this is a bad idea
- pub fn deactivate(self, device: &Device) {
+ pub fn deactivate(self, device: &mut Device, allocator: &mut DynamicAllocator) {
unsafe {
use core::ptr::read;
device.destroy_image_view(ManuallyDrop::into_inner(read(&self.image_view)));
device.destroy_image(ManuallyDrop::into_inner(read(&self.image)));
- device.free_memory(ManuallyDrop::into_inner(read(&self.memory)));
+ allocator.free(device, ManuallyDrop::into_inner(read(&self.memory)));
}
}
}
@@ -360,6 +355,7 @@ impl SampledImage {
pub fn new(
device: &mut Device,
adapter: &Adapter,
+ allocator: &mut DynamicAllocator,
format: Format,
usage: ImgUsage,
width: usize,
@@ -368,6 +364,7 @@ impl SampledImage {
let image = LoadedImage::new(
device,
adapter,
+ allocator,
format,
usage | ImgUsage::SAMPLED,
SubresourceRange {
@@ -396,6 +393,7 @@ impl SampledImage {
img: T,
device: &mut Device,
adapter: &Adapter,
+ allocator: &mut DynamicAllocator,
command_queue: &mut CommandQueue,
command_pool: &mut CommandPool,
format: Format,
@@ -404,6 +402,7 @@ impl SampledImage {
let mut sampled_image = SampledImage::new(
device,
adapter,
+ allocator,
format,
usage | ImgUsage::TRANSFER_DST,
img.width() as usize,
@@ -411,18 +410,299 @@ impl SampledImage {
)?;
sampled_image
.image
- .load(img, device, adapter, command_queue, command_pool)?;
+ .load(img, device, adapter, allocator, command_queue, command_pool)?;
Ok(sampled_image)
}
- pub fn deactivate(self, device: &mut Device) {
+ pub fn deactivate(self, device: &mut Device, allocator: &mut DynamicAllocator) {
unsafe {
use core::ptr::read;
device.destroy_sampler(ManuallyDrop::into_inner(read(&self.sampler)));
- ManuallyDrop::into_inner(read(&self.image)).deactivate(device);
+ ManuallyDrop::into_inner(read(&self.image)).deactivate(device, allocator);
}
}
}
+
+/// Holds an image that's loaded into GPU memory dedicated only to that image, bypassing the memory allocator.
+pub struct DedicatedLoadedImage {
+ /// The GPU Image handle
+ image: ManuallyDrop<Image>,
+
+ /// The full view of the image
+ pub image_view: ManuallyDrop<ImageView>,
+
+ /// The memory backing the image
+ memory: ManuallyDrop<Memory>,
+}
+
+
+impl DedicatedLoadedImage {
+ pub fn new(
+ device: &mut Device,
+ adapter: &Adapter,
+ format: Format,
+ usage: ImgUsage,
+ resources: SubresourceRange,
+ width: usize,
+ height: usize,
+ ) -> Result<DedicatedLoadedImage, &'static str> {
+ let (memory, image_ref) = {
+ // Round up the size to align properly
+ let initial_row_size = PIXEL_SIZE * width;
+ let limits = adapter.physical_device.limits();
+ let row_alignment_mask = limits.optimal_buffer_copy_pitch_alignment as u32 - 1;
+
+ let row_size = ((initial_row_size as u32 + row_alignment_mask) & !row_alignment_mask) as usize;
+ debug_assert!(row_size as usize >= initial_row_size);
+
+ // Make the image
+ let mut image_ref = unsafe {
+ use hal::image::{Kind, Tiling, ViewCapabilities};
+
+ device.create_image(
+ Kind::D2(width as u32, height as u32, 1, 1),
+ 1,
+ format,
+ Tiling::Optimal,
+ usage,
+ ViewCapabilities::empty(),
+ )
+ }
+ .map_err(|_| "Couldn't create image")?;
+
+ // Allocate memory
+
+ // Allocate memory
+ let memory = unsafe {
+ let requirements = device.get_image_requirements(&image_ref);
+
+ let memory_type_id = adapter
+ .physical_device
+ .memory_properties()
+ .memory_types
+ .iter()
+ .enumerate()
+ .find(|&(id, memory_type)| {
+ requirements.type_mask & (1 << id) != 0
+ && memory_type.properties.contains(MemProperties::DEVICE_LOCAL)
+ })
+ .map(|(id, _)| MemoryTypeId(id))
+ .ok_or("Couldn't find a memory type for image memory")?;
+
+ let memory = device
+ .allocate_memory(memory_type_id, requirements.size)
+ .map_err(|_| "Couldn't allocate image memory")?;
+
+ device
+ .bind_image_memory(&memory, 0, &mut image_ref)
+ .map_err(|_| "Couldn't bind memory to image")?;
+
+ Ok(memory)
+ }?;
+
+ Ok((memory, image_ref))
+ }?;
+
+ // Create ImageView and sampler
+ let image_view = unsafe {
+ device.create_image_view(&image_ref, ViewKind::D2, format, Swizzle::NO, resources)
+ }
+ .map_err(|_| "Couldn't create the image view!")?;
+
+ Ok(DedicatedLoadedImage {
+ image: ManuallyDrop::new(image_ref),
+ image_view: ManuallyDrop::new(image_view),
+ memory: ManuallyDrop::new(memory),
+ })
+ }
+
+ /// Load the given image
+ pub fn load<T: LoadableImage>(
+ &mut self,
+ img: T,
+ device: &mut Device,
+ adapter: &Adapter,
+ command_queue: &mut CommandQueue,
+ command_pool: &mut CommandPool,
+ ) -> Result<(), &'static str> {
+ let initial_row_size = PIXEL_SIZE * img.width() as usize;
+ let limits = adapter.physical_device.limits();
+ let row_alignment_mask = limits.optimal_buffer_copy_pitch_alignment as u32 - 1;
+
+ let row_size =
+ ((initial_row_size as u32 + row_alignment_mask) & !row_alignment_mask) as usize;
+ let total_size = (row_size * (img.height() as usize)) as u64;
+ debug_assert!(row_size as usize >= initial_row_size);
+
+ // Make a staging buffer
+ let (staging_buffer, staging_memory) = create_buffer(
+ device,
+ adapter,
+ BufUsage::TRANSFER_SRC,
+ MemProperties::CPU_VISIBLE | MemProperties::COHERENT,
+ total_size,
+ )
+ .map_err(|_| "Couldn't create staging buffer")?;
+
+ // Copy everything into it
+ unsafe {
+ let mapped_memory: *mut u8 = std::mem::transmute(device
+ .map_memory(&staging_memory, 0..total_size)
+ .map_err(|_| "Couldn't map buffer memory")?);
+
+ for y in 0..img.height() as usize {
+ let dest_base: isize = (y * row_size).try_into().unwrap();
+ img.copy_row(y as u32, mapped_memory.offset(dest_base));
+ }
+
+ device.unmap_memory(&staging_memory);
+ }
+
+ // Copy from staging to image memory
+ let buf = unsafe {
+ use hal::command::{BufferImageCopy, CommandBufferFlags};
+ use hal::image::{Access, Extent, Layout, Offset, SubresourceLayers};
+ use hal::memory::Barrier;
+ use hal::pso::PipelineStage;
+
+ // Get a command buffer
+ let mut buf = command_pool.allocate_one(hal::command::Level::Primary);
+ buf.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT);
+
+ // Setup the layout of our image for copying
+ let image_barrier = Barrier::Image {
+ states: (Access::empty(), Layout::Undefined)
+ ..(Access::TRANSFER_WRITE, Layout::TransferDstOptimal),
+ target: &(*self.image),
+ families: None,
+ range: SubresourceRange {
+ aspects: Aspects::COLOR,
+ levels: 0..1,
+ layers: 0..1,
+ },
+ };
+ buf.pipeline_barrier(
+ PipelineStage::TOP_OF_PIPE..PipelineStage::TRANSFER,
+ MemDependencies::empty(),
+ &[image_barrier],
+ );
+
+ // Copy from buffer to image
+ buf.copy_buffer_to_image(
+ &staging_buffer,
+ &(*self.image),
+ Layout::TransferDstOptimal,
+ &[BufferImageCopy {
+ buffer_offset: 0,
+ buffer_width: (row_size / PIXEL_SIZE) as u32,
+ buffer_height: img.height(),
+ image_layers: SubresourceLayers {
+ aspects: Aspects::COLOR,
+ level: 0,
+ layers: 0..1,
+ },
+ image_offset: Offset { x: 0, y: 0, z: 0 },
+ image_extent: Extent {
+ width: img.width(),
+ height: img.height(),
+ depth: 1,
+ },
+ }],
+ );
+
+ // Setup the layout of our image for shaders
+ let image_barrier = Barrier::Image {
+ states: (Access::TRANSFER_WRITE, Layout::TransferDstOptimal)
+ ..(Access::SHADER_READ, Layout::ShaderReadOnlyOptimal),
+ target: &(*self.image),
+ families: None,
+ range: SubresourceRange {
+ aspects: Aspects::COLOR,
+ levels: 0..1,
+ layers: 0..1,
+ },
+ };
+
+ buf.pipeline_barrier(
+ PipelineStage::TRANSFER..PipelineStage::FRAGMENT_SHADER,
+ MemDependencies::empty(),
+ &[image_barrier],
+ );
+
+ buf.finish();
+
+ buf
+ };
+
+ // Submit our commands and wait for them to finish
+ unsafe {
+ let setup_finished = device.create_fence(false).unwrap();
+ command_queue.submit::<_, _, Semaphore, _, _>(
+ Submission {
+ command_buffers: &[&buf],
+ wait_semaphores: std::iter::empty::<_>(),
+ signal_semaphores: std::iter::empty::<_>(),
+ },
+ Some(&setup_finished),
+ );
+
+ device
+ .wait_for_fence(&setup_finished, core::u64::MAX)
+ .unwrap();
+ device.destroy_fence(setup_finished);
+ };
+
+ // Clean up temp resources
+ unsafe {
+ command_pool.free(once(buf));
+
+ device.free_memory(staging_memory);
+ device.destroy_buffer(staging_buffer);
+ }
+
+ Ok(())
+ }
+
+ /// Load the given image into a new buffer
+ pub fn load_into_new<T: LoadableImage>(
+ img: T,
+ device: &mut Device,
+ adapter: &Adapter,
+ command_queue: &mut CommandQueue,
+ command_pool: &mut CommandPool,
+ format: Format,
+ usage: ImgUsage,
+ ) -> Result<DedicatedLoadedImage, &'static str> {
+ let mut loaded_image = Self::new(
+ device,
+ adapter,
+ format,
+ usage | ImgUsage::TRANSFER_DST,
+ SubresourceRange {
+ aspects: Aspects::COLOR,
+ levels: 0..1,
+ layers: 0..1,
+ },
+ img.width() as usize,
+ img.height() as usize,
+ )?;
+ loaded_image.load(img, device, adapter, command_queue, command_pool)?;
+
+ Ok(loaded_image)
+ }
+
+ /// Properly frees/destroys all the objects in this struct
+ /// Dropping without doing this is a bad idea
+ pub fn deactivate(self, device: &mut Device) {
+ unsafe {
+ use core::ptr::read;
+
+ device.destroy_image_view(ManuallyDrop::into_inner(read(&self.image_view)));
+ device.destroy_image(ManuallyDrop::into_inner(read(&self.image)));
+ device.free_memory(ManuallyDrop::into_inner(read(&self.memory)));
+ }
+ }
+} \ No newline at end of file
diff --git a/stockton-render/src/draw/texture/loader.rs b/stockton-render/src/draw/texture/loader.rs
index 30c89dc..9385d96 100644
--- a/stockton-render/src/draw/texture/loader.rs
+++ b/stockton-render/src/draw/texture/loader.rs
@@ -47,6 +47,7 @@ impl TextureStore {
pub fn new_empty(
device: &mut Device,
adapter: &mut Adapter,
+ allocator: &mut DynamicAllocator,
command_queue: &mut CommandQueue,
command_pool: &mut CommandPool,
size: usize,
@@ -64,7 +65,7 @@ impl TextureStore {
// Descriptor pool, where we get our sets from
let mut descriptor_pool = unsafe {
use hal::pso::{
- DescriptorPoolCreateFlags, DescriptorRangeDesc, DescriptorType, ImageDescriptorType,
+ DescriptorPoolCreateFlags, DescriptorRangeDesc, DescriptorType,
};
device
@@ -72,11 +73,7 @@ impl TextureStore {
num_chunks,
&[
DescriptorRangeDesc {
- ty: DescriptorType::Image {
- ty: ImageDescriptorType::Sampled {
- with_sampler: false,
- },
- },
+ ty: DescriptorType::SampledImage,
count: rounded_size,
},
DescriptorRangeDesc {
@@ -95,18 +92,14 @@ impl TextureStore {
// Layout of our descriptor sets
let descriptor_set_layout = unsafe {
use hal::pso::{
- DescriptorSetLayoutBinding, DescriptorType, ImageDescriptorType, ShaderStageFlags,
+ DescriptorSetLayoutBinding, DescriptorType, ShaderStageFlags,
};
device.create_descriptor_set_layout(
&[
DescriptorSetLayoutBinding {
binding: 0,
- ty: DescriptorType::Image {
- ty: ImageDescriptorType::Sampled {
- with_sampler: false,
- },
- },
+ ty: DescriptorType::SampledImage,
count: CHUNK_SIZE,
stage_flags: ShaderStageFlags::FRAGMENT,
immutable_samplers: false,
@@ -140,6 +133,7 @@ impl TextureStore {
chunks.push(TextureChunk::new_empty(
device,
adapter,
+ allocator,
command_queue,
command_pool,
descriptor_set,
@@ -159,6 +153,7 @@ impl TextureStore {
pub fn new<T: HasTextures>(
device: &mut Device,
adapter: &mut Adapter,
+ allocator: &mut DynamicAllocator,
command_queue: &mut CommandQueue,
command_pool: &mut CommandPool,
file: &T,
@@ -177,7 +172,7 @@ impl TextureStore {
// Descriptor pool, where we get our sets from
let mut descriptor_pool = unsafe {
use hal::pso::{
- DescriptorPoolCreateFlags, DescriptorRangeDesc, DescriptorType, ImageDescriptorType,
+ DescriptorPoolCreateFlags, DescriptorRangeDesc, DescriptorType,
};
device
@@ -185,11 +180,7 @@ impl TextureStore {
num_chunks,
&[
DescriptorRangeDesc {
- ty: DescriptorType::Image {
- ty: ImageDescriptorType::Sampled {
- with_sampler: false,
- },
- },
+ ty: DescriptorType::SampledImage,
count: rounded_size,
},
DescriptorRangeDesc {
@@ -208,18 +199,14 @@ impl TextureStore {
// Layout of our descriptor sets
let descriptor_set_layout = unsafe {
use hal::pso::{
- DescriptorSetLayoutBinding, DescriptorType, ImageDescriptorType, ShaderStageFlags,
+ DescriptorSetLayoutBinding, DescriptorType, ShaderStageFlags,
};
device.create_descriptor_set_layout(
&[
DescriptorSetLayoutBinding {
binding: 0,
- ty: DescriptorType::Image {
- ty: ImageDescriptorType::Sampled {
- with_sampler: false,
- },
- },
+ ty: DescriptorType::SampledImage,
count: CHUNK_SIZE,
stage_flags: ShaderStageFlags::FRAGMENT,
immutable_samplers: false,
@@ -254,6 +241,7 @@ impl TextureStore {
chunks.push(TextureChunk::new(
device,
adapter,
+ allocator,
command_queue,
command_pool,
descriptor_set,
@@ -272,12 +260,12 @@ impl TextureStore {
}
/// Call this before dropping
- pub fn deactivate(mut self, device: &mut Device) {
+ pub fn deactivate(mut self, device: &mut Device, allocator: &mut DynamicAllocator) {
unsafe {
use core::ptr::read;
for chunk in self.chunks.into_vec().drain(..) {
- chunk.deactivate(device)
+ chunk.deactivate(device, allocator);
}
self.descriptor_pool.reset();
@@ -299,6 +287,7 @@ impl TextureStore {
img: T,
device: &mut Device,
adapter: &mut Adapter,
+ allocator: &mut DynamicAllocator,
command_queue: &mut CommandQueue,
command_pool: &mut CommandPool,
) -> Result<(), &'static str> {
@@ -309,6 +298,7 @@ impl TextureStore {
idx % CHUNK_SIZE,
device,
adapter,
+ allocator,
command_queue,
command_pool,
)
diff --git a/stockton-render/src/draw/ui/pipeline.rs b/stockton-render/src/draw/ui/pipeline.rs
index 878d8cd..f608173 100644
--- a/stockton-render/src/draw/ui/pipeline.rs
+++ b/stockton-render/src/draw/ui/pipeline.rs
@@ -97,7 +97,7 @@ impl UIPipeline {
let external_dependency = SubpassDependency {
flags: Dependencies::empty(),
- passes: None..Some(0),
+ passes: SubpassRef::External..SubpassRef::Pass(0),
stages: PipelineStage::COLOR_ATTACHMENT_OUTPUT
..(PipelineStage::COLOR_ATTACHMENT_OUTPUT
| PipelineStage::EARLY_FRAGMENT_TESTS),
@@ -198,7 +198,6 @@ impl UIPipeline {
depth_clamping: false,
depth_bias: None,
conservative: true,
- line_width: hal::pso::State::Static(1.0),
};
// Depth stencil
diff --git a/stockton-render/src/draw/ui/texture.rs b/stockton-render/src/draw/ui/texture.rs
index ce18f02..52580e5 100755
--- a/stockton-render/src/draw/ui/texture.rs
+++ b/stockton-render/src/draw/ui/texture.rs
@@ -43,12 +43,13 @@ impl LoadableImage for &Texture {
pub fn ensure_textures(texture_store: &mut TextureStore, ui: &mut UIState,
device: &mut Device,
adapter: &mut Adapter,
+ allocator: &mut DynamicAllocator,
command_queue: &mut CommandQueue,
command_pool: &mut CommandPool) {
let tex = ui.ctx.texture();
if tex.version != ui.last_tex_ver {
- texture_store.put_texture(0, &*tex, device, adapter, command_queue, command_pool).unwrap(); // TODO
+ texture_store.put_texture(0, &*tex, device, adapter, allocator, command_queue, command_pool).unwrap(); // TODO
ui.last_tex_ver = tex.version;
}
} \ No newline at end of file
diff --git a/stockton-render/src/draw/utils.rs b/stockton-render/src/draw/utils.rs
new file mode 100644
index 0000000..e175e47
--- /dev/null
+++ b/stockton-render/src/draw/utils.rs
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) Oscar Shrimpton 2020
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+use crate::types::*;
+use hal::{
+ memory::{Properties as MemProperties},
+ MemoryTypeId,
+ prelude::*,
+};
+
+pub fn find_memory_type_id(adapter: &Adapter, type_mask: u64, props: MemProperties) -> Option<MemoryTypeId> {
+ adapter
+ .physical_device
+ .memory_properties()
+ .memory_types
+ .iter()
+ .enumerate()
+ .find(|&(id, memory_type)| {
+ type_mask & (1 << id) != 0 &&
+ memory_type.properties.contains(props)
+ })
+ .map(|(id, _)| MemoryTypeId(id))
+
+} \ No newline at end of file
diff --git a/stockton-render/src/error.rs b/stockton-render/src/error.rs
index e0de55d..654df4a 100644
--- a/stockton-render/src/error.rs
+++ b/stockton-render/src/error.rs
@@ -41,7 +41,7 @@ pub enum CreationError {
BufferNoMemory,
SwapchainError(hal::window::CreationError),
- ImageViewError(hal::image::ViewCreationError),
+ ImageViewError(hal::image::ViewError),
BadDataError,
}
diff --git a/stockton-render/src/types.rs b/stockton-render/src/types.rs
index 56a71b7..f6187c2 100644
--- a/stockton-render/src/types.rs
+++ b/stockton-render/src/types.rs
@@ -41,3 +41,6 @@ pub type RenderPass = <back::Backend as hal::Backend>::RenderPass;
pub type Adapter = hal::adapter::Adapter<back::Backend>;
pub type QueueGroup = hal::queue::QueueGroup<back::Backend>;
+
+pub type DynamicAllocator = rendy_memory::DynamicAllocator<back::Backend>;
+pub type DynamicBlock = rendy_memory::DynamicBlock<back::Backend>; \ No newline at end of file