mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2025-02-14 08:03:12 +00:00
Specialize the gpu_access function ; one for buffers one for images
This commit is contained in:
parent
04c462b5a2
commit
43d9c80888
@ -17,6 +17,7 @@
|
||||
//!
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::ops::Range;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -39,6 +40,32 @@ use VulkanPointers;
|
||||
use check_errors;
|
||||
use vk;
|
||||
|
||||
pub unsafe trait BufferResource: Resource {
|
||||
/// Instructs the resource that it is going to be used by the GPU soon in the future. The
|
||||
/// function should block if the memory is currently being accessed by the CPU.
|
||||
///
|
||||
/// `write` indicates whether the GPU will write to the memory. If `false`, then it will only
|
||||
/// be written.
|
||||
///
|
||||
/// `queue` is the queue where the command buffer that accesses the memory will be submitted.
|
||||
/// If the `gpu_access` function submits something to that queue, it will thus be submitted
|
||||
/// beforehand. This behavior can be used for example to submit sparse binding commands.
|
||||
///
|
||||
/// `fence` is a fence that will be signaled when this GPU access will stop. It should be
|
||||
/// waited upon whenever the user wants to read this memory from the CPU. If `requires_fence`
|
||||
/// returned false, then this value will be `None`.
|
||||
///
|
||||
/// `semaphore` is a semaphore that will be signaled when this GPU access will stop. This value
|
||||
/// is intended to be returned later, in a follow-up call to `gpu_access`. If
|
||||
/// `requires_semaphore` returned false, then this value will be `None`.
|
||||
///
|
||||
/// The function can return a semaphore which will be waited up by the GPU before the
|
||||
/// work starts.
|
||||
fn gpu_access(&self, write: bool, offset: usize, size: usize, queue: &mut Queue,
|
||||
fence: Option<Arc<Fence>>, semaphore: Option<Arc<Semaphore>>)
|
||||
-> Option<Arc<Semaphore>>;
|
||||
}
|
||||
|
||||
pub struct Buffer<T: ?Sized, M> {
|
||||
marker: PhantomData<T>,
|
||||
inner: Inner<M>,
|
||||
@ -205,6 +232,17 @@ impl<T: ?Sized, M> Buffer<T, M> {
|
||||
|
||||
pub fn write(&self) -> Result<ReadWrite, > {
|
||||
}*/
|
||||
|
||||
/// Builds a slice without checking neither the type nor the range.
|
||||
#[inline]
|
||||
pub unsafe fn unchecked_slice<U: ?Sized>(&self, range: Range<usize>) -> BufferSlice<U, M> {
|
||||
BufferSlice {
|
||||
marker: PhantomData,
|
||||
inner: &self.inner,
|
||||
offset: range.start,
|
||||
size: range.end - range.start,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, M> Buffer<[T], M> {
|
||||
@ -230,12 +268,16 @@ unsafe impl<T: ?Sized, M> Resource for Buffer<T, M> where M: MemorySourceChunk {
|
||||
fn sharing_mode(&self) -> &SharingMode {
|
||||
&self.inner.sharing
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: ?Sized, M> BufferResource for Buffer<T, M> where M: MemorySourceChunk {
|
||||
#[inline]
|
||||
fn gpu_access(&self, write: bool, queue: &mut Queue, fence: Option<Arc<Fence>>,
|
||||
semaphore: Option<Arc<Semaphore>>) -> Option<Arc<Semaphore>>
|
||||
fn gpu_access(&self, write: bool, offset: usize, size: usize, queue: &mut Queue,
|
||||
fence: Option<Arc<Fence>>, semaphore: Option<Arc<Semaphore>>)
|
||||
-> Option<Arc<Semaphore>>
|
||||
{
|
||||
self.inner.memory.gpu_access(write, ChunkRange::All, queue, fence, semaphore)
|
||||
self.inner.memory.gpu_access(write, ChunkRange::Range { offset: offset, size: size },
|
||||
queue, fence, semaphore)
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,23 +429,6 @@ pub struct BufferSlice<'a, T: ?Sized + 'a, M: 'a> {
|
||||
size: usize,
|
||||
}
|
||||
|
||||
unsafe impl<'a, T: ?Sized + 'a, M: 'a> Resource for BufferSlice<'a, T, M>
|
||||
where M: MemorySourceChunk
|
||||
{
|
||||
#[inline]
|
||||
fn sharing_mode(&self) -> &SharingMode {
|
||||
&self.inner.sharing
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn gpu_access(&self, write: bool, queue: &mut Queue, fence: Option<Arc<Fence>>,
|
||||
semaphore: Option<Arc<Semaphore>>) -> Option<Arc<Semaphore>>
|
||||
{
|
||||
self.inner.memory.gpu_access(write, ChunkRange::Range { offset: self.offset, size: self.size },
|
||||
queue, fence, semaphore)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + 'a, M: 'a> BufferSlice<'a, T, M> {
|
||||
/// Returns the offset of that slice within the buffer.
|
||||
#[inline]
|
||||
|
@ -4,6 +4,7 @@ use std::sync::Arc;
|
||||
|
||||
use buffer::Buffer;
|
||||
use buffer::BufferSlice;
|
||||
use buffer::BufferResource;
|
||||
use command_buffer::CommandBufferPool;
|
||||
use command_buffer::DynamicState;
|
||||
use device::Queue;
|
||||
@ -36,10 +37,10 @@ pub struct InnerCommandBufferBuilder {
|
||||
cmd: Option<vk::CommandBuffer>,
|
||||
|
||||
// List of all resources that are used by this command buffer.
|
||||
resources: Vec<Arc<Resource>>,
|
||||
buffer_resources: Vec<Arc<BufferResource>>,
|
||||
|
||||
// Same as `resources`. Should be merged with `resources` once Rust allows turning a
|
||||
// `Arc<ImageResource>` into an `Arc<Resource>`.
|
||||
// `Arc<ImageResource>` into an `Arc<BufferResource>`.
|
||||
image_resources: Vec<Arc<ImageResource>>,
|
||||
|
||||
// List of pipelines that are used by this command buffer.
|
||||
@ -100,7 +101,7 @@ impl InnerCommandBufferBuilder {
|
||||
device: device.clone(),
|
||||
pool: pool.clone(),
|
||||
cmd: Some(cmd),
|
||||
resources: Vec::new(),
|
||||
buffer_resources: Vec::new(),
|
||||
image_resources: Vec::new(),
|
||||
pipelines: Vec::new(),
|
||||
graphics_pipeline: None,
|
||||
@ -124,7 +125,8 @@ impl InnerCommandBufferBuilder {
|
||||
for cb in iter {
|
||||
command_buffers.push(cb.cmd);
|
||||
for p in cb.pipelines.iter() { self.pipelines.push(p.clone()); }
|
||||
for r in cb.resources.iter() { self.resources.push(r.clone()); }
|
||||
for r in cb.buffer_resources.iter() { self.buffer_resources.push(r.clone()); }
|
||||
for r in cb.image_resources.iter() { self.image_resources.push(r.clone()); }
|
||||
}
|
||||
|
||||
let vk = self.device.pointers();
|
||||
@ -203,7 +205,7 @@ impl InnerCommandBufferBuilder {
|
||||
assert!(size % 4 == 0);
|
||||
assert!(buffer.usage_transfer_dest());
|
||||
|
||||
self.resources.push(buffer.clone());
|
||||
self.buffer_resources.push(buffer.clone());
|
||||
|
||||
// FIXME: check that the queue family supports transfers
|
||||
// FIXME: check queue family of the buffer
|
||||
@ -251,8 +253,8 @@ impl InnerCommandBufferBuilder {
|
||||
vk.CmdCopyBuffer(self.cmd.unwrap(), source.internal_object(),
|
||||
destination.internal_object(), 1, ©);
|
||||
|
||||
self.resources.push(source.clone());
|
||||
self.resources.push(destination.clone());
|
||||
self.buffer_resources.push(source.clone());
|
||||
self.buffer_resources.push(destination.clone());
|
||||
}
|
||||
|
||||
self
|
||||
@ -427,7 +429,7 @@ impl InnerCommandBufferBuilder {
|
||||
device: self.device.clone(),
|
||||
pool: self.pool.clone(),
|
||||
cmd: cmd,
|
||||
resources: mem::replace(&mut self.resources, Vec::new()),
|
||||
buffer_resources: mem::replace(&mut self.buffer_resources, Vec::new()),
|
||||
image_resources: mem::replace(&mut self.image_resources, Vec::new()),
|
||||
pipelines: mem::replace(&mut self.pipelines, Vec::new()),
|
||||
})
|
||||
@ -454,7 +456,7 @@ pub struct InnerCommandBuffer {
|
||||
device: Arc<Device>,
|
||||
pool: Arc<CommandBufferPool>,
|
||||
cmd: vk::CommandBuffer,
|
||||
resources: Vec<Arc<Resource>>,
|
||||
buffer_resources: Vec<Arc<BufferResource>>,
|
||||
image_resources: Vec<Arc<ImageResource>>,
|
||||
pipelines: Vec<Arc<GenericPipeline>>,
|
||||
}
|
||||
@ -478,7 +480,7 @@ impl InnerCommandBuffer {
|
||||
|
||||
// FIXME: fence shouldn't be discarded, as it could be ignored by resources and
|
||||
// destroyed while in use
|
||||
let fence = if self.resources.iter().any(|r| r.requires_fence()) ||
|
||||
let fence = if self.buffer_resources.iter().any(|r| r.requires_fence()) ||
|
||||
self.image_resources.iter().any(|r| r.requires_fence())
|
||||
{
|
||||
Some(try!(Fence::new(queue.device())))
|
||||
@ -496,33 +498,48 @@ impl InnerCommandBuffer {
|
||||
// they should be included in a return value instead
|
||||
// FIXME: same for post-semaphores
|
||||
|
||||
macro_rules! process {
|
||||
($iter:expr) => (
|
||||
for resource in $iter {
|
||||
let post_semaphore = if resource.requires_semaphore() {
|
||||
let semaphore = try!(Semaphore::new(queue.device()));
|
||||
post_semaphores.push(semaphore.clone());
|
||||
post_semaphores_ids.push(semaphore.internal_object());
|
||||
Some(semaphore)
|
||||
for resource in self.buffer_resources.iter() {
|
||||
let post_semaphore = if resource.requires_semaphore() {
|
||||
let semaphore = try!(Semaphore::new(queue.device()));
|
||||
post_semaphores.push(semaphore.clone());
|
||||
post_semaphores_ids.push(semaphore.internal_object());
|
||||
Some(semaphore)
|
||||
|
||||
} else {
|
||||
None
|
||||
};
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// FIXME: for the moment `write` is always true ; that shouldn't be the case
|
||||
let sem = resource.gpu_access(true, queue, fence.clone(), post_semaphore);
|
||||
// FIXME: for the moment `write` is always true ; that shouldn't be the case
|
||||
// FIXME: wrong offset and size
|
||||
let sem = resource.gpu_access(true, 0, 18, queue, fence.clone(), post_semaphore);
|
||||
|
||||
if let Some(s) = sem {
|
||||
pre_semaphores_ids.push(s.internal_object());
|
||||
pre_semaphores_stages.push(vk::PIPELINE_STAGE_TOP_OF_PIPE_BIT); // TODO:
|
||||
pre_semaphores.push(s);
|
||||
}
|
||||
}
|
||||
);
|
||||
if let Some(s) = sem {
|
||||
pre_semaphores_ids.push(s.internal_object());
|
||||
pre_semaphores_stages.push(vk::PIPELINE_STAGE_TOP_OF_PIPE_BIT); // TODO:
|
||||
pre_semaphores.push(s);
|
||||
}
|
||||
}
|
||||
|
||||
process!(self.resources.iter());
|
||||
process!(self.image_resources.iter());
|
||||
for resource in self.image_resources.iter() {
|
||||
let post_semaphore = if resource.requires_semaphore() {
|
||||
let semaphore = try!(Semaphore::new(queue.device()));
|
||||
post_semaphores.push(semaphore.clone());
|
||||
post_semaphores_ids.push(semaphore.internal_object());
|
||||
Some(semaphore)
|
||||
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// FIXME: for the moment `write` is always true ; that shouldn't be the case
|
||||
let sem = resource.gpu_access(true, queue, fence.clone(), post_semaphore);
|
||||
|
||||
if let Some(s) = sem {
|
||||
pre_semaphores_ids.push(s.internal_object());
|
||||
pre_semaphores_stages.push(vk::PIPELINE_STAGE_TOP_OF_PIPE_BIT); // TODO:
|
||||
pre_semaphores.push(s);
|
||||
}
|
||||
}
|
||||
|
||||
let infos = vk::SubmitInfo {
|
||||
sType: vk::STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
|
@ -43,6 +43,29 @@ pub unsafe trait ImageResource: Resource {
|
||||
/// command buffer, it is switched from this default layout to something else (if necessary),
|
||||
/// then back again to the default.
|
||||
fn default_layout(&self) -> Layout;
|
||||
|
||||
/// Instructs the resource that it is going to be used by the GPU soon in the future. The
|
||||
/// function should block if the memory is currently being accessed by the CPU.
|
||||
///
|
||||
/// `write` indicates whether the GPU will write to the memory. If `false`, then it will only
|
||||
/// be written.
|
||||
///
|
||||
/// `queue` is the queue where the command buffer that accesses the memory will be submitted.
|
||||
/// If the `gpu_access` function submits something to that queue, it will thus be submitted
|
||||
/// beforehand. This behavior can be used for example to submit sparse binding commands.
|
||||
///
|
||||
/// `fence` is a fence that will be signaled when this GPU access will stop. It should be
|
||||
/// waited upon whenever the user wants to read this memory from the CPU. If `requires_fence`
|
||||
/// returned false, then this value will be `None`.
|
||||
///
|
||||
/// `semaphore` is a semaphore that will be signaled when this GPU access will stop. This value
|
||||
/// is intended to be returned later, in a follow-up call to `gpu_access`. If
|
||||
/// `requires_semaphore` returned false, then this value will be `None`.
|
||||
///
|
||||
/// The function can return a semaphore which will be waited up by the GPU before the
|
||||
/// work starts.
|
||||
fn gpu_access(&self, write: bool, queue: &mut Queue, fence: Option<Arc<Fence>>,
|
||||
semaphore: Option<Arc<Semaphore>>) -> Option<Arc<Semaphore>>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
@ -387,14 +410,6 @@ unsafe impl<Ty, F, M> Resource for Image<Ty, F, M>
|
||||
fn sharing_mode(&self) -> &SharingMode {
|
||||
&self.sharing
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn gpu_access(&self, write: bool, queue: &mut Queue, fence: Option<Arc<Fence>>,
|
||||
semaphore: Option<Arc<Semaphore>>) -> Option<Arc<Semaphore>>
|
||||
{
|
||||
// FIXME: if the image is in its initial transition phase, we need to a semaphore
|
||||
self.memory.gpu_access(write, ChunkRange::All, queue, fence, semaphore)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<Ty, F, M> ImageResource for Image<Ty, F, M>
|
||||
@ -404,6 +419,14 @@ unsafe impl<Ty, F, M> ImageResource for Image<Ty, F, M>
|
||||
fn default_layout(&self) -> Layout {
|
||||
self.layout
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn gpu_access(&self, write: bool, queue: &mut Queue, fence: Option<Arc<Fence>>,
|
||||
semaphore: Option<Arc<Semaphore>>) -> Option<Arc<Semaphore>>
|
||||
{
|
||||
// FIXME: if the image is in its initial transition phase, we need to a semaphore
|
||||
self.memory.gpu_access(write, ChunkRange::All, queue, fence, semaphore)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ty, F, M> Drop for Image<Ty, F, M>
|
||||
@ -665,13 +688,6 @@ unsafe impl<Ty, F, M> Resource for ImageView<Ty, F, M>
|
||||
fn sharing_mode(&self) -> &SharingMode {
|
||||
self.image.sharing_mode()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn gpu_access(&self, write: bool, queue: &mut Queue, fence: Option<Arc<Fence>>,
|
||||
semaphore: Option<Arc<Semaphore>>) -> Option<Arc<Semaphore>>
|
||||
{
|
||||
self.image.gpu_access(write, queue, fence, semaphore)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<Ty, F, M> ImageResource for ImageView<Ty, F, M>
|
||||
@ -681,6 +697,13 @@ unsafe impl<Ty, F, M> ImageResource for ImageView<Ty, F, M>
|
||||
fn default_layout(&self) -> Layout {
|
||||
self.image.default_layout()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn gpu_access(&self, write: bool, queue: &mut Queue, fence: Option<Arc<Fence>>,
|
||||
semaphore: Option<Arc<Semaphore>>) -> Option<Arc<Semaphore>>
|
||||
{
|
||||
self.image.gpu_access(write, queue, fence, semaphore)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ty, F, M> Drop for ImageView<Ty, F, M> where Ty: ImageTypeMarker {
|
||||
|
@ -45,7 +45,7 @@ impl Swapchain {
|
||||
///
|
||||
/// See also the `Surface::get_capabilities` function which returns the values that are
|
||||
/// supported by the implementation. All the parameters that you pass to `Swapchain::new`
|
||||
/// must be supported.
|
||||
/// must be supported.
|
||||
///
|
||||
/// The `clipped` parameter indicates whether the implementation is allowed to discard
|
||||
/// rendering operations that affect regions of the surface which aren't visible. This is
|
||||
|
@ -39,29 +39,6 @@ pub unsafe trait Resource {
|
||||
fn requires_semaphore(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Instructs the resource that it is going to be used by the GPU soon in the future. The
|
||||
/// function should block if the memory is currently being accessed by the CPU.
|
||||
///
|
||||
/// `write` indicates whether the GPU will write to the memory. If `false`, then it will only
|
||||
/// be written.
|
||||
///
|
||||
/// `queue` is the queue where the command buffer that accesses the memory will be submitted.
|
||||
/// If the `gpu_access` function submits something to that queue, it will thus be submitted
|
||||
/// beforehand. This behavior can be used for example to submit sparse binding commands.
|
||||
///
|
||||
/// `fence` is a fence that will be signaled when this GPU access will stop. It should be
|
||||
/// waited upon whenever the user wants to read this memory from the CPU. If `requires_fence`
|
||||
/// returned false, then this value will be `None`.
|
||||
///
|
||||
/// `semaphore` is a semaphore that will be signaled when this GPU access will stop. This value
|
||||
/// is intended to be returned later, in a follow-up call to `gpu_access`. If
|
||||
/// `requires_semaphore` returned false, then this value will be `None`.
|
||||
///
|
||||
/// The function can return a semaphore which will be waited up by the GPU before the
|
||||
/// work starts.
|
||||
fn gpu_access(&self, write: bool, queue: &mut Queue, fence: Option<Arc<Fence>>,
|
||||
semaphore: Option<Arc<Semaphore>>) -> Option<Arc<Semaphore>>;
|
||||
}
|
||||
|
||||
/// Declares in which queue(s) a resource can be used.
|
||||
|
Loading…
Reference in New Issue
Block a user