Merge remote branch 'main/master' into radeon-rewrite
[mesa.git] / src / gallium / winsys / drm / nouveau / drm / nouveau_drm_api.c
1 #include "util/u_memory.h"
2
3 #include "nouveau_drm_api.h"
4 #include "nouveau_winsys_pipe.h"
5
6 #include "nouveau_drmif.h"
7 #include "nouveau_channel.h"
8 #include "nouveau_bo.h"
9
10 static struct pipe_screen *
11 nouveau_drm_create_screen(int fd, int pciid)
12 {
13 struct pipe_winsys *ws;
14 struct nouveau_winsys *nvws;
15 struct nouveau_device *dev = NULL;
16 struct pipe_screen *(*init)(struct pipe_winsys *,
17 struct nouveau_winsys *);
18 int ret;
19
20 ret = nouveau_device_open_existing(&dev, 0, fd, 0);
21 if (ret)
22 return NULL;
23
24 switch (dev->chipset & 0xf0) {
25 case 0x00:
26 init = nv04_screen_create;
27 break;
28 case 0x10:
29 init = nv10_screen_create;
30 break;
31 case 0x20:
32 init = nv20_screen_create;
33 break;
34 case 0x30:
35 init = nv30_screen_create;
36 break;
37 case 0x40:
38 case 0x60:
39 init = nv40_screen_create;
40 break;
41 case 0x80:
42 case 0x90:
43 case 0xa0:
44 init = nv50_screen_create;
45 break;
46 default:
47 debug_printf("%s: unknown chipset nv%02x\n", __func__,
48 dev->chipset);
49 return NULL;
50 }
51
52 ws = nouveau_pipe_winsys_new(dev);
53 if (!ws) {
54 nouveau_device_close(&dev);
55 return NULL;
56 }
57
58 nvws = nouveau_winsys_new(ws);
59 if (!nvws) {
60 ws->destroy(ws);
61 return NULL;
62 }
63
64 nouveau_pipe_winsys(ws)->pscreen = init(ws, nvws);
65 if (!nouveau_pipe_winsys(ws)->pscreen) {
66 ws->destroy(ws);
67 return NULL;
68 }
69
70 return nouveau_pipe_winsys(ws)->pscreen;
71 }
72
73 static struct pipe_context *
74 nouveau_drm_create_context(struct pipe_screen *pscreen)
75 {
76 struct nouveau_pipe_winsys *nvpws = nouveau_screen(pscreen);
77 struct pipe_context *(*init)(struct pipe_screen *, unsigned);
78 unsigned chipset = nvpws->channel->device->chipset;
79 int i;
80
81 switch (chipset & 0xf0) {
82 case 0x00:
83 init = nv04_create;
84 break;
85 case 0x10:
86 init = nv10_create;
87 break;
88 case 0x20:
89 init = nv20_create;
90 break;
91 case 0x30:
92 init = nv30_create;
93 break;
94 case 0x40:
95 case 0x60:
96 init = nv40_create;
97 break;
98 case 0x80:
99 case 0x90:
100 case 0xa0:
101 init = nv50_create;
102 break;
103 default:
104 debug_printf("%s: unknown chipset nv%02x\n", __func__, chipset);
105 return NULL;
106 }
107
108 /* Find a free slot for a pipe context, allocate a new one if needed */
109 for (i = 0; i < nvpws->nr_pctx; i++) {
110 if (nvpws->pctx[i] == NULL)
111 break;
112 }
113
114 if (i == nvpws->nr_pctx) {
115 nvpws->nr_pctx++;
116 nvpws->pctx = realloc(nvpws->pctx,
117 sizeof(*nvpws->pctx) * nvpws->nr_pctx);
118 }
119
120 nvpws->pctx[i] = init(pscreen, i);
121 return nvpws->pctx[i];
122 }
123
124 static boolean
125 nouveau_drm_pb_from_pt(struct pipe_texture *pt, struct pipe_buffer **ppb,
126 unsigned *stride)
127 {
128 return false;
129 }
130
131 static struct pipe_buffer *
132 nouveau_drm_pb_from_handle(struct pipe_screen *pscreen, const char *name,
133 unsigned handle)
134 {
135 struct nouveau_pipe_winsys *nvpws = nouveau_screen(pscreen);
136 struct nouveau_device *dev = nvpws->channel->device;
137 struct nouveau_pipe_buffer *nvpb;
138 int ret;
139
140 nvpb = CALLOC_STRUCT(nouveau_pipe_buffer);
141 if (!nvpb)
142 return NULL;
143
144 ret = nouveau_bo_handle_ref(dev, handle, &nvpb->bo);
145 if (ret) {
146 debug_printf("%s: ref name 0x%08x failed with %d\n",
147 __func__, handle, ret);
148 FREE(nvpb);
149 return NULL;
150 }
151
152 pipe_reference_init(&nvpb->base.reference, 1);
153 nvpb->base.screen = pscreen;
154 nvpb->base.alignment = 0;
155 nvpb->base.usage = PIPE_BUFFER_USAGE_GPU_READ_WRITE |
156 PIPE_BUFFER_USAGE_CPU_READ_WRITE;
157 nvpb->base.size = nvpb->bo->size;
158 return &nvpb->base;
159 }
160
161 static boolean
162 nouveau_drm_handle_from_pb(struct pipe_screen *pscreen, struct pipe_buffer *pb,
163 unsigned *handle)
164 {
165 struct nouveau_pipe_buffer *nvpb = nouveau_pipe_buffer(pb);
166
167 if (!nvpb)
168 return FALSE;
169
170 *handle = nvpb->bo->handle;
171 return TRUE;
172 }
173
174 static boolean
175 nouveau_drm_name_from_pb(struct pipe_screen *pscreen, struct pipe_buffer *pb,
176 unsigned *handle)
177 {
178 struct nouveau_pipe_buffer *nvpb = nouveau_pipe_buffer(pb);
179
180 if (!nvpb)
181 return FALSE;
182
183 return nouveau_bo_handle_get(nvpb->bo, handle) == 0;
184 }
185
186 struct drm_api drm_api_hooks = {
187 .create_screen = nouveau_drm_create_screen,
188 .create_context = nouveau_drm_create_context,
189 .buffer_from_texture = nouveau_drm_pb_from_pt,
190 .buffer_from_handle = nouveau_drm_pb_from_handle,
191 .handle_from_buffer = nouveau_drm_handle_from_pb,
192 .global_handle_from_buffer = nouveau_drm_name_from_pb,
193 };
194