diff --git a/wgpu-core/src/command/transfer.rs b/wgpu-core/src/command/transfer.rs index ef974c15bf..5b679c40e0 100644 --- a/wgpu-core/src/command/transfer.rs +++ b/wgpu-core/src/command/transfer.rs @@ -120,27 +120,34 @@ pub(crate) fn extract_texture_selector( }); } - let layers = match texture.desc.dimension { - wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => { - copy_texture.origin.z..copy_texture.origin.z + copy_size.depth_or_array_layers - } - wgt::TextureDimension::D3 => 0..1, + let (layers, origin_z) = match texture.desc.dimension { + wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => ( + copy_texture.origin.z..copy_texture.origin.z + copy_size.depth_or_array_layers, + 0, + ), + wgt::TextureDimension::D3 => (0..1, copy_texture.origin.z), + }; + let base = hal::TextureCopyBase { + origin: wgt::Origin3d { + x: copy_texture.origin.x, + y: copy_texture.origin.y, + z: origin_z, + }, + // this value will be incremented per copied layer + array_layer: layers.start, + mip_level: copy_texture.mip_level, + aspect: copy_aspect, }; let selector = TextureSelector { levels: copy_texture.mip_level..copy_texture.mip_level + 1, layers, }; - let base = hal::TextureCopyBase { - origin: copy_texture.origin, - mip_level: copy_texture.mip_level, - aspect: copy_aspect, - }; Ok((selector, base, format)) } /// Function copied with some modifications from webgpu standard -/// If successful, returns number of buffer bytes required for this copy. +/// If successful, returns (number of buffer bytes required for this copy, number of bytes between array layers). pub(crate) fn validate_linear_texture_data( layout: &wgt::ImageDataLayout, format: wgt::TextureFormat, @@ -149,7 +156,7 @@ pub(crate) fn validate_linear_texture_data( bytes_per_block: BufferAddress, copy_size: &Extent3d, need_copy_aligned_rows: bool, -) -> Result { +) -> Result<(BufferAddress, BufferAddress), TransferError> { // Convert all inputs to BufferAddress (u64) to prevent overflow issues let copy_width = copy_size.width as BufferAddress; let copy_height = copy_size.height as BufferAddress; @@ -202,10 +209,10 @@ pub(crate) fn validate_linear_texture_data( } let bytes_in_last_row = block_size * width_in_blocks; + let bytes_per_image = bytes_per_row * block_rows_per_image; let required_bytes_in_copy = if copy_width == 0 || copy_height == 0 || copy_depth == 0 { 0 } else { - let bytes_per_image = bytes_per_row * block_rows_per_image; let bytes_in_last_slice = bytes_per_row * (height_in_blocks - 1) + bytes_in_last_row; bytes_per_image * (copy_depth - 1) + bytes_in_last_slice }; @@ -227,17 +234,17 @@ pub(crate) fn validate_linear_texture_data( if copy_height > 1 && bytes_per_row < bytes_in_last_row { return Err(TransferError::InvalidBytesPerRow); } - Ok(required_bytes_in_copy) + Ok((required_bytes_in_copy, bytes_per_image)) } /// Function copied with minor modifications from webgpu standard -/// Returns the (virtual) mip level extent. +/// Returns the HAL copy extent and the layer count. pub(crate) fn validate_texture_copy_range( texture_copy_view: &ImageCopyTexture, desc: &wgt::TextureDescriptor<()>, texture_side: CopySide, copy_size: &Extent3d, -) -> Result { +) -> Result<(hal::CopyExtent, u32), TransferError> { let (block_width, block_height) = desc.format.describe().block_dimensions; let block_width = block_width as u32; let block_height = block_height as u32; @@ -295,7 +302,28 @@ pub(crate) fn validate_texture_copy_range( return Err(TransferError::UnalignedCopyHeight); } - Ok(extent_virtual) + let (depth, array_layer_count) = match desc.dimension { + wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => { + (1, copy_size.depth_or_array_layers) + } + wgt::TextureDimension::D3 => ( + copy_size + .depth_or_array_layers + .min(extent_virtual.depth_or_array_layers), + 1, + ), + }; + + // WebGPU uses the physical size of the texture for copies whereas vulkan uses + // the virtual size. We have passed validation, so it's safe to use the + // image extent data directly. We want the provided copy size to be no larger than + // the virtual size. + let copy_extent = hal::CopyExtent { + width: copy_size.width.min(extent_virtual.width), + height: copy_size.width.min(extent_virtual.height), + depth, + }; + Ok((copy_extent, array_layer_count)) } impl Global { @@ -505,13 +533,13 @@ impl Global { let dst_barriers = dst_pending.map(|pending| pending.into_hal(dst_texture)); let format_desc = dst_texture.desc.format.describe(); - let max_image_extent = validate_texture_copy_range( + let (hal_copy_size, array_layer_count) = validate_texture_copy_range( destination, &dst_texture.desc, CopySide::Destination, copy_size, )?; - let required_buffer_bytes_in_copy = validate_linear_texture_data( + let (required_buffer_bytes_in_copy, bytes_per_array_layer) = validate_linear_texture_data( &source.layout, dst_texture.desc.format, src_buffer.size, @@ -538,24 +566,22 @@ impl Global { ); } - // WebGPU uses the physical size of the texture for copies whereas vulkan uses - // the virtual size. We have passed validation, so it's safe to use the - // image extent data directly. We want the provided copy size to be no larger than - // the virtual size. - let region = hal::BufferTextureCopy { - buffer_layout: source.layout, - texture_base: dst_base, - size: Extent3d { - width: copy_size.width.min(max_image_extent.width), - height: copy_size.height.min(max_image_extent.height), - depth_or_array_layers: copy_size.depth_or_array_layers, - }, - }; + let regions = (0..array_layer_count).map(|rel_array_layer| { + let mut texture_base = dst_base.clone(); + texture_base.array_layer += rel_array_layer; + let mut buffer_layout = source.layout; + buffer_layout.offset += rel_array_layer as u64 * bytes_per_array_layer; + hal::BufferTextureCopy { + buffer_layout, + texture_base, + size: hal_copy_size, + } + }); let cmd_buf_raw = cmd_buf.encoder.open(); unsafe { cmd_buf_raw.transition_buffers(src_barriers); cmd_buf_raw.transition_textures(dst_barriers); - cmd_buf_raw.copy_buffer_to_texture(src_raw, dst_raw, iter::once(region)); + cmd_buf_raw.copy_buffer_to_texture(src_raw, dst_raw, regions); } Ok(()) } @@ -635,9 +661,9 @@ impl Global { let dst_barriers = dst_pending.map(|pending| pending.into_hal(dst_buffer)); let format_desc = src_texture.desc.format.describe(); - let max_image_extent = + let (hal_copy_size, array_layer_count) = validate_texture_copy_range(source, &src_texture.desc, CopySide::Source, copy_size)?; - let required_buffer_bytes_in_copy = validate_linear_texture_data( + let (required_buffer_bytes_in_copy, bytes_per_array_layer) = validate_linear_texture_data( &destination.layout, src_texture.desc.format, dst_buffer.size, @@ -667,19 +693,17 @@ impl Global { }), ); - // WebGPU uses the physical size of the texture for copies whereas vulkan uses - // the virtual size. We have passed validation, so it's safe to use the - // image extent data directly. We want the provided copy size to be no larger than - // the virtual size. - let region = hal::BufferTextureCopy { - buffer_layout: destination.layout, - texture_base: src_base, - size: Extent3d { - width: copy_size.width.min(max_image_extent.width), - height: copy_size.height.min(max_image_extent.height), - depth_or_array_layers: copy_size.depth_or_array_layers, - }, - }; + let regions = (0..array_layer_count).map(|rel_array_layer| { + let mut texture_base = src_base.clone(); + texture_base.array_layer += rel_array_layer; + let mut buffer_layout = destination.layout; + buffer_layout.offset += rel_array_layer as u64 * bytes_per_array_layer; + hal::BufferTextureCopy { + buffer_layout, + texture_base, + size: hal_copy_size, + } + }); let cmd_buf_raw = cmd_buf.encoder.open(); unsafe { cmd_buf_raw.transition_buffers(dst_barriers); @@ -688,7 +712,7 @@ impl Global { src_raw, hal::TextureUses::COPY_SRC, dst_raw, - iter::once(region), + regions, ); } Ok(()) @@ -725,11 +749,11 @@ impl Global { return Ok(()); } - let (src_range, src_base, _) = + let (src_range, src_tex_base, _) = extract_texture_selector(source, copy_size, &*texture_guard)?; - let (dst_range, dst_base, _) = + let (dst_range, dst_tex_base, _) = extract_texture_selector(destination, copy_size, &*texture_guard)?; - if src_base.aspect != dst_base.aspect { + if src_tex_base.aspect != dst_tex_base.aspect { return Err(TransferError::MismatchedAspects.into()); } @@ -777,32 +801,31 @@ impl Global { } barriers.extend(dst_pending.map(|pending| pending.into_hal(dst_texture))); - let max_src_image_extent = + let (src_copy_size, array_layer_count) = validate_texture_copy_range(source, &src_texture.desc, CopySide::Source, copy_size)?; - let max_dst_image_extent = validate_texture_copy_range( + let (dst_copy_size, _) = validate_texture_copy_range( destination, &dst_texture.desc, CopySide::Destination, copy_size, )?; - // WebGPU uses the physical size of the texture for copies whereas vulkan uses - // the virtual size. We have passed validation, so it's safe to use the - // image extent data directly. We want the provided copy size to be no larger than - // the virtual size. - let region = hal::TextureCopy { - src_base, - dst_base, - size: Extent3d { - width: copy_size - .width - .min(max_src_image_extent.width.min(max_dst_image_extent.width)), - height: copy_size - .height - .min(max_src_image_extent.height.min(max_dst_image_extent.height)), - depth_or_array_layers: copy_size.depth_or_array_layers, - }, + let hal_copy_size = hal::CopyExtent { + width: src_copy_size.width.min(dst_copy_size.width), + height: src_copy_size.height.min(dst_copy_size.height), + depth: src_copy_size.depth.min(dst_copy_size.depth), }; + let regions = (0..array_layer_count).map(|rel_array_layer| { + let mut src_base = src_tex_base.clone(); + let mut dst_base = dst_tex_base.clone(); + src_base.array_layer += rel_array_layer; + dst_base.array_layer += rel_array_layer; + hal::TextureCopy { + src_base, + dst_base, + size: hal_copy_size, + } + }); let cmd_buf_raw = cmd_buf.encoder.open(); unsafe { cmd_buf_raw.transition_textures(barriers.into_iter()); @@ -810,7 +833,7 @@ impl Global { src_raw, hal::TextureUses::COPY_SRC, dst_raw, - iter::once(region), + regions, ); } Ok(()) diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index f418783970..a315458180 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -732,10 +732,13 @@ impl Device { let usage = { let mask_copy = !(hal::TextureUses::COPY_SRC | hal::TextureUses::COPY_DST); let mask_dimension = match view_dim { - wgt::TextureViewDimension::Cube | - wgt::TextureViewDimension::CubeArray => hal::TextureUses::SAMPLED, + wgt::TextureViewDimension::Cube | wgt::TextureViewDimension::CubeArray => { + hal::TextureUses::SAMPLED + } wgt::TextureViewDimension::D3 => { - hal::TextureUses::SAMPLED | hal::TextureUses::STORAGE_LOAD | hal::TextureUses::STORAGE_STORE + hal::TextureUses::SAMPLED + | hal::TextureUses::STORAGE_LOAD + | hal::TextureUses::STORAGE_STORE } _ => hal::TextureUses::all(), }; @@ -747,7 +750,11 @@ impl Device { texture.hal_usage & mask_copy & mask_dimension & mask_mip_level }; - log::debug!("Create view for texture {:?} filters usages to {:?}", texture_id, usage); + log::debug!( + "Create view for texture {:?} filters usages to {:?}", + texture_id, + usage + ); let hal_desc = hal::TextureViewDescriptor { label: desc.label.borrow_option(), format, diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index a68766a835..e302bd8c6a 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -433,10 +433,10 @@ impl Global { } let (texture_guard, _) = hub.textures.read(&mut token); - let (selector, texture_base, texture_format) = + let (selector, dst_base, texture_format) = extract_texture_selector(destination, size, &*texture_guard)?; let format_desc = texture_format.describe(); - validate_linear_texture_data( + let (_, bytes_per_array_layer) = validate_linear_texture_data( data_layout, texture_format, data.len() as wgt::BufferAddress, @@ -495,7 +495,7 @@ impl Global { TransferError::MissingCopyDstUsageFlag(None, Some(destination.texture)).into(), ); } - let max_image_extent = + let (hal_copy_size, array_layer_count) = validate_texture_copy_range(destination, &dst.desc, CopySide::Destination, size)?; dst.life_guard.use_at(device.active_submission_index + 1); @@ -542,33 +542,29 @@ impl Global { .map_err(DeviceError::from)?; } - // WebGPU uses the physical size of the texture for copies whereas vulkan uses - // the virtual size. We have passed validation, so it's safe to use the - // image extent data directly. We want the provided copy size to be no larger than - // the virtual size. - let region = hal::BufferTextureCopy { - buffer_layout: wgt::ImageDataLayout { - offset: 0, - bytes_per_row: NonZeroU32::new(stage_bytes_per_row), - rows_per_image: NonZeroU32::new(block_rows_per_image), - }, - texture_base, - size: wgt::Extent3d { - width: size.width.min(max_image_extent.width), - height: size.height.min(max_image_extent.height), - depth_or_array_layers: size.depth_or_array_layers, - }, - }; - + let regions = (0..array_layer_count).map(|rel_array_layer| { + let mut texture_base = dst_base.clone(); + texture_base.array_layer += rel_array_layer; + hal::BufferTextureCopy { + buffer_layout: wgt::ImageDataLayout { + offset: rel_array_layer as u64 * bytes_per_array_layer, + bytes_per_row: NonZeroU32::new(stage_bytes_per_row), + rows_per_image: NonZeroU32::new(block_rows_per_image), + }, + texture_base, + size: hal_copy_size, + } + }); let barrier = hal::BufferBarrier { buffer: &stage.buffer, usage: hal::BufferUses::MAP_WRITE..hal::BufferUses::COPY_SRC, }; + let encoder = device.pending_writes.activate(); unsafe { encoder.transition_buffers(iter::once(barrier)); encoder.transition_textures(transition.map(|pending| pending.into_hal(dst))); - encoder.copy_buffer_to_texture(&stage.buffer, dst_raw, iter::once(region)); + encoder.copy_buffer_to_texture(&stage.buffer, dst_raw, regions); } device.pending_writes.consume(stage); diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index 047d0599d3..fb6c102028 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -302,9 +302,14 @@ impl Example { texture_base: hal::TextureCopyBase { origin: wgt::Origin3d::ZERO, mip_level: 0, + array_layer: 0, aspect: hal::FormatAspects::COLOR, }, - size: texture_desc.size, + size: hal::CopyExtent { + width: 1, + height: 1, + depth: 1, + }, }; unsafe { cmd_encoder.transition_buffers(iter::once(buffer_barrier)); diff --git a/wgpu-hal/src/dx12/command.rs b/wgpu-hal/src/dx12/command.rs index 6068be44e5..642e734bad 100644 --- a/wgpu-hal/src/dx12/command.rs +++ b/wgpu-hal/src/dx12/command.rs @@ -210,59 +210,26 @@ impl crate::CommandEncoder for super::CommandEncoder { }; for r in regions { - let ( - depth, - array_layer_count, - src_z, - src_base_array_layer, - dst_z, - dst_base_array_layer, - ) = match src.dimension { - wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => ( - 1, - r.size.depth_or_array_layers, - 0, - r.src_base.origin.z, - 0, - r.dst_base.origin.z, - ), - wgt::TextureDimension::D3 => ( - r.size.depth_or_array_layers, - 1, - r.src_base.origin.z, - 0, - r.dst_base.origin.z, - 0, - ), - }; let src_box = d3d12::D3D12_BOX { left: r.src_base.origin.x, top: r.src_base.origin.y, right: r.src_base.origin.x + r.size.width, bottom: r.src_base.origin.y + r.size.height, - front: src_z, - back: src_z + depth, + front: r.src_base.origin.z, + back: r.src_base.origin.z + r.size.depth, }; - for rel_array_layer in 0..array_layer_count { - *src_location.u.SubresourceIndex_mut() = src.calc_subresource( - r.src_base.mip_level, - src_base_array_layer + rel_array_layer, - 0, - ); - *dst_location.u.SubresourceIndex_mut() = dst.calc_subresource( - r.dst_base.mip_level, - dst_base_array_layer + rel_array_layer, - 0, - ); - list.CopyTextureRegion( - &dst_location, - r.dst_base.origin.x, - r.dst_base.origin.y, - dst_z, - &src_location, - &src_box, - ); - } + *src_location.u.SubresourceIndex_mut() = + src.calc_subresource(r.src_base.mip_level, r.src_base.array_layer, 0); + *dst_location.u.SubresourceIndex_mut() = + dst.calc_subresource(r.dst_base.mip_level, r.dst_base.array_layer, 0); + list.CopyTextureRegion( + &dst_location, + r.dst_base.origin.x, + r.dst_base.origin.y, + r.dst_base.origin.z, + &src_location, + &src_box, + ); } } @@ -285,14 +252,7 @@ impl crate::CommandEncoder for super::CommandEncoder { ) where T: Iterator, { - for r in regions { - let (_base_array_layer, _array_layer_count) = match src.dimension { - wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => { - (r.texture_base.origin.z, r.size.depth_or_array_layers) - } - wgt::TextureDimension::D3 => (0, 1), - }; - } + for _r in regions {} } unsafe fn begin_query(&mut self, set: &super::QuerySet, index: u32) {} diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 9e4cf285cd..2b0dbc522a 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -201,52 +201,51 @@ impl super::Queue { ref copy, } => { //TODO: cubemaps - //TODO: how is depth handled? + //TODO: handle 3D copies gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.copy_fbo)); - for layer in 0..copy.size.depth_or_array_layers as i32 { - if is_3d_target(src_target) { - //TODO: handle GLES without framebuffer_texture_3d - gl.framebuffer_texture_layer( - glow::READ_FRAMEBUFFER, - glow::COLOR_ATTACHMENT0, - Some(src), - copy.src_base.mip_level as i32, - copy.src_base.origin.z as i32 + layer, - ); - } else { - gl.framebuffer_texture_2d( - glow::READ_FRAMEBUFFER, - glow::COLOR_ATTACHMENT0, - src_target, - Some(src), - copy.src_base.mip_level as i32, - ); - } - gl.bind_texture(dst_target, Some(dst)); - if is_3d_target(dst_target) { - gl.copy_tex_sub_image_3d( - dst_target, - copy.dst_base.mip_level as i32, - copy.dst_base.origin.x as i32, - copy.dst_base.origin.y as i32, - copy.dst_base.origin.z as i32 + layer, - copy.src_base.origin.x as i32, - copy.src_base.origin.y as i32, - copy.size.width as i32, - copy.size.height as i32, - ); - } else { - gl.copy_tex_sub_image_2d( - dst_target, - copy.dst_base.mip_level as i32, - copy.dst_base.origin.x as i32, - copy.dst_base.origin.y as i32, - copy.src_base.origin.x as i32, - copy.src_base.origin.y as i32, - copy.size.width as i32, - copy.size.height as i32, - ); - } + if is_3d_target(src_target) { + //TODO: handle GLES without framebuffer_texture_3d + gl.framebuffer_texture_layer( + glow::READ_FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + Some(src), + copy.src_base.mip_level as i32, + copy.src_base.array_layer as i32, + ); + } else { + gl.framebuffer_texture_2d( + glow::READ_FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + src_target, + Some(src), + copy.src_base.mip_level as i32, + ); + } + + gl.bind_texture(dst_target, Some(dst)); + if is_3d_target(dst_target) { + gl.copy_tex_sub_image_3d( + dst_target, + copy.dst_base.mip_level as i32, + copy.dst_base.origin.x as i32, + copy.dst_base.origin.y as i32, + copy.dst_base.origin.z as i32, + copy.src_base.origin.x as i32, + copy.src_base.origin.y as i32, + copy.size.width as i32, + copy.size.height as i32, + ); + } else { + gl.copy_tex_sub_image_2d( + dst_target, + copy.dst_base.mip_level as i32, + copy.dst_base.origin.x as i32, + copy.dst_base.origin.y as i32, + copy.src_base.origin.x as i32, + copy.src_base.origin.y as i32, + copy.size.width as i32, + copy.size.height as i32, + ); } } C::CopyBufferToTexture { @@ -286,7 +285,7 @@ impl super::Queue { copy.texture_base.origin.z as i32, copy.size.width as i32, copy.size.height as i32, - copy.size.depth_or_array_layers as i32, + copy.size.depth as i32, format_desc.external, format_desc.data_type, unpack_data, @@ -306,26 +305,18 @@ impl super::Queue { ); } glow::TEXTURE_CUBE_MAP => { - let mut offset = copy.buffer_layout.offset as u32; - for face_index in 0..copy.size.depth_or_array_layers { - gl.tex_sub_image_2d( - CUBEMAP_FACES - [(copy.texture_base.origin.z + face_index) as usize], - copy.texture_base.mip_level as i32, - copy.texture_base.origin.x as i32, - copy.texture_base.origin.y as i32, - copy.size.width as i32, - copy.size.height as i32, - format_desc.external, - format_desc.data_type, - glow::PixelUnpackData::BufferOffset(offset), - ); - offset += copy - .buffer_layout - .rows_per_image - .map_or(0, |rpi| rpi.get()) - * copy.buffer_layout.bytes_per_row.map_or(0, |bpr| bpr.get()); - } + let offset = copy.buffer_layout.offset as u32; + gl.tex_sub_image_2d( + CUBEMAP_FACES[copy.texture_base.array_layer as usize], + copy.texture_base.mip_level as i32, + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.size.width as i32, + copy.size.height as i32, + format_desc.external, + format_desc.data_type, + glow::PixelUnpackData::BufferOffset(offset), + ); } glow::TEXTURE_CUBE_MAP_ARRAY => { //Note: not sure if this is correct! @@ -337,7 +328,7 @@ impl super::Queue { copy.texture_base.origin.z as i32, copy.size.width as i32, copy.size.height as i32, - copy.size.depth_or_array_layers as i32, + copy.size.depth as i32, format_desc.external, format_desc.data_type, unpack_data, @@ -349,10 +340,9 @@ impl super::Queue { let bytes_per_image = copy.buffer_layout.rows_per_image.map_or(1, |rpi| rpi.get()) * copy.buffer_layout.bytes_per_row.map_or(1, |bpr| bpr.get()); - let offset_end = copy.buffer_layout.offset as u32 - + bytes_per_image * copy.size.depth_or_array_layers; + let offset = copy.buffer_layout.offset as u32; let unpack_data = glow::CompressedPixelUnpackData::BufferRange( - copy.buffer_layout.offset as u32..offset_end, + offset..offset + bytes_per_image, ); match dst_target { glow::TEXTURE_3D | glow::TEXTURE_2D_ARRAY => { @@ -364,7 +354,7 @@ impl super::Queue { copy.texture_base.origin.z as i32, copy.size.width as i32, copy.size.height as i32, - copy.size.depth_or_array_layers as i32, + copy.size.depth as i32, format_desc.internal, unpack_data, ); @@ -382,23 +372,18 @@ impl super::Queue { ); } glow::TEXTURE_CUBE_MAP => { - let mut offset = copy.buffer_layout.offset as u32; - for face_index in 0..copy.size.depth_or_array_layers { - gl.compressed_tex_sub_image_2d( - CUBEMAP_FACES - [(copy.texture_base.origin.z + face_index) as usize], - copy.texture_base.mip_level as i32, - copy.texture_base.origin.x as i32, - copy.texture_base.origin.y as i32, - copy.size.width as i32, - copy.size.height as i32, - format_desc.internal, - glow::CompressedPixelUnpackData::BufferRange( - offset..offset + bytes_per_image, - ), - ); - offset += bytes_per_image; - } + gl.compressed_tex_sub_image_2d( + CUBEMAP_FACES[copy.texture_base.array_layer as usize], + copy.texture_base.mip_level as i32, + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.size.width as i32, + copy.size.height as i32, + format_desc.internal, + glow::CompressedPixelUnpackData::BufferRange( + offset..offset + bytes_per_image, + ), + ); } glow::TEXTURE_CUBE_MAP_ARRAY => { //Note: not sure if this is correct! @@ -410,7 +395,7 @@ impl super::Queue { copy.texture_base.origin.z as i32, copy.size.width as i32, copy.size.height as i32, - copy.size.depth_or_array_layers as i32, + copy.size.depth as i32, format_desc.internal, unpack_data, ); @@ -445,45 +430,37 @@ impl super::Queue { .map_or(copy.size.width, |bpr| { bpr.get() / format_info.block_size as u32 }); - let column_texels = copy - .buffer_layout - .rows_per_image - .map_or(copy.size.height, |rpi| rpi.get()); gl.pixel_store_i32(glow::PACK_ROW_LENGTH, row_texels as i32); gl.bind_buffer(glow::PIXEL_PACK_BUFFER, Some(dst)); gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.copy_fbo)); - for layer in 0..copy.size.depth_or_array_layers { - let offset = copy.buffer_layout.offset as u32 - + layer * column_texels * row_texels * format_info.block_size as u32; - if is_3d_target(src_target) { - //TODO: handle GLES without framebuffer_texture_3d - gl.framebuffer_texture_layer( - glow::READ_FRAMEBUFFER, - glow::COLOR_ATTACHMENT0, - Some(src), - copy.texture_base.mip_level as i32, - copy.texture_base.origin.z as i32 + layer as i32, - ); - } else { - gl.framebuffer_texture_2d( - glow::READ_FRAMEBUFFER, - glow::COLOR_ATTACHMENT0, - src_target, - Some(src), - copy.texture_base.mip_level as i32, - ); - } - gl.read_pixels( - copy.texture_base.origin.x as i32, - copy.texture_base.origin.y as i32, - copy.size.width as i32, - copy.size.height as i32, - format_desc.external, - format_desc.data_type, - glow::PixelPackData::BufferOffset(offset), + if is_3d_target(src_target) { + //TODO: handle GLES without framebuffer_texture_3d + gl.framebuffer_texture_layer( + glow::READ_FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + Some(src), + copy.texture_base.mip_level as i32, + copy.texture_base.array_layer as i32, + ); + } else { + gl.framebuffer_texture_2d( + glow::READ_FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + src_target, + Some(src), + copy.texture_base.mip_level as i32, ); } + gl.read_pixels( + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.size.width as i32, + copy.size.height as i32, + format_desc.external, + format_desc.data_type, + glow::PixelPackData::BufferOffset(copy.buffer_layout.offset as u32), + ); } C::SetIndexBuffer(buffer) => { gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(buffer)); diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index fefee510e7..97ae478821 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -351,6 +351,8 @@ pub trait CommandEncoder: Send + Sync { where T: Iterator; + /// Copy from one texture to another. + /// Works with a single array layer. /// Note: `dst` current usage has to be `TextureUses::COPY_DST`. unsafe fn copy_texture_to_texture( &mut self, @@ -361,11 +363,15 @@ pub trait CommandEncoder: Send + Sync { ) where T: Iterator; + /// Copy from buffer to texture. + /// Works with a single array layer. /// Note: `dst` current usage has to be `TextureUses::COPY_DST`. unsafe fn copy_buffer_to_texture(&mut self, src: &A::Buffer, dst: &A::Texture, regions: T) where T: Iterator; + /// Copy from texture to buffer. + /// Works with a single array layer. unsafe fn copy_texture_to_buffer( &mut self, src: &A::Texture, @@ -1006,26 +1012,33 @@ pub struct BufferCopy { #[derive(Clone, Debug)] pub struct TextureCopyBase { - pub origin: wgt::Origin3d, pub mip_level: u32, + pub array_layer: u32, + /// Origin within a texture. + /// Note: for 1D and 2D textures, Z must be 0. + pub origin: wgt::Origin3d, pub aspect: FormatAspects, } -//TODO: all the copy operations really want to separate -// array layers from Z, so this should not use `wgt::Extent3d`, -// and potentially work with a single layer at a time. +#[derive(Clone, Copy, Debug)] +pub struct CopyExtent { + pub width: u32, + pub height: u32, + pub depth: u32, +} + #[derive(Clone, Debug)] pub struct TextureCopy { pub src_base: TextureCopyBase, pub dst_base: TextureCopyBase, - pub size: wgt::Extent3d, + pub size: CopyExtent, } #[derive(Clone, Debug)] pub struct BufferTextureCopy { pub buffer_layout: wgt::ImageDataLayout, pub texture_base: TextureCopyBase, - pub size: wgt::Extent3d, + pub size: CopyExtent, } #[derive(Debug)] diff --git a/wgpu-hal/src/metal/command.rs b/wgpu-hal/src/metal/command.rs index 9fbaf3c042..e395f9320c 100644 --- a/wgpu-hal/src/metal/command.rs +++ b/wgpu-hal/src/metal/command.rs @@ -156,22 +156,20 @@ impl crate::CommandEncoder for super::CommandEncoder { { let encoder = self.enter_blit(); for copy in regions { - let (src_slice, src_origin) = conv::map_origin(©.src_base.origin, src.raw_type); - let (dst_slice, dst_origin) = conv::map_origin(©.dst_base.origin, dst.raw_type); - let (slice_count, extent) = conv::map_extent(©.size, src.raw_type); - for slice in 0..slice_count { - encoder.copy_from_texture( - &src.raw, - src_slice + slice, - copy.src_base.mip_level as u64, - src_origin, - extent, - &dst.raw, - dst_slice + slice, - copy.dst_base.mip_level as u64, - dst_origin, - ); - } + let src_origin = conv::map_origin(©.src_base.origin); + let dst_origin = conv::map_origin(©.dst_base.origin); + let extent = conv::map_copy_extent(©.size); + encoder.copy_from_texture( + &src.raw, + copy.src_base.array_layer as u64, + copy.src_base.mip_level as u64, + src_origin, + extent, + &dst.raw, + copy.dst_base.array_layer as u64, + copy.dst_base.mip_level as u64, + dst_origin, + ); } } @@ -185,8 +183,8 @@ impl crate::CommandEncoder for super::CommandEncoder { { let encoder = self.enter_blit(); for copy in regions { - let (dst_slice, dst_origin) = conv::map_origin(©.texture_base.origin, dst.raw_type); - let (slice_count, extent) = conv::map_extent(©.size, dst.raw_type); + let dst_origin = conv::map_origin(©.texture_base.origin); + let extent = conv::map_copy_extent(©.size); let bytes_per_row = copy .buffer_layout .bytes_per_row @@ -195,21 +193,18 @@ impl crate::CommandEncoder for super::CommandEncoder { .buffer_layout .rows_per_image .map_or(0, |v| v.get() as u64 * bytes_per_row); - for slice in 0..slice_count { - let offset = copy.buffer_layout.offset + bytes_per_image * slice; - encoder.copy_from_buffer_to_texture( - &src.raw, - offset, - bytes_per_row, - bytes_per_image, - extent, - &dst.raw, - dst_slice + slice, - copy.texture_base.mip_level as u64, - dst_origin, - mtl::MTLBlitOption::empty(), - ); - } + encoder.copy_from_buffer_to_texture( + &src.raw, + copy.buffer_layout.offset, + bytes_per_row, + bytes_per_image, + extent, + &dst.raw, + copy.texture_base.array_layer as u64, + copy.texture_base.mip_level as u64, + dst_origin, + mtl::MTLBlitOption::empty(), + ); } } @@ -224,8 +219,8 @@ impl crate::CommandEncoder for super::CommandEncoder { { let encoder = self.enter_blit(); for copy in regions { - let (src_slice, src_origin) = conv::map_origin(©.texture_base.origin, src.raw_type); - let (slice_count, extent) = conv::map_extent(©.size, src.raw_type); + let src_origin = conv::map_origin(©.texture_base.origin); + let extent = conv::map_copy_extent(©.size); let bytes_per_row = copy .buffer_layout .bytes_per_row @@ -234,21 +229,18 @@ impl crate::CommandEncoder for super::CommandEncoder { .buffer_layout .rows_per_image .map_or(0, |v| v.get() as u64 * bytes_per_row); - for slice in 0..slice_count { - let offset = copy.buffer_layout.offset + bytes_per_image * slice; - encoder.copy_from_texture_to_buffer( - &src.raw, - src_slice + slice, - copy.texture_base.mip_level as u64, - src_origin, - extent, - &dst.raw, - offset, - bytes_per_row, - bytes_per_image, - mtl::MTLBlitOption::empty(), - ); - } + encoder.copy_from_texture_to_buffer( + &src.raw, + copy.texture_base.array_layer as u64, + copy.texture_base.mip_level as u64, + src_origin, + extent, + &dst.raw, + copy.buffer_layout.offset, + bytes_per_row, + bytes_per_image, + mtl::MTLBlitOption::empty(), + ); } } diff --git a/wgpu-hal/src/metal/conv.rs b/wgpu-hal/src/metal/conv.rs index 61ae6cab14..b1c7e0b303 100644 --- a/wgpu-hal/src/metal/conv.rs +++ b/wgpu-hal/src/metal/conv.rs @@ -261,34 +261,20 @@ pub fn map_range(range: &crate::MemoryRange) -> mtl::NSRange { } } -pub fn map_extent(extent: &wgt::Extent3d, raw_type: mtl::MTLTextureType) -> (u64, mtl::MTLSize) { - let (depth, array_layers) = match raw_type { - mtl::MTLTextureType::D3 => (extent.depth_or_array_layers as u64, 1), - _ => (1, extent.depth_or_array_layers as u64), - }; - ( - array_layers, - mtl::MTLSize { - width: extent.width as u64, - height: extent.height as u64, - depth, - }, - ) +pub fn map_copy_extent(extent: &crate::CopyExtent) -> mtl::MTLSize { + mtl::MTLSize { + width: extent.width as u64, + height: extent.height as u64, + depth: extent.depth as u64, + } } -pub fn map_origin(origin: &wgt::Origin3d, raw_type: mtl::MTLTextureType) -> (u64, mtl::MTLOrigin) { - let (z, slice) = match raw_type { - mtl::MTLTextureType::D3 => (origin.z as u64, 0), - _ => (0, origin.z as u64), - }; - ( - slice, - mtl::MTLOrigin { - x: origin.x as u64, - y: origin.y as u64, - z, - }, - ) +pub fn map_origin(origin: &wgt::Origin3d) -> mtl::MTLOrigin { + mtl::MTLOrigin { + x: origin.x as u64, + y: origin.y as u64, + z: origin.z as u64, + } } pub fn map_store_action(store: bool, resolve: bool) -> mtl::MTLStoreAction { diff --git a/wgpu-hal/src/vulkan/command.rs b/wgpu-hal/src/vulkan/command.rs index 9b2f7f4630..fded155bd2 100644 --- a/wgpu-hal/src/vulkan/command.rs +++ b/wgpu-hal/src/vulkan/command.rs @@ -18,13 +18,11 @@ impl super::Texture { where T: Iterator, { - let dim = self.dim; let aspects = self.aspects; let fi = self.format_info; regions.map(move |r| { - let (layer_count, image_extent) = conv::map_extent(r.size, dim); let (image_subresource, image_offset) = - conv::map_subresource_layers(&r.texture_base, dim, aspects, layer_count); + conv::map_subresource_layers(&r.texture_base, aspects); vk::BufferImageCopy { buffer_offset: r.buffer_layout.offset, buffer_row_length: r.buffer_layout.bytes_per_row.map_or(0, |bpr| { @@ -36,7 +34,7 @@ impl super::Texture { .map_or(0, |rpi| rpi.get() * fi.block_dimensions.1 as u32), image_subresource, image_offset, - image_extent, + image_extent: conv::map_copy_extent(&r.size), } }) } @@ -228,17 +226,16 @@ impl crate::CommandEncoder for super::CommandEncoder { let src_layout = conv::derive_image_layout(src_usage, src.aspects); let vk_regions_iter = regions.map(|r| { - let (layer_count, extent) = conv::map_extent(r.size, src.dim); let (src_subresource, src_offset) = - conv::map_subresource_layers(&r.src_base, src.dim, src.aspects, layer_count); + conv::map_subresource_layers(&r.src_base, src.aspects); let (dst_subresource, dst_offset) = - conv::map_subresource_layers(&r.dst_base, dst.dim, dst.aspects, layer_count); + conv::map_subresource_layers(&r.dst_base, dst.aspects); vk::ImageCopy { src_subresource, src_offset, dst_subresource, dst_offset, - extent, + extent: conv::map_copy_extent(&r.size), } }); diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index b6bb4ca10b..ffa38a4c18 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -352,42 +352,6 @@ pub fn map_aspects(aspects: crate::FormatAspects) -> vk::ImageAspectFlags { flags } -pub fn map_origin( - origin: wgt::Origin3d, - texture_dim: wgt::TextureDimension, -) -> (u32, vk::Offset3D) { - let (z, array_layer) = match texture_dim { - wgt::TextureDimension::D3 => (origin.z as i32, 0), - _ => (0, origin.z), - }; - ( - array_layer, - vk::Offset3D { - x: origin.x as i32, - y: origin.y as i32, - z, - }, - ) -} - -pub fn map_extent( - extent: wgt::Extent3d, - texture_dim: wgt::TextureDimension, -) -> (u32, vk::Extent3D) { - let (depth, array_layers) = match texture_dim { - wgt::TextureDimension::D3 => (extent.depth_or_array_layers, 1), - _ => (1, extent.depth_or_array_layers), - }; - ( - array_layers, - vk::Extent3D { - width: extent.width, - height: extent.height, - depth, - }, - ) -} - pub fn map_attachment_ops( op: crate::AttachmentOps, ) -> (vk::AttachmentLoadOp, vk::AttachmentStoreOp) { @@ -541,6 +505,14 @@ pub fn map_view_dimension(dim: wgt::TextureViewDimension) -> vk::ImageViewType { } } +pub fn map_copy_extent(extent: &crate::CopyExtent) -> vk::Extent3D { + vk::Extent3D { + width: extent.width, + height: extent.height, + depth: extent.depth, + } +} + pub fn map_subresource_range( range: &wgt::ImageSubresourceRange, texture_aspect: crate::FormatAspects, @@ -560,16 +532,18 @@ pub fn map_subresource_range( pub fn map_subresource_layers( base: &crate::TextureCopyBase, - texture_dim: wgt::TextureDimension, texture_aspect: crate::FormatAspects, - layer_count: u32, ) -> (vk::ImageSubresourceLayers, vk::Offset3D) { - let (base_array_layer, offset) = map_origin(base.origin, texture_dim); + let offset = vk::Offset3D { + x: base.origin.x as i32, + y: base.origin.y as i32, + z: base.origin.z as i32, + }; let subresource = vk::ImageSubresourceLayers { aspect_mask: map_aspects(base.aspect & texture_aspect), mip_level: base.mip_level, - base_array_layer, - layer_count, + base_array_layer: base.array_layer, + layer_count: 1, }; (subresource, offset) } diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 47fc9a45f4..64156cf218 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -654,7 +654,11 @@ impl crate::Device for super::Device { &self, desc: &crate::TextureDescriptor, ) -> Result { - let (array_layer_count, vk_extent) = conv::map_extent(desc.size, desc.dimension); + let (depth, array_layer_count) = match desc.dimension { + wgt::TextureDimension::D3 => (desc.size.depth_or_array_layers, 1), + _ => (1, desc.size.depth_or_array_layers), + }; + let mut raw_flags = vk::ImageCreateFlags::empty(); if desc.dimension == wgt::TextureDimension::D2 && desc.size.depth_or_array_layers % 6 == 0 { raw_flags |= vk::ImageCreateFlags::CUBE_COMPATIBLE; @@ -664,7 +668,11 @@ impl crate::Device for super::Device { .flags(raw_flags) .image_type(conv::map_texture_dimension(desc.dimension)) .format(self.shared.private_caps.map_texture_format(desc.format)) - .extent(vk_extent) + .extent(vk::Extent3D { + width: desc.size.width, + height: desc.size.height, + depth, + }) .mip_levels(desc.mip_level_count) .array_layers(array_layer_count) .samples(vk::SampleCountFlags::from_raw(desc.sample_count)) @@ -699,7 +707,6 @@ impl crate::Device for super::Device { raw, block: Some(block), usage: desc.usage, - dim: desc.dimension, aspects: crate::FormatAspects::from(desc.format), format_info: desc.format.describe(), raw_flags, diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index ae3c441034..39261edbed 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -647,7 +647,6 @@ impl crate::Surface for super::Surface { raw: sc.images[index as usize], block: None, usage: sc.config.usage, - dim: wgt::TextureDimension::D2, aspects: crate::FormatAspects::COLOR, format_info: sc.config.format.describe(), raw_flags: vk::ImageCreateFlags::empty(), diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index 4b5e17f97c..387d079fd9 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -255,7 +255,6 @@ pub struct Texture { raw: vk::Image, block: Option>, usage: crate::TextureUses, - dim: wgt::TextureDimension, aspects: crate::FormatAspects, format_info: wgt::TextureFormatInfo, raw_flags: vk::ImageCreateFlags,