2 * Copyright © 2008 Jérôme Glisse
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:
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.
23 * The above copyright notice and this permission notice (including the
24 * next paragraph) shall be included in all copies or substantial portions
29 * Jérôme Glisse <glisse@freedesktop.org>
30 * Corbin Simpson <MostAwesomeDude@gmail.com>
33 #include "radeon_buffer.h"
34 #include "radeon_drm.h"
36 #include "util/u_format.h"
37 #include "util/u_math.h"
38 #include "util/u_memory.h"
40 #include "radeon_bo_gem.h"
41 #include <X11/Xutil.h>
43 struct radeon_vl_context
50 static const char *radeon_get_name(struct pipe_winsys
*ws
)
52 return "Radeon/GEM+KMS";
55 static uint32_t radeon_domain_from_usage(unsigned usage
)
59 if (usage
& PIPE_BUFFER_USAGE_GPU_WRITE
) {
60 domain
|= RADEON_GEM_DOMAIN_VRAM
;
62 if (usage
& PIPE_BUFFER_USAGE_PIXEL
) {
63 domain
|= RADEON_GEM_DOMAIN_VRAM
;
65 if (usage
& PIPE_BUFFER_USAGE_VERTEX
) {
66 domain
|= RADEON_GEM_DOMAIN_GTT
;
68 if (usage
& PIPE_BUFFER_USAGE_INDEX
) {
69 domain
|= RADEON_GEM_DOMAIN_GTT
;
75 static struct pipe_buffer
*radeon_buffer_create(struct pipe_winsys
*ws
,
80 struct radeon_winsys
*radeon_ws
= (struct radeon_winsys
*)ws
;
81 struct radeon_pipe_buffer
*radeon_buffer
;
85 radeon_buffer
= CALLOC_STRUCT(radeon_pipe_buffer
);
86 if (radeon_buffer
== NULL
) {
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
;
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
;
99 radeon_buffer
->pb
= pb_malloc_buffer_create(size
, &desc
);
100 return &radeon_buffer
->base
;
103 domain
= radeon_domain_from_usage(usage
);
105 radeon_buffer
->bo
= radeon_bo_open(radeon_ws
->priv
->bom
, 0, size
,
106 alignment
, domain
, 0);
107 if (radeon_buffer
->bo
== NULL
) {
111 return &radeon_buffer
->base
;
114 static struct pipe_buffer
*radeon_buffer_user_create(struct pipe_winsys
*ws
,
118 struct radeon_pipe_buffer
*radeon_buffer
;
121 (struct radeon_pipe_buffer
*)radeon_buffer_create(ws
, 0, 0, bytes
);
122 if (radeon_buffer
== NULL
) {
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
;
131 static struct pipe_buffer
*radeon_surface_buffer_create(struct pipe_winsys
*ws
,
134 enum pipe_format format
,
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
;
144 nblocksy
= util_format_get_nblocksy(format
, height
);
145 *stride
= align(util_format_get_stride(format
, width
), alignment
);
146 size
= *stride
* nblocksy
;
148 return radeon_buffer_create(ws
, 64, usage
, size
);
151 static void radeon_buffer_del(struct pipe_buffer
*buffer
)
153 struct radeon_pipe_buffer
*radeon_buffer
=
154 (struct radeon_pipe_buffer
*)buffer
;
156 if (radeon_buffer
->pb
) {
157 pipe_reference_init(&radeon_buffer
->pb
->base
.reference
, 0);
158 pb_destroy(radeon_buffer
->pb
);
161 if (radeon_buffer
->bo
) {
162 radeon_bo_unref(radeon_buffer
->bo
);
168 static void *radeon_buffer_map(struct pipe_winsys
*ws
,
169 struct pipe_buffer
*buffer
,
172 struct radeon_winsys_priv
*priv
= ((struct radeon_winsys
*)ws
)->priv
;
173 struct radeon_pipe_buffer
*radeon_buffer
=
174 (struct radeon_pipe_buffer
*)buffer
;
177 if (radeon_buffer
->pb
) {
178 return pb_map(radeon_buffer
->pb
, flags
);
181 if (flags
& PIPE_BUFFER_USAGE_DONTBLOCK
) {
184 if (radeon_bo_is_busy(radeon_buffer
->bo
, &domain
))
188 if (radeon_bo_is_referenced_by_cs(radeon_buffer
->bo
, priv
->cs
)) {
189 priv
->flush_cb(priv
->flush_data
);
192 if (flags
& PIPE_BUFFER_USAGE_CPU_WRITE
) {
196 if (radeon_bo_map(radeon_buffer
->bo
, write
)) {
200 return radeon_buffer
->bo
->ptr
;
203 static void radeon_buffer_unmap(struct pipe_winsys
*ws
,
204 struct pipe_buffer
*buffer
)
206 struct radeon_pipe_buffer
*radeon_buffer
=
207 (struct radeon_pipe_buffer
*)buffer
;
209 if (radeon_buffer
->pb
) {
210 pb_unmap(radeon_buffer
->pb
);
212 radeon_bo_unmap(radeon_buffer
->bo
);
216 static boolean
radeon_is_buffer_referenced(struct radeon_winsys
*ws
,
217 struct pipe_buffer
*buffer
)
219 struct radeon_pipe_buffer
*radeon_buffer
=
220 (struct radeon_pipe_buffer
*)buffer
;
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
);
228 static void radeon_buffer_set_tiling(struct radeon_winsys
*ws
,
229 struct pipe_buffer
*buffer
,
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
;
240 flags
|= RADEON_BO_FLAGS_MICRO_TILE
;
243 flags
|= RADEON_BO_FLAGS_MACRO_TILE
;
246 radeon_bo_get_tiling(radeon_buffer
->bo
, &old_flags
, &old_pitch
);
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
);
255 radeon_bo_set_tiling(radeon_buffer
->bo
, flags
, pitch
);
259 static void radeon_fence_reference(struct pipe_winsys
*ws
,
260 struct pipe_fence_handle
**ptr
,
261 struct pipe_fence_handle
*pfence
)
265 static int radeon_fence_signalled(struct pipe_winsys
*ws
,
266 struct pipe_fence_handle
*pfence
,
272 static int radeon_fence_finish(struct pipe_winsys
*ws
,
273 struct pipe_fence_handle
*pfence
,
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
,
285 struct radeon_bo_manager
* bom
= radeon_ws
->priv
->bom
;
286 struct radeon_pipe_buffer
* radeon_buffer
;
287 struct radeon_bo
* bo
= NULL
;
289 bo
= radeon_bo_open(bom
, whandle
->handle
, 0, 0, 0, 0);
294 radeon_buffer
= CALLOC_STRUCT(radeon_pipe_buffer
);
295 if (radeon_buffer
== NULL
) {
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
;
305 *stride
= whandle
->stride
;
307 return &radeon_buffer
->base
;
310 static boolean
radeon_buffer_get_handle(struct radeon_winsys
*radeon_ws
,
311 struct pipe_buffer
*buffer
,
313 struct winsys_handle
*whandle
)
316 struct drm_gem_flink flink
;
317 struct radeon_pipe_buffer
* radeon_buffer
;
319 radeon_buffer
= (struct radeon_pipe_buffer
*)buffer
;
322 if (whandle
->type
== DRM_API_HANDLE_TYPE_SHARED
) {
323 if (!radeon_buffer
->flinked
) {
324 fd
= radeon_ws
->priv
->fd
;
326 flink
.handle
= radeon_buffer
->bo
->handle
;
328 retval
= ioctl(fd
, DRM_IOCTL_GEM_FLINK
, &flink
);
330 debug_printf("radeon: DRM_IOCTL_GEM_FLINK failed, error %d\n",
335 radeon_buffer
->flink
= flink
.name
;
336 radeon_buffer
->flinked
= TRUE
;
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
;
343 whandle
->stride
= stride
;
348 struct radeon_winsys
* radeon_pipe_winsys(int fd
)
350 struct radeon_winsys
* radeon_ws
;
352 radeon_ws
= CALLOC_STRUCT(radeon_winsys
);
353 if (radeon_ws
== NULL
) {
357 radeon_ws
->priv
= CALLOC_STRUCT(radeon_winsys_priv
);
358 if (radeon_ws
->priv
== NULL
) {
363 radeon_ws
->priv
->fd
= fd
;
364 radeon_ws
->priv
->bom
= radeon_bo_manager_gem_ctor(fd
);
366 radeon_ws
->base
.flush_frontbuffer
= NULL
; /* overriden by co-state tracker */
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
;
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
;
379 radeon_ws
->base
.get_name
= radeon_get_name
;
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
;
385 radeon_ws
->is_buffer_referenced
= radeon_is_buffer_referenced
;