1use crate::upload::gpu_image_data::GpuImageData;
2use rafx_api::extra::upload::{RafxTransferUpload, RafxUploadError};
3use rafx_api::{
4 RafxBarrierQueueTransition, RafxCmdCopyBufferToTextureParams, RafxDeviceContext, RafxExtents3D,
5 RafxQueue, RafxResourceState, RafxResourceType, RafxSampleCount, RafxTexture,
6 RafxTextureBarrier, RafxTextureDef, RafxTextureDimensions,
7};
8
9pub struct ImageUploadParams<'a> {
10 pub resource_type: RafxResourceType,
11 pub generate_mips: bool,
12 pub layer_swizzle: Option<&'a [u32]>,
13}
14
15impl<'a> Default for ImageUploadParams<'a> {
16 fn default() -> Self {
17 ImageUploadParams {
18 resource_type: RafxResourceType::TEXTURE,
19 generate_mips: false,
20 layer_swizzle: None,
21 }
22 }
23}
24
25pub fn enqueue_load_image(
29 device_context: &RafxDeviceContext,
30 upload: &mut RafxTransferUpload,
31 image_data: &GpuImageData,
32 params: ImageUploadParams,
33) -> Result<RafxTexture, RafxUploadError> {
34 #[cfg(debug_assertions)]
36 image_data.verify_state();
37
38 let bytes_required = image_data.total_size(
42 device_context.device_info().upload_texture_alignment,
43 device_context.device_info().upload_texture_row_alignment,
44 );
45
46 let has_space_available = upload.has_space_available(
47 bytes_required as usize,
48 device_context.device_info().upload_texture_alignment as usize,
49 1,
50 );
51
52 if !has_space_available {
53 Err(RafxUploadError::BufferFull)?;
54 }
55
56 let mip_count = if params.generate_mips {
60 rafx_api::extra::mipmaps::mip_level_max_count_for_image_size(
61 image_data.width,
62 image_data.height,
63 )
64 } else {
65 image_data.layers[0].mip_levels.len() as u32
66 };
67
68 let mut layer_offsets = Vec::default();
73 for layer in &image_data.layers {
74 let mut level_offsets = Vec::default();
75 for level in &layer.mip_levels {
76 let level_block_width = rafx_base::memory::round_size_up_to_alignment_u32(
77 level.width,
78 image_data.format.block_width_in_pixels(),
79 ) / image_data.format.block_width_in_pixels();
80 let level_block_height = rafx_base::memory::round_size_up_to_alignment_u32(
81 level.height,
82 image_data.format.block_height_in_pixels(),
83 ) / image_data.format.block_height_in_pixels();
84
85 let row_size_in_bytes =
87 level_block_width * image_data.format.block_or_pixel_size_in_bytes();
88 for row_index in 0..level_block_height {
89 let alignment = if row_index == 0 {
90 device_context.device_info().upload_texture_alignment
91 } else {
92 device_context.device_info().upload_texture_row_alignment
93 };
94
95 let offset = upload.push(
96 &level.data[((row_size_in_bytes * row_index) as usize)
97 ..((row_size_in_bytes * (row_index + 1)) as usize)],
98 alignment as usize,
99 )?;
100
101 if row_index == 0 {
102 level_offsets.push(offset);
103 }
104 }
105 }
106 layer_offsets.push(level_offsets);
107 }
108
109 let layer_count = params
112 .layer_swizzle
113 .map(|x| x.len())
114 .unwrap_or_else(|| image_data.layers.len()) as u32;
115
116 assert!(mip_count > 0);
120 let texture = device_context.create_texture(&RafxTextureDef {
121 extents: RafxExtents3D {
122 width: image_data.width,
123 height: image_data.height,
124 depth: 1,
125 },
126 array_length: layer_count,
127 mip_count,
128 sample_count: RafxSampleCount::SampleCount1,
129 format: image_data.format,
130 resource_type: params.resource_type,
131 dimensions: RafxTextureDimensions::Dim2D,
132 })?;
133
134 upload
142 .transfer_command_buffer()
143 .cmd_resource_barrier(
144 &[],
145 &[RafxTextureBarrier {
146 texture: &texture,
147 src_state: RafxResourceState::UNDEFINED,
148 dst_state: RafxResourceState::COPY_DST,
149 queue_transition: RafxBarrierQueueTransition::None,
150 array_slice: None,
151 mip_slice: None,
152 }],
153 )
154 .unwrap();
155
156 for dst_layer_index in 0..layer_count {
157 let src_layer_index = if let Some(layer_swizzle) = params.layer_swizzle {
158 layer_swizzle[dst_layer_index as usize] as usize
159 } else {
160 dst_layer_index as usize
161 };
162
163 for level_index in 0..image_data.layers[src_layer_index].mip_levels.len() {
164 upload
165 .transfer_command_buffer()
166 .cmd_copy_buffer_to_texture(
167 upload.staging_buffer(),
168 &texture,
169 &RafxCmdCopyBufferToTextureParams {
170 buffer_offset: layer_offsets[src_layer_index][level_index],
171 array_layer: dst_layer_index as u16,
172 mip_level: level_index as u8,
173 },
174 )
175 .unwrap();
176 }
177 }
178
179 log::debug!(
180 "upload image {}x{} format {:?} layers: {} levels: {} generate mips: {} resource type: {:?}",
181 image_data.width,
182 image_data.height,
183 image_data.format,
184 layer_count,
185 mip_count,
186 params.generate_mips,
187 params.resource_type
188 );
189
190 if params.generate_mips && mip_count > 1 {
191 assert!(!device_context.is_dx12());
193
194 upload.transfer_command_buffer().cmd_resource_barrier(
198 &[],
199 &[RafxTextureBarrier {
200 texture: &texture,
201 src_state: RafxResourceState::COPY_DST,
202 dst_state: RafxResourceState::COPY_SRC,
203 queue_transition: RafxBarrierQueueTransition::ReleaseTo(
204 upload.dst_queue().queue_type(),
205 ),
206 array_slice: None,
207 mip_slice: Some(0),
208 }],
209 )?;
210
211 upload.dst_command_buffer().cmd_resource_barrier(
215 &[],
216 &[RafxTextureBarrier {
217 texture: &texture,
218 src_state: RafxResourceState::COPY_DST,
219 dst_state: RafxResourceState::COPY_SRC,
220 queue_transition: RafxBarrierQueueTransition::AcquireFrom(
221 upload.transfer_queue().queue_type(),
222 ),
223 array_slice: None,
224 mip_slice: Some(0),
225 }],
226 )?;
227
228 rafx_api::extra::mipmaps::generate_mipmaps(upload.dst_command_buffer(), &texture)?;
229
230 upload.dst_command_buffer().cmd_resource_barrier(
234 &[],
235 &[RafxTextureBarrier {
236 texture: &texture,
237 src_state: RafxResourceState::COPY_SRC,
238 dst_state: RafxResourceState::SHADER_RESOURCE,
239 queue_transition: RafxBarrierQueueTransition::None,
240 array_slice: None,
241 mip_slice: None,
242 }],
243 )?;
244 } else {
245 upload.transfer_command_buffer().cmd_resource_barrier(
246 &[],
247 &[RafxTextureBarrier {
248 texture: &texture,
249 src_state: RafxResourceState::COPY_DST,
250 dst_state: RafxResourceState::SHADER_RESOURCE,
251 queue_transition: RafxBarrierQueueTransition::ReleaseTo(
252 upload.dst_queue().queue_type(),
253 ),
254 array_slice: None,
255 mip_slice: None,
256 }],
257 )?;
258
259 upload.dst_command_buffer().cmd_resource_barrier(
260 &[],
261 &[RafxTextureBarrier {
262 texture: &texture,
263 src_state: RafxResourceState::COPY_DST,
264 dst_state: RafxResourceState::SHADER_RESOURCE,
265 queue_transition: RafxBarrierQueueTransition::AcquireFrom(
266 upload.transfer_queue().queue_type(),
267 ),
268 array_slice: None,
269 mip_slice: None,
270 }],
271 )?;
272 }
273
274 Ok(texture)
275}
276
277pub fn load_image_blocking(
278 device_context: &RafxDeviceContext,
279 transfer_queue: &RafxQueue,
280 dst_queue: &RafxQueue,
281 upload_buffer_max_size: u64,
282 image_data: &GpuImageData,
283 params: ImageUploadParams,
284) -> Result<RafxTexture, RafxUploadError> {
285 let total_size = image_data.total_size(
286 device_context.device_info().upload_texture_alignment,
287 device_context.device_info().upload_texture_row_alignment,
288 );
289 if upload_buffer_max_size < total_size {
290 Err(RafxUploadError::BufferFull)?;
291 }
292
293 let mut upload = RafxTransferUpload::new(
294 device_context,
295 transfer_queue,
296 dst_queue,
297 upload_buffer_max_size,
298 None,
299 )?;
300
301 let texture = enqueue_load_image(device_context, &mut upload, image_data, params)?;
302
303 upload.block_until_upload_complete()?;
304
305 Ok(texture)
306}