X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Ffreedreno%2Fvulkan%2Ftu_cs.c;h=48242f813ada953826896797c6d3881b56a6a0e1;hb=b69d5d6e19568c2098638af014abb8c541402822;hp=108ac707e29786b35384c97dec80673709786114;hpb=2774a1b97d450c81108c4f8d00c948d8e3427c4f;p=mesa.git diff --git a/src/freedreno/vulkan/tu_cs.c b/src/freedreno/vulkan/tu_cs.c index 108ac707e29..48242f813ad 100644 --- a/src/freedreno/vulkan/tu_cs.c +++ b/src/freedreno/vulkan/tu_cs.c @@ -27,15 +27,27 @@ * Initialize a command stream. */ void -tu_cs_init(struct tu_cs *cs) +tu_cs_init(struct tu_cs *cs, enum tu_cs_mode mode, uint32_t initial_size) { - cs->start = cs->cur = cs->end = NULL; + assert(mode != TU_CS_MODE_EXTERNAL); - cs->entry_count = cs->entry_capacity = 0; - cs->entries = NULL; + memset(cs, 0, sizeof(*cs)); - cs->bo_count = cs->bo_capacity = 0; - cs->bos = NULL; + cs->mode = mode; + cs->next_bo_size = initial_size; +} + +/** + * Initialize a command stream as a wrapper to an external buffer. + */ +void +tu_cs_init_external(struct tu_cs *cs, uint32_t *start, uint32_t *end) +{ + memset(cs, 0, sizeof(*cs)); + + cs->mode = TU_CS_MODE_EXTERNAL; + cs->start = cs->reserved_end = cs->cur = start; + cs->end = end; } /** @@ -98,8 +110,14 @@ tu_cs_is_empty(const struct tu_cs *cs) * be emitted to the new BO. */ static VkResult -tu_cs_add_bo(struct tu_device *dev, struct tu_cs *cs, uint32_t byte_size) +tu_cs_add_bo(struct tu_device *dev, struct tu_cs *cs, uint32_t size) { + /* no BO for TU_CS_MODE_EXTERNAL */ + assert(cs->mode != TU_CS_MODE_EXTERNAL); + + /* no dangling command packet */ + assert(tu_cs_is_empty(cs)); + /* grow cs->bos if needed */ if (cs->bo_count == cs->bo_capacity) { uint32_t new_capacity = MAX2(4, 2 * cs->bo_capacity); @@ -116,7 +134,7 @@ tu_cs_add_bo(struct tu_device *dev, struct tu_cs *cs, uint32_t byte_size) if (!new_bo) return VK_ERROR_OUT_OF_HOST_MEMORY; - VkResult result = tu_bo_init_new(dev, new_bo, byte_size); + VkResult result = tu_bo_init_new(dev, new_bo, size * sizeof(uint32_t)); if (result != VK_SUCCESS) { free(new_bo); return result; @@ -131,7 +149,7 @@ tu_cs_add_bo(struct tu_device *dev, struct tu_cs *cs, uint32_t byte_size) cs->bos[cs->bo_count++] = new_bo; - cs->start = cs->cur = (uint32_t *) new_bo->map; + cs->start = cs->cur = cs->reserved_end = (uint32_t *) new_bo->map; cs->end = cs->start + new_bo->size / sizeof(uint32_t); return VK_SUCCESS; @@ -141,8 +159,11 @@ tu_cs_add_bo(struct tu_device *dev, struct tu_cs *cs, uint32_t byte_size) * Reserve an IB entry. */ static VkResult -tu_cs_reserve_entry(struct tu_cs *cs) +tu_cs_reserve_entry(struct tu_device *dev, struct tu_cs *cs) { + /* entries are only for TU_CS_MODE_GROW */ + assert(cs->mode == TU_CS_MODE_GROW); + /* grow cs->entries if needed */ if (cs->entry_count == cs->entry_capacity) { uint32_t new_capacity = MAX2(4, cs->entry_capacity * 2); @@ -165,6 +186,9 @@ tu_cs_reserve_entry(struct tu_cs *cs) static void tu_cs_add_entry(struct tu_cs *cs) { + /* entries are only for TU_CS_MODE_GROW */ + assert(cs->mode == TU_CS_MODE_GROW); + /* disallow empty entry */ assert(!tu_cs_is_empty(cs)); @@ -186,46 +210,130 @@ tu_cs_add_entry(struct tu_cs *cs) } /** - * Begin (or continue) command packet emission. This will reserve space from - * the command stream for at least \a reserve_size uint32_t values. + * Begin (or continue) command packet emission. This does nothing but sanity + * checks currently. \a cs must not be in TU_CS_MODE_SUB_STREAM mode. */ -VkResult -tu_cs_begin(struct tu_device *dev, struct tu_cs *cs, uint32_t reserve_size) +void +tu_cs_begin(struct tu_cs *cs) { - /* no dangling command packet */ + assert(cs->mode != TU_CS_MODE_SUB_STREAM); assert(tu_cs_is_empty(cs)); +} - if (tu_cs_get_space(cs) < reserve_size) { - uint32_t new_size = MAX2(16384, reserve_size * sizeof(uint32_t)); - if (cs->bo_count) - new_size = MAX2(new_size, cs->bos[cs->bo_count - 1]->size * 2); +/** + * End command packet emission. This adds an IB entry when \a cs is in + * TU_CS_MODE_GROW mode. + */ +void +tu_cs_end(struct tu_cs *cs) +{ + assert(cs->mode != TU_CS_MODE_SUB_STREAM); - VkResult result = tu_cs_add_bo(dev, cs, new_size); - if (result != VK_SUCCESS) - return result; - } + if (cs->mode == TU_CS_MODE_GROW && !tu_cs_is_empty(cs)) + tu_cs_add_entry(cs); +} + +/** + * Begin command packet emission to a sub-stream. \a cs must be in + * TU_CS_MODE_SUB_STREAM mode. + * + * Return \a sub_cs which is in TU_CS_MODE_EXTERNAL mode. tu_cs_begin and + * tu_cs_reserve_space are implied and \a sub_cs is ready for command packet + * emission. + */ +VkResult +tu_cs_begin_sub_stream(struct tu_device *dev, + struct tu_cs *cs, + uint32_t size, + struct tu_cs *sub_cs) +{ + assert(cs->mode == TU_CS_MODE_SUB_STREAM); + assert(size); + + VkResult result = tu_cs_reserve_space(dev, cs, size); + if (result != VK_SUCCESS) + return result; - assert(tu_cs_get_space(cs) >= reserve_size); + tu_cs_init_external(sub_cs, cs->cur, cs->reserved_end); + tu_cs_begin(sub_cs); + result = tu_cs_reserve_space(dev, sub_cs, size); + assert(result == VK_SUCCESS); return VK_SUCCESS; } /** - * End command packet emission by adding an IB entry for the command packets - * emitted since the last call to tu_cs_begin. + * End command packet emission to a sub-stream. \a sub_cs becomes invalid + * after this call. + * + * Return an IB entry for the sub-stream. The entry has the same lifetime as + * \a cs. + */ +struct tu_cs_entry +tu_cs_end_sub_stream(struct tu_cs *cs, struct tu_cs *sub_cs) +{ + assert(cs->mode == TU_CS_MODE_SUB_STREAM); + assert(cs->bo_count); + assert(sub_cs->start == cs->cur && sub_cs->end == cs->reserved_end); + tu_cs_sanity_check(sub_cs); + + tu_cs_end(sub_cs); + + cs->cur = sub_cs->cur; + + struct tu_cs_entry entry = { + .bo = cs->bos[cs->bo_count - 1], + .size = tu_cs_get_size(cs) * sizeof(uint32_t), + .offset = tu_cs_get_offset(cs) * sizeof(uint32_t), + }; + + cs->start = cs->cur; + + return entry; +} + +/** + * Reserve space from a command stream for \a reserved_size uint32_t values. + * This never fails when \a cs has mode TU_CS_MODE_EXTERNAL. */ VkResult -tu_cs_end(struct tu_cs *cs) +tu_cs_reserve_space(struct tu_device *dev, + struct tu_cs *cs, + uint32_t reserved_size) { - /* no command packet at all */ - if (tu_cs_is_empty(cs)) - return VK_SUCCESS; + if (tu_cs_get_space(cs) < reserved_size) { + if (cs->mode == TU_CS_MODE_EXTERNAL) { + unreachable("cannot grow external buffer"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } - VkResult result = tu_cs_reserve_entry(cs); - if (result != VK_SUCCESS) - return result; + /* add an entry for the exiting command packets */ + if (!tu_cs_is_empty(cs)) { + /* no direct command packet for TU_CS_MODE_SUB_STREAM */ + assert(cs->mode != TU_CS_MODE_SUB_STREAM); - tu_cs_add_entry(cs); + tu_cs_add_entry(cs); + } + + /* switch to a new BO */ + uint32_t new_size = MAX2(cs->next_bo_size, reserved_size); + VkResult result = tu_cs_add_bo(dev, cs, new_size); + if (result != VK_SUCCESS) + return result; + + /* double the size for the next bo */ + new_size <<= 1; + if (cs->next_bo_size < new_size) + cs->next_bo_size = new_size; + } + + assert(tu_cs_get_space(cs) >= reserved_size); + cs->reserved_end = cs->cur + reserved_size; + + if (cs->mode == TU_CS_MODE_GROW) { + /* reserve an entry for the next call to this function or tu_cs_end */ + return tu_cs_reserve_entry(dev, cs); + } return VK_SUCCESS; } @@ -237,6 +345,12 @@ tu_cs_end(struct tu_cs *cs) void tu_cs_reset(struct tu_device *dev, struct tu_cs *cs) { + if (cs->mode == TU_CS_MODE_EXTERNAL) { + assert(!cs->bo_count && !cs->entry_count); + cs->reserved_end = cs->cur = cs->start; + return; + } + for (uint32_t i = 0; i + 1 < cs->bo_count; ++i) { tu_bo_finish(dev, cs->bos[i]); free(cs->bos[i]); @@ -246,7 +360,7 @@ tu_cs_reset(struct tu_device *dev, struct tu_cs *cs) cs->bos[0] = cs->bos[cs->bo_count - 1]; cs->bo_count = 1; - cs->start = cs->cur = (uint32_t *) cs->bos[0]->map; + cs->start = cs->cur = cs->reserved_end = (uint32_t *) cs->bos[0]->map; cs->end = cs->start + cs->bos[0]->size / sizeof(uint32_t); }