| /* |
| * Copyright © 2022 Imagination Technologies Ltd. |
| * |
| * based in part on anv driver which is: |
| * Copyright © 2015 Intel Corporation |
| * |
| * based in part on v3dv_cl.h which is: |
| * Copyright © 2019 Raspberry Pi |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a copy |
| * of this software and associated documentation files (the "Software"), to deal |
| * in the Software without restriction, including without limitation the rights |
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| * copies of the Software, and to permit persons to whom the Software is |
| * furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| */ |
| |
| #ifndef PVR_CSB_H |
| #define PVR_CSB_H |
| |
| #include <assert.h> |
| #include <stdbool.h> |
| #include <stdint.h> |
| #include <vulkan/vulkan.h> |
| |
| #include "pvr_bo.h" |
| #include "pvr_types.h" |
| #include "pvr_winsys.h" |
| #include "util/list.h" |
| #include "util/macros.h" |
| #include "util/u_dynarray.h" |
| |
| #define __pvr_address_type pvr_dev_addr_t |
| #define __pvr_get_address(pvr_dev_addr) (pvr_dev_addr).addr |
| /* clang-format off */ |
| #define __pvr_make_address(addr_u64) PVR_DEV_ADDR(addr_u64) |
| /* clang-format on */ |
| |
| #include "csbgen/rogue_hwdefs.h" |
| |
| struct pvr_device; |
| |
| enum pvr_cmd_stream_type { |
| PVR_CMD_STREAM_TYPE_INVALID = 0, /* explicitly treat 0 as invalid */ |
| PVR_CMD_STREAM_TYPE_GRAPHICS, |
| PVR_CMD_STREAM_TYPE_GRAPHICS_DEFERRED, |
| PVR_CMD_STREAM_TYPE_COMPUTE, |
| }; |
| |
| struct pvr_csb { |
| struct pvr_device *device; |
| |
| /* Pointer to current csb buffer object */ |
| struct pvr_bo *pvr_bo; |
| |
| /* pointers to current bo memory */ |
| void *start; |
| void *end; |
| void *next; |
| |
| /* List of csb buffer objects */ |
| struct list_head pvr_bo_list; |
| |
| struct util_dynarray deferred_cs_mem; |
| |
| enum pvr_cmd_stream_type stream_type; |
| |
| /* Current error status of the command buffer. Used to track inconsistent |
| * or incomplete command buffer states that are the consequence of run-time |
| * errors such as out of memory scenarios. We want to track this in the |
| * csb because the command buffer object is not visible to some parts |
| * of the driver. |
| */ |
| VkResult status; |
| }; |
| |
| /** |
| * \brief Gets the status of the csb. |
| * |
| * \param[in] csb Control Stream Builder object. |
| * \return VK_SUCCESS if the csb hasn't encountered any error or error code |
| * otherwise. |
| */ |
| static inline VkResult pvr_csb_get_status(const struct pvr_csb *csb) |
| { |
| return csb->status; |
| } |
| |
| /** |
| * \brief Checks if the control stream is empty or not. |
| * |
| * \param[in] csb Control Stream Builder object. |
| * \return true if csb is empty false otherwise. |
| */ |
| static inline bool pvr_csb_is_empty(const struct pvr_csb *csb) |
| { |
| return list_is_empty(&csb->pvr_bo_list); |
| } |
| |
| static inline pvr_dev_addr_t |
| pvr_csb_get_start_address(const struct pvr_csb *csb) |
| { |
| if (!pvr_csb_is_empty(csb)) { |
| struct pvr_bo *pvr_bo = |
| list_first_entry(&csb->pvr_bo_list, struct pvr_bo, link); |
| |
| return pvr_bo->vma->dev_addr; |
| } |
| |
| return PVR_DEV_ADDR_INVALID; |
| } |
| |
| void pvr_csb_init(struct pvr_device *device, |
| enum pvr_cmd_stream_type stream_type, |
| struct pvr_csb *csb); |
| void pvr_csb_finish(struct pvr_csb *csb); |
| void *pvr_csb_alloc_dwords(struct pvr_csb *csb, uint32_t num_dwords); |
| VkResult pvr_csb_copy(struct pvr_csb *csb_dst, struct pvr_csb *csb_src); |
| void pvr_csb_emit_link(struct pvr_csb *csb, pvr_dev_addr_t addr, bool ret); |
| VkResult pvr_csb_emit_return(struct pvr_csb *csb); |
| VkResult pvr_csb_emit_terminate(struct pvr_csb *csb); |
| |
| #define PVRX(x) ROGUE_##x |
| #define pvr_cmd_length(x) PVRX(x##_length) |
| #define pvr_cmd_header(x) PVRX(x##_header) |
| #define pvr_cmd_pack(x) PVRX(x##_pack) |
| #define pvr_cmd_unpack(x) PVRX(x##_unpack) |
| |
| /** |
| * \brief Merges dwords0 and dwords1 arrays and stores the result into the |
| * control stream pointed by the csb object. |
| * |
| * \param[in] csb Control Stream Builder object. |
| * \param[in] dwords0 Dwords0 array. |
| * \param[in] dwords1 Dwords1 array. |
| */ |
| #define pvr_csb_emit_merge(csb, dwords0, dwords1) \ |
| do { \ |
| uint32_t *dw; \ |
| STATIC_ASSERT(ARRAY_SIZE(dwords0) == ARRAY_SIZE(dwords1)); \ |
| dw = pvr_csb_alloc_dwords(csb, ARRAY_SIZE(dwords0)); \ |
| if (!dw) \ |
| break; \ |
| for (uint32_t i = 0; i < ARRAY_SIZE(dwords0); i++) \ |
| dw[i] = (dwords0)[i] | (dwords1)[i]; \ |
| } while (0) |
| |
| /** |
| * \brief Packs a command/state into one or more dwords and stores them into |
| * the control stream pointed by the csb object. |
| * |
| * \param[in] csb Control Stream Builder object. |
| * \param[in] cmd Command/state type. |
| * \param[in,out] name Name to give to the command/state structure variable, |
| * which contains the information to be packed. This can be |
| * used by the caller to modify the command or state |
| * information before it's packed. |
| */ |
| #define pvr_csb_emit(csb, cmd, name) \ |
| for (struct PVRX(cmd) \ |
| name = { pvr_cmd_header(cmd) }, \ |
| *_dst = pvr_csb_alloc_dwords(csb, pvr_cmd_length(cmd)); \ |
| __builtin_expect(_dst != NULL, 1); \ |
| ({ \ |
| pvr_cmd_pack(cmd)(_dst, &name); \ |
| _dst = NULL; \ |
| })) |
| |
| /** |
| * \brief Stores dword into the control stream pointed by the csb object. |
| * |
| * \param[in] csb Control Stream Builder object. |
| * \param[in] dword Dword to store into control stream. |
| */ |
| #define pvr_csb_emit_dword(csb, dword) \ |
| do { \ |
| uint32_t *dw; \ |
| STATIC_ASSERT(sizeof(dword) == sizeof(uint32_t)); \ |
| dw = pvr_csb_alloc_dwords(csb, 1U); \ |
| if (!dw) \ |
| break; \ |
| *dw = dword; \ |
| } while (0) |
| |
| /** |
| * \name Raw command/state buffer helpers. |
| * These provide functionality to read or write control/state words from/to a |
| * raw buffer, accessed through a pointer, with some extra checks. |
| * |
| * The raw buffer doesn't have to be related to a control stream builder object |
| * so these can be used with any cpu accessible buffer. |
| */ |
| /**@{*/ |
| |
| /** |
| * \brief Packs a command/state into one or more dwords and stores them in the |
| * memory pointed to by _dst. |
| * |
| * \param[out] _dst Pointer to store the packed command/state. |
| * \param[in] cmd Command/state type. |
| * \param[in,out] name Name to give to the command/state structure variable, |
| * which contains the information to be packed and emitted. |
| * This can be used by the caller to modify the command or |
| * state information before it's packed. |
| */ |
| #define pvr_csb_pack(_dst, cmd, name) \ |
| for (struct PVRX(cmd) name = { pvr_cmd_header(cmd) }, \ |
| *_loop_terminate = &name; \ |
| __builtin_expect(_loop_terminate != NULL, 1); \ |
| ({ \ |
| STATIC_ASSERT(sizeof(*(_dst)) == pvr_cmd_length(cmd) * 4); \ |
| pvr_cmd_pack(cmd)((_dst), &name); \ |
| _loop_terminate = NULL; \ |
| })) |
| |
| /** |
| * \brief Unpacks one or more dwords into a command/state struct. |
| * |
| * Unlike pvr_csb_pack, this returns the stack-allocated struct directly |
| * since it is not needed afterwards. |
| * |
| * \param[in] _src Pointer to read the packed command/state from. |
| * \param[in] cmd Command/state type. |
| */ |
| #define pvr_csb_unpack(_src, cmd) \ |
| ({ \ |
| struct PVRX(cmd) _name; \ |
| STATIC_ASSERT(sizeof(*(_src)) == pvr_cmd_length(cmd) * 4); \ |
| pvr_cmd_unpack(cmd)((_src), &_name); \ |
| _name; \ |
| }) |
| |
| /** |
| * \brief Writes a command/state word value into a raw buffer and advance. |
| * |
| * The buffer pointer is incremented appropriately based on the control stream |
| * word length. |
| * |
| * \param[in,out] dst Raw buffer pointer for writing. |
| * \param[in] cmd Command/state type. |
| * \param[in] val Pre-packed value to write. |
| */ |
| #define pvr_csb_write_value(dst, cmd, val) \ |
| do { \ |
| static_assert(sizeof(*(dst)) == pvr_cmd_length(cmd) * sizeof(uint32_t), \ |
| "Size mismatch"); \ |
| static_assert(sizeof(*(dst)) == sizeof(val), "Size mismatch"); \ |
| *(dst) = (val); \ |
| (dst)++; \ |
| } while (0) |
| |
| /** |
| * \brief Packs a command/state word struct and writes the value into a raw |
| * buffer and advance. |
| * |
| * The buffer pointer is incremented appropriately based on the control stream |
| * word length. |
| * |
| * \param[in,out] dst Raw buffer pointer for writing. |
| * \param[in] cmd Command/state type. |
| * \param[in] val Command/state struct to pack and write. |
| */ |
| #define pvr_csb_write_struct(dst, cmd, val) \ |
| do { \ |
| static_assert(sizeof(*(dst)) == pvr_cmd_length(cmd) * sizeof(uint32_t), \ |
| "Size mismatch"); \ |
| pvr_cmd_pack(cmd)((dst), (val)); \ |
| (dst)++; \ |
| } while (0) |
| |
| /**@}*/ |
| /* End of \name Raw command/state buffer helpers. */ |
| |
| #endif /* PVR_CSB_H */ |