• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2022 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 <errno.h>
25 #include <stddef.h>
26 #include <stdint.h>
27 #include <vulkan/vulkan.h>
28 #include <xf86drm.h>
29 
30 #include "drm-uapi/pvr_drm.h"
31 #include "pvr_private.h"
32 #include "pvr_drm.h"
33 #include "pvr_drm_job_common.h"
34 #include "pvr_drm_job_transfer.h"
35 #include "pvr_winsys.h"
36 #include "pvr_winsys_helper.h"
37 #include "util/macros.h"
38 #include "vk_alloc.h"
39 #include "vk_drm_syncobj.h"
40 #include "vk_log.h"
41 
42 struct pvr_drm_winsys_transfer_ctx {
43    struct pvr_winsys_transfer_ctx base;
44 
45    uint32_t handle;
46 };
47 
48 #define to_pvr_drm_winsys_transfer_ctx(ctx) \
49    container_of(ctx, struct pvr_drm_winsys_transfer_ctx, base)
50 
pvr_drm_winsys_transfer_ctx_create(struct pvr_winsys * ws,const struct pvr_winsys_transfer_ctx_create_info * create_info,struct pvr_winsys_transfer_ctx ** const ctx_out)51 VkResult pvr_drm_winsys_transfer_ctx_create(
52    struct pvr_winsys *ws,
53    const struct pvr_winsys_transfer_ctx_create_info *create_info,
54    struct pvr_winsys_transfer_ctx **const ctx_out)
55 {
56    struct pvr_drm_winsys *drm_ws = to_pvr_drm_winsys(ws);
57    struct drm_pvr_ioctl_create_context_args ctx_args = {
58       .type = DRM_PVR_CTX_TYPE_TRANSFER_FRAG,
59       .priority = pvr_drm_from_winsys_priority(create_info->priority),
60       .vm_context_handle = drm_ws->vm_context,
61    };
62 
63    struct pvr_drm_winsys_transfer_ctx *drm_ctx;
64    VkResult result;
65 
66    drm_ctx = vk_zalloc(ws->alloc,
67                        sizeof(*drm_ctx),
68                        8,
69                        VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
70    if (!drm_ctx) {
71       result = vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
72       goto err_out;
73    }
74 
75    result = pvr_ioctlf(ws->render_fd,
76                        DRM_IOCTL_PVR_CREATE_CONTEXT,
77                        &ctx_args,
78                        VK_ERROR_INITIALIZATION_FAILED,
79                        "Failed to create transfer context");
80    if (result)
81       goto err_free_ctx;
82 
83    drm_ctx->base.ws = ws;
84    drm_ctx->handle = ctx_args.handle;
85 
86    *ctx_out = &drm_ctx->base;
87 
88    return VK_SUCCESS;
89 
90 err_free_ctx:
91    vk_free(ws->alloc, drm_ctx);
92 
93 err_out:
94    return result;
95 }
96 
pvr_drm_winsys_transfer_ctx_destroy(struct pvr_winsys_transfer_ctx * ctx)97 void pvr_drm_winsys_transfer_ctx_destroy(struct pvr_winsys_transfer_ctx *ctx)
98 {
99    struct pvr_drm_winsys *drm_ws = to_pvr_drm_winsys(ctx->ws);
100    struct pvr_drm_winsys_transfer_ctx *drm_ctx =
101       to_pvr_drm_winsys_transfer_ctx(ctx);
102    struct drm_pvr_ioctl_destroy_context_args args = {
103       .handle = drm_ctx->handle,
104    };
105 
106    pvr_ioctlf(drm_ws->base.render_fd,
107               DRM_IOCTL_PVR_DESTROY_CONTEXT,
108               &args,
109               VK_ERROR_UNKNOWN,
110               "Error destroying transfer context");
111 
112    vk_free(drm_ws->base.alloc, drm_ctx);
113 }
114 
pvr_winsys_transfer_flags_to_drm(const struct pvr_winsys_transfer_cmd_flags * ws_flags)115 static uint32_t pvr_winsys_transfer_flags_to_drm(
116    const struct pvr_winsys_transfer_cmd_flags *ws_flags)
117 {
118    uint32_t flags = 0U;
119 
120    if (ws_flags->use_single_core)
121       flags |= DRM_PVR_SUBMIT_JOB_TRANSFER_CMD_SINGLE_CORE;
122 
123    return flags;
124 }
125 
pvr_drm_winsys_transfer_submit(const struct pvr_winsys_transfer_ctx * ctx,const struct pvr_winsys_transfer_submit_info * submit_info,UNUSED const struct pvr_device_info * const dev_info,struct vk_sync * signal_sync)126 VkResult pvr_drm_winsys_transfer_submit(
127    const struct pvr_winsys_transfer_ctx *ctx,
128    const struct pvr_winsys_transfer_submit_info *submit_info,
129    UNUSED const struct pvr_device_info *const dev_info,
130    struct vk_sync *signal_sync)
131 {
132    const struct pvr_drm_winsys *drm_ws = to_pvr_drm_winsys(ctx->ws);
133    const struct pvr_drm_winsys_transfer_ctx *drm_ctx =
134       to_pvr_drm_winsys_transfer_ctx(ctx);
135 
136    struct drm_pvr_sync_op sync_ops[2];
137 
138    struct drm_pvr_job job_args = {
139       .type = DRM_PVR_JOB_TYPE_TRANSFER_FRAG,
140       .cmd_stream = (__u64)&submit_info->cmds[0].fw_stream[0],
141       .cmd_stream_len = submit_info->cmds[0].fw_stream_len,
142       .flags = pvr_winsys_transfer_flags_to_drm(&submit_info->cmds[0].flags),
143       .context_handle = drm_ctx->handle,
144       .sync_ops = DRM_PVR_OBJ_ARRAY(0, sync_ops),
145    };
146 
147    struct drm_pvr_ioctl_submit_jobs_args args = {
148       .jobs = DRM_PVR_OBJ_ARRAY(1, &job_args),
149    };
150 
151    assert(submit_info->cmd_count == 1);
152 
153    if (submit_info->wait) {
154       struct vk_sync *sync = submit_info->wait;
155 
156       assert(!(sync->flags & VK_SYNC_IS_TIMELINE));
157       sync_ops[job_args.sync_ops.count++] = (struct drm_pvr_sync_op){
158          .handle = vk_sync_as_drm_syncobj(sync)->syncobj,
159          .flags = DRM_PVR_SYNC_OP_FLAG_WAIT |
160                   DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_SYNCOBJ,
161          .value = 0,
162       };
163    }
164 
165    if (signal_sync) {
166       assert(!(signal_sync->flags & VK_SYNC_IS_TIMELINE));
167       sync_ops[job_args.sync_ops.count++] = (struct drm_pvr_sync_op){
168          .handle = vk_sync_as_drm_syncobj(signal_sync)->syncobj,
169          .flags = DRM_PVR_SYNC_OP_FLAG_SIGNAL |
170                   DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_SYNCOBJ,
171          .value = 0,
172       };
173    }
174 
175    /* Returns VK_ERROR_OUT_OF_DEVICE_MEMORY to match pvrsrv. */
176    return pvr_ioctlf(drm_ws->base.render_fd,
177                      DRM_IOCTL_PVR_SUBMIT_JOBS,
178                      &args,
179                      VK_ERROR_OUT_OF_DEVICE_MEMORY,
180                      "Failed to submit transfer job");
181 }
182