rusticl/image: fix sub-buffer images

There were two issues with the current implementation:
 - We didn't set the offset for sampler and image views
 - Image::fill didn't take the parents offset into account

Cc: mesa-stable
Reported-by: Rob Clark <rob.clark@oss.qualcomm.com>
Tested-by: Rob Clark <rob.clark@oss.qualcomm.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35537>
This commit is contained in:
Karol Herbst 2025-06-15 18:46:20 +02:00 committed by Marge Bot
parent 17fbd0df51
commit 7e9ee2000a
3 changed files with 53 additions and 26 deletions

View file

@ -1831,12 +1831,24 @@ impl Image {
}
// If image is created from a buffer, use clear_image_buffer instead
if self.is_parent_buffer() {
if let Some(Mem::Buffer(parent)) = self.parent() {
let strides = (
self.image_desc.row_pitch()? as usize,
self.image_desc.slice_pitch(),
);
ctx.clear_image_buffer(res, &new_pattern, origin, region, strides, pixel_size);
let offset = parent.apply_offset(CLVec::calc_offset(
origin,
[pixel_size, strides.0, strides.1],
))?;
ctx.clear_image_buffer(
res,
&new_pattern,
offset.try_into_with_err(CL_OUT_OF_HOST_MEMORY)?,
region,
strides,
pixel_size,
);
} else {
let bx = create_pipe_box(*origin, *region, self.mem_type)?;
ctx.clear_texture(res, &new_pattern, &bx);
@ -1851,10 +1863,6 @@ impl Image {
matches!(entry, Entry::Occupied(entry) if entry.get().count > 0)
}
pub fn is_parent_buffer(&self) -> bool {
matches!(self.parent(), Some(Mem::Buffer(_)))
}
pub fn map(
&self,
origin: CLVec<usize>,
@ -2116,12 +2124,23 @@ impl Image {
pub fn sampler_view<'c>(&self, ctx: &'c QueueContext) -> CLResult<PipeSamplerView<'c, '_>> {
let res = self.get_res_for_access(ctx, RWFlags::RD)?;
let template = if res.is_buffer() && self.mem_type == CL_MEM_OBJECT_IMAGE2D {
res.pipe_sampler_view_template_2d_buffer(self.pipe_format, &self.buffer_2d_info()?)
let template = if let Some(Mem::Buffer(parent)) = self.parent() {
if self.mem_type == CL_MEM_OBJECT_IMAGE2D {
res.pipe_sampler_view_template_2d_buffer(
self.pipe_format,
&self.buffer_2d_info()?,
parent.offset() as u32 / self.image_format.pixel_size().unwrap() as u32,
)
} else {
assert_eq!(self.mem_type, CL_MEM_OBJECT_IMAGE1D_BUFFER);
// we need to pass in the size of the buffer, not the width.
let size = self.size.try_into_with_err(CL_OUT_OF_RESOURCES)?;
let offset = parent.offset().try_into_with_err(CL_OUT_OF_RESOURCES)?;
res.pipe_sampler_view_template_1d_buffer(self.pipe_format, size, offset)
}
} else if res.is_buffer() {
// we need to pass in the size of the buffer, not the width.
let size = self.size.try_into_with_err(CL_OUT_OF_RESOURCES)?;
res.pipe_sampler_view_template_1d_buffer(self.pipe_format, size)
res.pipe_sampler_view_template_1d_buffer(self.pipe_format, size, 0)
} else {
res.pipe_sampler_view_template()
};
@ -2133,17 +2152,23 @@ impl Image {
let rw = if read_write { RWFlags::RW } else { RWFlags::WR };
let res = self.get_res_for_access(ctx, rw)?;
if res.is_buffer() && self.mem_type == CL_MEM_OBJECT_IMAGE2D {
Ok(
res.pipe_image_view_2d_buffer(
if let Some(Mem::Buffer(parent)) = self.parent() {
if self.mem_type == CL_MEM_OBJECT_IMAGE2D {
Ok(res.pipe_image_view_2d_buffer(
self.pipe_format,
read_write,
&self.buffer_2d_info()?,
),
)
parent.offset() as u32 / self.image_format.pixel_size().unwrap() as u32,
))
} else {
assert_eq!(self.mem_type, CL_MEM_OBJECT_IMAGE1D_BUFFER);
let size = self.size.try_into_with_err(CL_OUT_OF_RESOURCES)?;
let offset = parent.offset().try_into_with_err(CL_OUT_OF_RESOURCES)?;
Ok(res.pipe_image_view_1d_buffer(self.pipe_format, read_write, size, offset))
}
} else if res.is_buffer() {
let size = self.size.try_into_with_err(CL_OUT_OF_RESOURCES)?;
Ok(res.pipe_image_view_1d_buffer(self.pipe_format, read_write, size))
Ok(res.pipe_image_view_1d_buffer(self.pipe_format, read_write, size, 0))
} else {
Ok(res.pipe_image_view(read_write))
}

View file

@ -135,7 +135,7 @@ impl PipeContext {
&self,
res: &PipeResource,
pattern: &[u32],
origin: &[usize; 3],
offset_bytes: u32,
region: &[usize; 3],
strides: (usize, usize),
pixel_size: usize,
@ -144,16 +144,14 @@ impl PipeContext {
for z in 0..region[2] {
for y in 0..region[1] {
let pitch = [pixel_size, row_pitch, slice_pitch];
// Convoluted way of doing (origin + [0, y, z]) * pitch
let offset = (0..3)
.map(|i| ((origin[i] + [0, y, z][i]) * pitch[i]) as u32)
.sum();
// Convoluted way of doing [0, y, z] * pitch
let offset: u32 = (0..3).map(|i| ([0, y, z][i] * pitch[i]) as u32).sum();
unsafe {
self.pipe.as_ref().clear_buffer.unwrap()(
self.pipe.as_ptr(),
res.pipe(),
offset,
offset + offset_bytes,
(region[0] * pixel_size) as u32,
pattern.as_ptr().cast(),
pixel_size as i32,

View file

@ -166,6 +166,7 @@ impl PipeResource {
format: pipe_format,
read_write: bool,
size: u32,
offset_bytes: u32,
) -> PipeImageView {
debug_assert!(self.is_buffer());
@ -182,7 +183,7 @@ impl PipeResource {
shader_access: shader_access,
u: pipe_image_view__bindgen_ty_1 {
buf: pipe_image_view__bindgen_ty_1__bindgen_ty_2 {
offset: 0,
offset: offset_bytes,
size: size,
},
},
@ -194,6 +195,7 @@ impl PipeResource {
format: pipe_format,
read_write: bool,
app_img_info: &AppImgInfo,
offset_pixels: u32,
) -> PipeImageView {
debug_assert!(self.is_buffer());
@ -210,7 +212,7 @@ impl PipeResource {
shader_access: shader_access,
u: pipe_image_view__bindgen_ty_1 {
tex2d_from_buf: pipe_tex2d_from_buf {
offset: 0,
offset: offset_pixels,
row_stride: app_img_info.row_stride as u16,
width: app_img_info.width as u16,
height: app_img_info.height as u16,
@ -234,6 +236,7 @@ impl PipeResource {
&self,
format: pipe_format,
size: u32,
offset_bytes: u32,
) -> pipe_sampler_view {
debug_assert!(self.is_buffer());
@ -245,7 +248,7 @@ impl PipeResource {
// write the entire union field because u_sampler_view_default_template might have left it
// in an undefined state.
res.u.buf = pipe_sampler_view__bindgen_ty_1__bindgen_ty_2 {
offset: 0,
offset: offset_bytes,
size: size,
};
@ -256,6 +259,7 @@ impl PipeResource {
&self,
format: pipe_format,
app_img_info: &AppImgInfo,
offset_pixels: u32,
) -> pipe_sampler_view {
debug_assert!(self.is_buffer());
@ -267,7 +271,7 @@ impl PipeResource {
// write the entire union field because u_sampler_view_default_template might have left it
// in an undefined state.
res.u.tex2d_from_buf = pipe_tex2d_from_buf {
offset: 0,
offset: offset_pixels,
row_stride: app_img_info.row_stride as u16,
width: app_img_info.width as u16,
height: app_img_info.height as u16,