Merge branch '7.8' into master
[mesa.git] / src / gallium / winsys / drm / radeon / core / radeon_buffer.c
1 /*
2 * Copyright © 2008 Jérôme Glisse
3 * 2009 Corbin Simpson
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
18 * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * The above copyright notice and this permission notice (including the
24 * next paragraph) shall be included in all copies or substantial portions
25 * of the Software.
26 */
27 /*
28 * Authors:
29 * Jérôme Glisse <glisse@freedesktop.org>
30 * Corbin Simpson <MostAwesomeDude@gmail.com>
31 */
32
33 #include "radeon_buffer.h"
34 #include "radeon_drm.h"
35
36 #include "util/u_format.h"
37 #include "util/u_math.h"
38 #include "util/u_memory.h"
39
40 #include "radeon_bo_gem.h"
41 #include <X11/Xutil.h>
42
43 struct radeon_vl_context
44 {
45 Display *display;
46 int screen;
47 Drawable drawable;
48 };
49
50 static const char *radeon_get_name(struct pipe_winsys *ws)
51 {
52 return "Radeon/GEM+KMS";
53 }
54
55 static uint32_t radeon_domain_from_usage(unsigned usage)
56 {
57 uint32_t domain = 0;
58
59 if (usage & PIPE_BUFFER_USAGE_GPU_WRITE) {
60 domain |= RADEON_GEM_DOMAIN_VRAM;
61 }
62 if (usage & PIPE_BUFFER_USAGE_PIXEL) {
63 domain |= RADEON_GEM_DOMAIN_VRAM;
64 }
65 if (usage & PIPE_BUFFER_USAGE_VERTEX) {
66 domain |= RADEON_GEM_DOMAIN_GTT;
67 }
68 if (usage & PIPE_BUFFER_USAGE_INDEX) {
69 domain |= RADEON_GEM_DOMAIN_GTT;
70 }
71
72 return domain;
73 }
74
75 static struct pipe_buffer *radeon_buffer_create(struct pipe_winsys *ws,
76 unsigned alignment,
77 unsigned usage,
78 unsigned size)
79 {
80 struct radeon_winsys *radeon_ws = (struct radeon_winsys *)ws;
81 struct radeon_pipe_buffer *radeon_buffer;
82 struct pb_desc desc;
83 uint32_t domain;
84
85 radeon_buffer = CALLOC_STRUCT(radeon_pipe_buffer);
86 if (radeon_buffer == NULL) {
87 return NULL;
88 }
89
90 pipe_reference_init(&radeon_buffer->base.reference, 1);
91 radeon_buffer->base.alignment = alignment;
92 radeon_buffer->base.usage = usage;
93 radeon_buffer->base.size = size;
94
95 if (usage & PIPE_BUFFER_USAGE_CONSTANT && is_r3xx(radeon_ws->pci_id)) {
96 /* Don't bother allocating a BO, as it'll never get to the card. */
97 desc.alignment = alignment;
98 desc.usage = usage;
99 radeon_buffer->pb = pb_malloc_buffer_create(size, &desc);
100 return &radeon_buffer->base;
101 }
102
103 domain = radeon_domain_from_usage(usage);
104
105 radeon_buffer->bo = radeon_bo_open(radeon_ws->priv->bom, 0, size,
106 alignment, domain, 0);
107 if (radeon_buffer->bo == NULL) {
108 FREE(radeon_buffer);
109 return NULL;
110 }
111 return &radeon_buffer->base;
112 }
113
114 static struct pipe_buffer *radeon_buffer_user_create(struct pipe_winsys *ws,
115 void *ptr,
116 unsigned bytes)
117 {
118 struct radeon_pipe_buffer *radeon_buffer;
119
120 radeon_buffer =
121 (struct radeon_pipe_buffer*)radeon_buffer_create(ws, 0, 0, bytes);
122 if (radeon_buffer == NULL) {
123 return NULL;
124 }
125 radeon_bo_map(radeon_buffer->bo, 1);
126 memcpy(radeon_buffer->bo->ptr, ptr, bytes);
127 radeon_bo_unmap(radeon_buffer->bo);
128 return &radeon_buffer->base;
129 }
130
131 static struct pipe_buffer *radeon_surface_buffer_create(struct pipe_winsys *ws,
132 unsigned width,
133 unsigned height,
134 enum pipe_format format,
135 unsigned usage,
136 unsigned tex_usage,
137 unsigned *stride)
138 {
139 /* Radeons enjoy things in multiples of 32. */
140 /* XXX this can be 32 when POT */
141 const unsigned alignment = 64;
142 unsigned nblocksy, size;
143
144 nblocksy = util_format_get_nblocksy(format, height);
145 *stride = align(util_format_get_stride(format, width), alignment);
146 size = *stride * nblocksy;
147
148 return radeon_buffer_create(ws, 64, usage, size);
149 }
150
151 static void radeon_buffer_del(struct pipe_buffer *buffer)
152 {
153 struct radeon_pipe_buffer *radeon_buffer =
154 (struct radeon_pipe_buffer*)buffer;
155
156 if (radeon_buffer->pb) {
157 pipe_reference_init(&radeon_buffer->pb->base.reference, 0);
158 pb_destroy(radeon_buffer->pb);
159 }
160
161 if (radeon_buffer->bo) {
162 radeon_bo_unref(radeon_buffer->bo);
163 }
164
165 FREE(radeon_buffer);
166 }
167
168 static void *radeon_buffer_map(struct pipe_winsys *ws,
169 struct pipe_buffer *buffer,
170 unsigned flags)
171 {
172 struct radeon_winsys_priv *priv = ((struct radeon_winsys *)ws)->priv;
173 struct radeon_pipe_buffer *radeon_buffer =
174 (struct radeon_pipe_buffer*)buffer;
175 int write = 0;
176
177 if (radeon_buffer->pb) {
178 return pb_map(radeon_buffer->pb, flags);
179 }
180
181 if (flags & PIPE_BUFFER_USAGE_DONTBLOCK) {
182 uint32_t domain;
183
184 if (radeon_bo_is_busy(radeon_buffer->bo, &domain))
185 return NULL;
186 }
187
188 if (radeon_bo_is_referenced_by_cs(radeon_buffer->bo, priv->cs)) {
189 priv->flush_cb(priv->flush_data);
190 }
191
192 if (flags & PIPE_BUFFER_USAGE_CPU_WRITE) {
193 write = 1;
194 }
195
196 if (radeon_bo_map(radeon_buffer->bo, write)) {
197 return NULL;
198 }
199
200 return radeon_buffer->bo->ptr;
201 }
202
203 static void radeon_buffer_unmap(struct pipe_winsys *ws,
204 struct pipe_buffer *buffer)
205 {
206 struct radeon_pipe_buffer *radeon_buffer =
207 (struct radeon_pipe_buffer*)buffer;
208
209 if (radeon_buffer->pb) {
210 pb_unmap(radeon_buffer->pb);
211 } else {
212 radeon_bo_unmap(radeon_buffer->bo);
213 }
214 }
215
216 static boolean radeon_is_buffer_referenced(struct radeon_winsys *ws,
217 struct pipe_buffer *buffer)
218 {
219 struct radeon_pipe_buffer *radeon_buffer =
220 (struct radeon_pipe_buffer*)buffer;
221 uint32_t domain;
222
223 /* Referenced by CS or HW. */
224 return radeon_bo_is_referenced_by_cs(radeon_buffer->bo, ws->priv->cs) ||
225 radeon_bo_is_busy(radeon_buffer->bo, &domain);
226 }
227
228 static void radeon_buffer_set_tiling(struct radeon_winsys *ws,
229 struct pipe_buffer *buffer,
230 uint32_t pitch,
231 boolean microtiled,
232 boolean macrotiled)
233 {
234 struct radeon_winsys_priv *priv = ((struct radeon_winsys *)ws)->priv;
235 struct radeon_pipe_buffer *radeon_buffer =
236 (struct radeon_pipe_buffer*)buffer;
237 uint32_t flags = 0, old_flags, old_pitch;
238
239 if (microtiled) {
240 flags |= RADEON_BO_FLAGS_MICRO_TILE;
241 }
242 if (macrotiled) {
243 flags |= RADEON_BO_FLAGS_MACRO_TILE;
244 }
245
246 radeon_bo_get_tiling(radeon_buffer->bo, &old_flags, &old_pitch);
247
248 if (flags != old_flags || pitch != old_pitch) {
249 /* Tiling determines how DRM treats the buffer data.
250 * We must flush CS when changing it if the buffer is referenced. */
251 if (radeon_bo_is_referenced_by_cs(radeon_buffer->bo, priv->cs)) {
252 priv->flush_cb(priv->flush_data);
253 }
254
255 radeon_bo_set_tiling(radeon_buffer->bo, flags, pitch);
256 }
257 }
258
259 static void radeon_fence_reference(struct pipe_winsys *ws,
260 struct pipe_fence_handle **ptr,
261 struct pipe_fence_handle *pfence)
262 {
263 }
264
265 static int radeon_fence_signalled(struct pipe_winsys *ws,
266 struct pipe_fence_handle *pfence,
267 unsigned flag)
268 {
269 return 1;
270 }
271
272 static int radeon_fence_finish(struct pipe_winsys *ws,
273 struct pipe_fence_handle *pfence,
274 unsigned flag)
275 {
276 return 0;
277 }
278
279 /* Create a buffer from a handle. */
280 static struct pipe_buffer* radeon_buffer_from_handle(struct radeon_winsys *radeon_ws,
281 struct pipe_screen *screen,
282 struct winsys_handle *whandle,
283 unsigned *stride)
284 {
285 struct radeon_bo_manager* bom = radeon_ws->priv->bom;
286 struct radeon_pipe_buffer* radeon_buffer;
287 struct radeon_bo* bo = NULL;
288
289 bo = radeon_bo_open(bom, whandle->handle, 0, 0, 0, 0);
290 if (bo == NULL) {
291 return NULL;
292 }
293
294 radeon_buffer = CALLOC_STRUCT(radeon_pipe_buffer);
295 if (radeon_buffer == NULL) {
296 radeon_bo_unref(bo);
297 return NULL;
298 }
299
300 pipe_reference_init(&radeon_buffer->base.reference, 1);
301 radeon_buffer->base.screen = screen;
302 radeon_buffer->base.usage = PIPE_BUFFER_USAGE_PIXEL;
303 radeon_buffer->bo = bo;
304
305 *stride = whandle->stride;
306
307 return &radeon_buffer->base;
308 }
309
310 static boolean radeon_buffer_get_handle(struct radeon_winsys *radeon_ws,
311 struct pipe_buffer *buffer,
312 unsigned stride,
313 struct winsys_handle *whandle)
314 {
315 int retval, fd;
316 struct drm_gem_flink flink;
317 struct radeon_pipe_buffer* radeon_buffer;
318
319 radeon_buffer = (struct radeon_pipe_buffer*)buffer;
320
321
322 if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) {
323 if (!radeon_buffer->flinked) {
324 fd = radeon_ws->priv->fd;
325
326 flink.handle = radeon_buffer->bo->handle;
327
328 retval = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
329 if (retval) {
330 debug_printf("radeon: DRM_IOCTL_GEM_FLINK failed, error %d\n",
331 retval);
332 return FALSE;
333 }
334
335 radeon_buffer->flink = flink.name;
336 radeon_buffer->flinked = TRUE;
337 }
338
339 whandle->handle = radeon_buffer->flink;
340 } else if (whandle->type == DRM_API_HANDLE_TYPE_KMS) {
341 whandle->handle = ((struct radeon_pipe_buffer*)buffer)->bo->handle;
342 }
343 whandle->stride = stride;
344
345 return TRUE;
346 }
347
348 struct radeon_winsys* radeon_pipe_winsys(int fd)
349 {
350 struct radeon_winsys* radeon_ws;
351
352 radeon_ws = CALLOC_STRUCT(radeon_winsys);
353 if (radeon_ws == NULL) {
354 return NULL;
355 }
356
357 radeon_ws->priv = CALLOC_STRUCT(radeon_winsys_priv);
358 if (radeon_ws->priv == NULL) {
359 FREE(radeon_ws);
360 return NULL;
361 }
362
363 radeon_ws->priv->fd = fd;
364 radeon_ws->priv->bom = radeon_bo_manager_gem_ctor(fd);
365
366 radeon_ws->base.flush_frontbuffer = NULL; /* overriden by co-state tracker */
367
368 radeon_ws->base.buffer_create = radeon_buffer_create;
369 radeon_ws->base.user_buffer_create = radeon_buffer_user_create;
370 radeon_ws->base.surface_buffer_create = radeon_surface_buffer_create;
371 radeon_ws->base.buffer_map = radeon_buffer_map;
372 radeon_ws->base.buffer_unmap = radeon_buffer_unmap;
373 radeon_ws->base.buffer_destroy = radeon_buffer_del;
374
375 radeon_ws->base.fence_reference = radeon_fence_reference;
376 radeon_ws->base.fence_signalled = radeon_fence_signalled;
377 radeon_ws->base.fence_finish = radeon_fence_finish;
378
379 radeon_ws->base.get_name = radeon_get_name;
380
381 radeon_ws->buffer_set_tiling = radeon_buffer_set_tiling;
382 radeon_ws->buffer_from_handle = radeon_buffer_from_handle;
383 radeon_ws->buffer_get_handle = radeon_buffer_get_handle;
384
385 radeon_ws->is_buffer_referenced = radeon_is_buffer_referenced;
386
387 return radeon_ws;
388 }