diff --git a/.pick_status.json b/.pick_status.json index 8421d8fffd1..fa6580c59c7 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -1844,7 +1844,7 @@ "description": "pvr: consider the size of DMA request when setting msize of DDMADT", "nominated": true, "nomination_type": 2, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": "4873903b565a10322669db325de7284218539248", "notes": null diff --git a/src/imagination/vulkan/pds/pvr_pds.h b/src/imagination/vulkan/pds/pvr_pds.h index 8db3a1a858c..462db7ab49e 100644 --- a/src/imagination/vulkan/pds/pvr_pds.h +++ b/src/imagination/vulkan/pds/pvr_pds.h @@ -1203,6 +1203,9 @@ struct pvr_pds_const_map_entry_vertex_attr_ddmadt_oob_buffer_size { uint8_t type; uint8_t const_offset; uint8_t binding_index; + uint8_t size_in_dwords; + uint16_t offset; + uint8_t attrib_size_in_bytes; } PVR_PACKED; struct pvr_pds_const_map_entry_cond_render { diff --git a/src/imagination/vulkan/pds/pvr_pipeline_pds.c b/src/imagination/vulkan/pds/pvr_pipeline_pds.c index d33d20225f3..f3ef330bc24 100644 --- a/src/imagination/vulkan/pds/pvr_pipeline_pds.c +++ b/src/imagination/vulkan/pds/pvr_pipeline_pds.c @@ -1101,7 +1101,11 @@ void pvr_pds_generate_vertex_primary_program( oob_buffer_size->type = PVR_PDS_CONST_MAP_ENTRY_TYPE_VERTEX_ATTR_DDMADT_OOB_BUFFER_SIZE; oob_buffer_size->const_offset = const_base + 7; + oob_buffer_size->offset = vertex_dma->offset; oob_buffer_size->binding_index = vertex_dma->binding_index; + oob_buffer_size->size_in_dwords = vertex_dma->size_in_dwords; + oob_buffer_size->attrib_size_in_bytes = + vertex_dma->attrib_size_in_bytes; } else { literal_entry = pvr_prepare_next_pds_const_map_entry(&entry_write_state, diff --git a/src/imagination/vulkan/pvr_arch_cmd_buffer.c b/src/imagination/vulkan/pvr_arch_cmd_buffer.c index aef0ac3076a..1559863b878 100644 --- a/src/imagination/vulkan/pvr_arch_cmd_buffer.c +++ b/src/imagination/vulkan/pvr_arch_cmd_buffer.c @@ -5345,26 +5345,54 @@ pvr_setup_vertex_buffers(struct pvr_cmd_buffer *cmd_buffer, &cmd_buffer->vk.dynamic_graphics_state; uint32_t stride = dynamic_state->vi_binding_strides[ddmadt_src3->binding_index]; - uint32_t bound_size = binding->buffer->vk.size - binding->offset; + uint32_t valid_buffer_size = + binding->buffer->vk.size - binding->offset - ddmadt_src3->offset; + uint32_t attrib_size = ddmadt_src3->attrib_size_in_bytes; + uint32_t dma_size = ddmadt_src3->size_in_dwords * 4; uint64_t control_qword; uint32_t control_dword; assert(PVR_HAS_FEATURE(&cmd_buffer->device->pdevice->dev_info, pds_ddmadt)); - if (stride) { - bound_size -= bound_size % stride; - if (bound_size == 0) { - /* If size is zero, DMA OOB won't execute. Read will come from - * robustness buffer. + /* The DMA should cover the whole attribute, but do not overread + * more than the headroom when allocating memory for buffers. + */ + assert(dma_size >= attrib_size); + assert(dma_size <= attrib_size + PVR_BUFFER_MEMORY_PADDING_SIZE); + + /* DDMADT checks whether the whole DMA request (size indicated by + * the sizes_in_dwords field) is out of the regions set by msize. + * Set the buffer size to the last valid vertex DMA address plus + * the size of one DMA request. + * + * This also ensures at least one valid inbound DDMAD is possible. + * In case the original buffer isn't big enough for one DMA, the + * DDMADT source_address should have been already redirected to the + * robust buffer when setting up ROBUST_VERTEX_ATTRIBUTE_ADDRESS. + * + * See also the pseudocode in pvr_pds_generate_vertex_primary_program() + * before the "LAST DDMAD" mark, which explains how DDMAD(T) works. + */ + if (stride == 0) { + /* All DMA requests happen on the same address */ + valid_buffer_size = 0; + } else { + uint32_t buffer_tail_size = valid_buffer_size % stride; + valid_buffer_size -= buffer_tail_size; + if (buffer_tail_size < attrib_size && valid_buffer_size != 0) { + /* The buffer tail isn't big enough for a vertex attribute fetch + * operation so the last valid DMA happens on the last whole + * stride. */ - bound_size = stride; + valid_buffer_size -= stride; } } + valid_buffer_size += dma_size; pvr_csb_pack (&control_qword, PDSINST_DDMAD_FIELDS_SRC3, src3) { src3.test = true; - src3.msize = bound_size; + src3.msize = valid_buffer_size; } control_dword = (uint32_t)(control_qword >> 32);