1 /*
2 * Copyright © 2023 Imagination Technologies Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #include <stddef.h>
25 #include <stdint.h>
26 #include <vulkan/vulkan_core.h>
27
28 #include "pvr_srv.h"
29 #include "pvr_srv_bridge.h"
30 #include "pvr_srv_sync_prim.h"
31 #include "util/log.h"
32 #include "util/simple_mtx.h"
33 #include "util/u_atomic.h"
34 #include "util/u_idalloc.h"
35 #include "vk_alloc.h"
36 #include "vk_log.h"
37
38 /* Amount of space used to hold sync prim values (in bytes). */
39 #define PVR_SRV_SYNC_PRIM_VALUE_SIZE 4
40
pvr_srv_sync_prim_block_init(struct pvr_srv_winsys * srv_ws)41 VkResult pvr_srv_sync_prim_block_init(struct pvr_srv_winsys *srv_ws)
42 {
43 /* We don't currently make use of this value, but we're required to provide
44 * a valid pointer to pvr_srv_alloc_sync_primitive_block.
45 */
46 void *sync_block_pmr;
47 uint32_t max_size;
48 VkResult result;
49
50 result =
51 pvr_srv_alloc_sync_primitive_block(srv_ws->base.render_fd,
52 &srv_ws->sync_prim_ctx.block_handle,
53 &sync_block_pmr,
54 &max_size,
55 &srv_ws->sync_prim_ctx.block_fw_addr);
56 if (result != VK_SUCCESS)
57 return result;
58
59 srv_ws->sync_prim_ctx.max_count = max_size / PVR_SRV_SYNC_PRIM_VALUE_SIZE;
60
61 /* TODO: This uses ralloc() should we be using vk_alloc()? */
62 util_idalloc_mt_init(&srv_ws->sync_prim_ctx.allocator,
63 srv_ws->sync_prim_ctx.max_count,
64 false);
65
66 return VK_SUCCESS;
67 }
68
pvr_srv_sync_prim_block_finish(struct pvr_srv_winsys * srv_ws)69 void pvr_srv_sync_prim_block_finish(struct pvr_srv_winsys *srv_ws)
70 {
71 util_idalloc_mt_fini(&srv_ws->sync_prim_ctx.allocator);
72 pvr_srv_free_sync_primitive_block(srv_ws->base.render_fd,
73 srv_ws->sync_prim_ctx.block_handle);
74 srv_ws->sync_prim_ctx.block_handle = NULL;
75 }
76
pvr_srv_sync_prim_alloc(struct pvr_srv_winsys * srv_ws)77 struct pvr_srv_sync_prim *pvr_srv_sync_prim_alloc(struct pvr_srv_winsys *srv_ws)
78 {
79 struct pvr_srv_sync_prim_ctx *ctx = &srv_ws->sync_prim_ctx;
80 struct pvr_srv_sync_prim *sync_prim;
81 unsigned id;
82
83 sync_prim = vk_alloc(srv_ws->base.alloc,
84 sizeof(*sync_prim),
85 8,
86 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
87 if (!sync_prim) {
88 vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
89 return NULL;
90 }
91
92 simple_mtx_lock(&srv_ws->sync_prim_ctx.allocator.mutex);
93
94 id = util_idalloc_alloc(&srv_ws->sync_prim_ctx.allocator.buf);
95 if (id >= ctx->max_count) {
96 /* FIXME: The last alloc expanded the idalloc. Assuming that the app can
97 * recover, we'll end up having memory that we'll never use.
98 */
99
100 util_idalloc_free(&srv_ws->sync_prim_ctx.allocator.buf, id);
101 simple_mtx_unlock(&srv_ws->sync_prim_ctx.allocator.mutex);
102 vk_free(srv_ws->base.alloc, sync_prim);
103
104 vk_errorf(NULL,
105 VK_ERROR_OUT_OF_DEVICE_MEMORY,
106 "Out of sync prim block space.");
107
108 return NULL;
109 }
110
111 simple_mtx_unlock(&srv_ws->sync_prim_ctx.allocator.mutex);
112
113 sync_prim->offset = id * PVR_SRV_SYNC_PRIM_VALUE_SIZE;
114 sync_prim->ctx = &srv_ws->sync_prim_ctx;
115 sync_prim->value = 0;
116
117 return sync_prim;
118 }
119
120 /* FIXME: Add support for freeing offsets back to the sync block. */
pvr_srv_sync_prim_free(struct pvr_srv_winsys * srv_ws,struct pvr_srv_sync_prim * sync_prim)121 void pvr_srv_sync_prim_free(struct pvr_srv_winsys *srv_ws,
122 struct pvr_srv_sync_prim *sync_prim)
123 {
124 if (sync_prim) {
125 const uint32_t id = sync_prim->offset / PVR_SRV_SYNC_PRIM_VALUE_SIZE;
126 VkResult result;
127
128 result = pvr_srv_set_sync_primitive(srv_ws->base.render_fd,
129 srv_ws->sync_prim_ctx.block_handle,
130 id,
131 0);
132 if (result != VK_SUCCESS) {
133 /* Let's keep the id allocated so no one else ends up using it. Using a
134 * non zeroed out sync prim will crash things.
135 */
136
137 mesa_logw("Failed to free sync prim. "
138 "Some sync prim block space will be lost.");
139
140 vk_free(srv_ws->base.alloc, sync_prim);
141 return;
142 }
143
144 util_idalloc_mt_free(&srv_ws->sync_prim_ctx.allocator, id);
145
146 vk_free(srv_ws->base.alloc, sync_prim);
147 }
148 }
149