[Mesa-dev] [PATCH 1/7] isl/i965/fs: SSBO/UBO buffers need size padding if not multiple of 32-bit (v2)
Jason Ekstrand
jason at jlekstrand.net
Mon Feb 26 15:54:14 UTC 2018
On Mon, Feb 26, 2018 at 6:14 AM, Jose Maria Casanova Crespo <
jmcasanova at igalia.com> wrote:
> The surfaces that backup the GPU buffers have a boundary check that
> considers that access to partial dwords are considered out-of-bounds.
> For example, buffers with 1/3 16-bit elemnts has size 2 or 6 and the
> last two bytes would always be read as 0 or its writting ignored.
>
> The introduction of 16-bit types implies that we need to align the size
> to 4-bytes multiples so that partial dwords could be read/written.
> Adding an inconditional +2 size to buffers not being multiple of 2
> solves this issue for the general cases of UBO or SSBO.
>
> But, when unsized arrays of 16-bit elements are used it is not possible
> to know if the size was padded or not. To solve this issue the
> implementation calculates the needed size of the buffer surfaces,
> as suggested by Jason:
>
> surface_size = 2 * aling_u64(buffer_size, 4) - buffer_size
>
> So when we calculate backwards the buffer_size in the backend we
> update the resinfo return value with:
>
> buffer_size = (surface_size & ~3) - (surface_size & 3)
>
> It is also exposed this buffer requirements when robust buffer access
> is enabled so these buffer sizes recommend being multiple of 4.
>
> v2: (Jason Ekstrand)
> Move padding logic fron anv to isl_surface_state
> Move calculus of original size from spirv to driver backend
> ---
> src/intel/compiler/brw_fs_nir.cpp | 27 ++++++++++++++++++++++++++-
> src/intel/isl/isl_surface_state.c | 21 ++++++++++++++++++++-
> src/intel/vulkan/anv_device.c | 11 +++++++++++
> 3 files changed, 57 insertions(+), 2 deletions(-)
>
> diff --git a/src/intel/compiler/brw_fs_nir.cpp
> b/src/intel/compiler/brw_fs_nir.cpp
> index 8efec34cc9d..d017af040b4 100644
> --- a/src/intel/compiler/brw_fs_nir.cpp
> +++ b/src/intel/compiler/brw_fs_nir.cpp
> @@ -4290,7 +4290,32 @@ fs_visitor::nir_emit_intrinsic(const fs_builder
> &bld, nir_intrinsic_instr *instr
> inst->mlen = 1;
> inst->size_written = 4 * REG_SIZE;
>
> - bld.MOV(retype(dest, ret_payload.type), component(ret_payload, 0));
> + /* SKL PRM, vol07, 3D Media GPGPU Engine, Bounds Checking and
> Faulting:
> + *
> + * "Out-of-bounds checking is always performed at a DWord
> granularity. If
> + * any part of the DWord is out-of-bounds then the whole DWord is
> + * considered out-of-bounds."
> + *
> + * This implies that types with size smaller than 4-bytes (16-bits)
> need
>
Yeah, 4-bytes (16-bits) is weird. I'd just drop the "(16-bits)".
> + * to be padded if they don't complete the last dword of the
> buffer. But
> + * as we need to maintain the original size we need to reverse the
> padding
> + * calculation to return the correct size to know the number of
> elements
> + * of an unsized array. As we stored in the last two bits of the
> size
> + * of the buffer the needed padding we calculate here:
> + *
> + * buffer_size = resinfo_size & ~3 - resinfo_size & 3
> + */
> +
> + fs_reg size_aligned32 = ubld.vgrf(BRW_REGISTER_TYPE_UD);
>
I'd call this aligned4 because it's in units of bytes.
> + fs_reg size_padding = ubld.vgrf(BRW_REGISTER_TYPE_UD);
> + fs_reg buffer_size = ubld.vgrf(BRW_REGISTER_TYPE_UD);
> +
> + ubld.AND(size_padding, component(ret_payload, 0), brw_imm_ud(3));
> + ubld.AND(size_aligned32, component(ret_payload, 0), brw_imm_ud(~3));
>
You don't really need the component() here.
> + ubld.ADD(buffer_size, size_aligned32, negate (size_padding));
> +
> + bld.MOV(retype(dest, ret_payload.type), component(buffer_size, 0));
> +
> brw_mark_surface_used(prog_data, index);
> break;
> }
> diff --git a/src/intel/isl/isl_surface_state.c
> b/src/intel/isl/isl_surface_state.c
> index bfb27fa4a44..ddc9eb53c96 100644
> --- a/src/intel/isl/isl_surface_state.c
> +++ b/src/intel/isl/isl_surface_state.c
> @@ -673,7 +673,26 @@ void
> isl_genX(buffer_fill_state_s)(void *state,
> const struct isl_buffer_fill_state_info
> *restrict info)
> {
> - uint32_t num_elements = info->size / info->stride;
> + uint64_t buffer_size = info->size;
> +
> + /* Uniform and Storage buffers need to have surface size not less that
> the
> + * aligned 32-bit size of the buffer. To calculate the array lenght on
> + * unsized arrays in StorageBuffer the last 2 bits store the padding
> size
> + * added to the surface, so we can calculate latter the original buffer
> + * size to know the number of elements.
> + *
> + * surface_size = 2 * aling_u64(buffer_size, 4) - buffer_size
>
isl_align
> + *
> + * array_size = (surface_size & ~3) - (surface_size & 3)
> + */
> + if (buffer_size % 4 &&
>
You don't need this bit as the below calculation will be a no-op in that
case.
> + (info->format == ISL_FORMAT_RAW ||
> + info->stride < isl_format_get_layout(info->format)->bpb / 8)) {
> + assert(info->stride == 1);
> + buffer_size = 2 * isl_align(buffer_size, 4) - buffer_size;
>
I think this would better match the FS calculation if it were:
uint64_t aligned_size = isl_align(buffer_size, 4);
buffer_size = aligned_size + (aligned_size - buffer_size);
The current calculation is probably fine though.
Reviewed-by: Jason Ekstrand <jason at jlekstrand.net>
> + }
> +
> + uint32_t num_elements = buffer_size / info->stride;
>
> if (GEN_GEN >= 7) {
> /* From the IVB PRM, SURFACE_STATE::Height,
> diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
> index a83b7a39f6a..cedeed56219 100644
> --- a/src/intel/vulkan/anv_device.c
> +++ b/src/intel/vulkan/anv_device.c
> @@ -2103,6 +2103,17 @@ void anv_GetBufferMemoryRequirements(
>
> pMemoryRequirements->size = buffer->size;
> pMemoryRequirements->alignment = alignment;
> +
> + /* Storage and Uniform buffers should have their size aligned to
> + * 32-bits to avoid boundary checks when last DWord is not complete.
> + * This would ensure that not internal padding would be needed for
> + * 16-bit types.
> + */
> + if (device->robust_buffer_access &&
> + (buffer->usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ||
> + buffer->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT))
> + pMemoryRequirements->size = align_u64(buffer->size, 4);
> +
> pMemoryRequirements->memoryTypeBits = memory_types;
> }
>
> --
> 2.14.3
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20180226/b80572c3/attachment-0001.html>
More information about the mesa-dev
mailing list