rafx_framework/upload/
buffer_upload.rs

1use rafx_api::extra::upload::{RafxTransferUpload, RafxUploadError};
2use rafx_api::{
3    RafxBarrierQueueTransition, RafxBuffer, RafxBufferBarrier, RafxBufferDef,
4    RafxCmdCopyBufferToBufferParams, RafxDeviceContext, RafxMemoryUsage, RafxOffsetSize,
5    RafxResourceState, RafxResourceType,
6};
7
8pub fn enqueue_load_buffer(
9    device_context: &RafxDeviceContext,
10    upload: &mut RafxTransferUpload,
11    // transfer_queue_family_index: u32,
12    // dst_queue_family_index: u32,
13    resource_type: RafxResourceType,
14    data: &[u8],
15    dst_buffer: Option<&RafxBuffer>,
16    dst_byte_offset: u64,
17    //TODO: params?
18) -> Result<Option<RafxBuffer>, RafxUploadError> {
19    // Arbitrary, not sure if there is any requirement
20    const REQUIRED_ALIGNMENT: usize = 16;
21
22    // Push data into the staging buffer
23    let src_byte_offset = upload.push(data, REQUIRED_ALIGNMENT)?;
24    let size = data.len() as u64;
25
26    // Allocate a GPU buffer
27    let mut new_buffer = None;
28    let (dst_buffer, barrier_offset_size) = if let Some(dst_buffer) = dst_buffer {
29        if device_context.is_dx12() {
30            //DX12TODO: Partial barriers not supported on DX12
31            (dst_buffer, None)
32        } else {
33            let barrier_offset_size = RafxOffsetSize {
34                size: data.len() as u64,
35                byte_offset: dst_byte_offset,
36            };
37            (dst_buffer, Some(barrier_offset_size))
38        }
39    } else {
40        new_buffer = Some(device_context.create_buffer(&RafxBufferDef {
41            size,
42            memory_usage: RafxMemoryUsage::GpuOnly,
43            queue_type: upload.transfer_queue().queue_type(),
44            resource_type,
45            ..Default::default()
46        })?);
47        (new_buffer.as_ref().unwrap(), None)
48    };
49
50    // DX12TODO: Updating just part of the buffer while it is in use elsewhere will require
51    // extended barrier support. So on DX12 use the graphics queue for these updates.
52    // Also for other APIs I think we still need to do a proper queue transition or make the buffer
53    // be non-exclusive, and I don't think we're doing that here.
54    let use_transfer_queue = new_buffer.is_some();
55
56    //println!("upload to buffer {:?} offset: {}", dst_buffer, dst_byte_offset);
57
58    let copy_params = RafxCmdCopyBufferToBufferParams {
59        src_byte_offset,
60        dst_byte_offset,
61        size: data.len() as u64,
62    };
63
64    if use_transfer_queue {
65        upload.transfer_command_buffer().cmd_copy_buffer_to_buffer(
66            &upload.staging_buffer(),
67            &dst_buffer,
68            &copy_params,
69        )?;
70
71        upload.transfer_command_buffer().cmd_resource_barrier(
72            &[RafxBufferBarrier {
73                buffer: &dst_buffer,
74                src_state: RafxResourceState::COPY_DST,
75                dst_state: RafxResourceState::VERTEX_AND_CONSTANT_BUFFER
76                    | RafxResourceState::INDEX_BUFFER,
77                queue_transition: RafxBarrierQueueTransition::ReleaseTo(
78                    upload.dst_queue().queue_type(),
79                ),
80                offset_size: barrier_offset_size,
81            }],
82            &[],
83        )?;
84
85        upload.dst_command_buffer().cmd_resource_barrier(
86            &[RafxBufferBarrier {
87                buffer: &dst_buffer,
88                src_state: RafxResourceState::COPY_DST,
89                dst_state: RafxResourceState::VERTEX_AND_CONSTANT_BUFFER
90                    | RafxResourceState::INDEX_BUFFER,
91                queue_transition: RafxBarrierQueueTransition::AcquireFrom(
92                    upload.transfer_queue().queue_type(),
93                ),
94                offset_size: barrier_offset_size,
95            }],
96            &[],
97        )?;
98    } else {
99        // If we didn't just create this buffer, we need to transition it from vertex/constant/index
100        // to COPY_DST before doing a copy
101        if new_buffer.is_none() {
102            upload.dst_command_buffer().cmd_resource_barrier(
103                &[RafxBufferBarrier {
104                    buffer: &dst_buffer,
105                    src_state: RafxResourceState::VERTEX_AND_CONSTANT_BUFFER
106                        | RafxResourceState::INDEX_BUFFER,
107                    dst_state: RafxResourceState::COPY_DST,
108                    queue_transition: RafxBarrierQueueTransition::None,
109                    offset_size: barrier_offset_size,
110                }],
111                &[],
112            )?;
113        }
114
115        upload.dst_command_buffer().cmd_copy_buffer_to_buffer(
116            &upload.staging_buffer(),
117            &dst_buffer,
118            &copy_params,
119        )?;
120
121        upload.dst_command_buffer().cmd_resource_barrier(
122            &[RafxBufferBarrier {
123                buffer: &dst_buffer,
124                src_state: RafxResourceState::COPY_DST,
125                dst_state: RafxResourceState::VERTEX_AND_CONSTANT_BUFFER
126                    | RafxResourceState::INDEX_BUFFER,
127                queue_transition: RafxBarrierQueueTransition::None,
128                offset_size: barrier_offset_size,
129            }],
130            &[],
131        )?;
132    }
133
134    log::trace!("upload buffer bytes: {}", data.len());
135
136    Ok(new_buffer)
137}