1 /**************************************************************************
3 * Copyright 2009, VMware, Inc.
5 * Copyright 2010 George Sapountzis <gsapountzis@gmail.com>
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sub license, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
23 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
24 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 **************************************************************************/
37 #include <sys/types.h>
44 #include "pipe/p_compiler.h"
45 #include "pipe/p_format.h"
46 #include "pipe/p_state.h"
47 #include "util/u_inlines.h"
48 #include "util/format/u_format.h"
49 #include "util/u_math.h"
50 #include "util/u_memory.h"
51 #include "util/list.h"
53 #include "state_tracker/sw_winsys.h"
54 #include "state_tracker/drm_driver.h"
55 #include "kms_dri_sw_winsys.h"
58 #define DEBUG_PRINT(msg, ...) fprintf(stderr, msg, __VA_ARGS__)
60 #define DEBUG_PRINT(msg, ...)
63 struct kms_sw_displaytarget
;
71 struct kms_sw_displaytarget
*dt
;
72 struct list_head link
;
75 struct kms_sw_displaytarget
77 enum pipe_format format
;
86 struct list_head link
;
87 struct list_head planes
;
92 struct sw_winsys base
;
95 struct list_head bo_list
;
98 static inline struct kms_sw_plane
*
99 kms_sw_plane( struct sw_displaytarget
*dt
)
101 return (struct kms_sw_plane
*)dt
;
104 static inline struct sw_displaytarget
*
105 sw_displaytarget( struct kms_sw_plane
*pl
)
107 return (struct sw_displaytarget
*)pl
;
110 static inline struct kms_sw_winsys
*
111 kms_sw_winsys( struct sw_winsys
*ws
)
113 return (struct kms_sw_winsys
*)ws
;
118 kms_sw_is_displaytarget_format_supported( struct sw_winsys
*ws
,
120 enum pipe_format format
)
122 /* TODO: check visuals or other sensible thing here */
126 static struct kms_sw_plane
*get_plane(struct kms_sw_displaytarget
*kms_sw_dt
,
127 enum pipe_format format
,
128 unsigned width
, unsigned height
,
129 unsigned stride
, unsigned offset
)
131 struct kms_sw_plane
*plane
= NULL
;
133 if (offset
+ util_format_get_2d_size(format
, stride
, height
) >
135 DEBUG_PRINT("KMS-DEBUG: plane too big. format: %d stride: %d height: %d "
136 "offset: %d size:%d\n", format
, stride
, height
, offset
,
141 LIST_FOR_EACH_ENTRY(plane
, &kms_sw_dt
->planes
, link
) {
142 if (plane
->offset
== offset
)
146 plane
= CALLOC_STRUCT(kms_sw_plane
);
150 plane
->width
= width
;
151 plane
->height
= height
;
152 plane
->stride
= stride
;
153 plane
->offset
= offset
;
154 plane
->dt
= kms_sw_dt
;
155 list_add(&plane
->link
, &kms_sw_dt
->planes
);
159 static struct sw_displaytarget
*
160 kms_sw_displaytarget_create(struct sw_winsys
*ws
,
162 enum pipe_format format
,
163 unsigned width
, unsigned height
,
165 const void *front_private
,
168 struct kms_sw_winsys
*kms_sw
= kms_sw_winsys(ws
);
169 struct kms_sw_displaytarget
*kms_sw_dt
;
170 struct drm_mode_create_dumb create_req
;
171 struct drm_mode_destroy_dumb destroy_req
;
174 kms_sw_dt
= CALLOC_STRUCT(kms_sw_displaytarget
);
178 list_inithead(&kms_sw_dt
->planes
);
179 kms_sw_dt
->ref_count
= 1;
180 kms_sw_dt
->mapped
= MAP_FAILED
;
181 kms_sw_dt
->ro_mapped
= MAP_FAILED
;
183 kms_sw_dt
->format
= format
;
185 memset(&create_req
, 0, sizeof(create_req
));
186 create_req
.bpp
= util_format_get_blocksizebits(format
);
187 create_req
.width
= width
;
188 create_req
.height
= height
;
189 ret
= drmIoctl(kms_sw
->fd
, DRM_IOCTL_MODE_CREATE_DUMB
, &create_req
);
193 kms_sw_dt
->size
= create_req
.size
;
194 kms_sw_dt
->handle
= create_req
.handle
;
195 struct kms_sw_plane
*plane
= get_plane(kms_sw_dt
, format
, width
, height
,
196 create_req
.pitch
, 0);
200 list_add(&kms_sw_dt
->link
, &kms_sw
->bo_list
);
202 DEBUG_PRINT("KMS-DEBUG: created buffer %u (size %u)\n", kms_sw_dt
->handle
, kms_sw_dt
->size
);
204 *stride
= create_req
.pitch
;
205 return sw_displaytarget(plane
);
208 memset(&destroy_req
, 0, sizeof destroy_req
);
209 destroy_req
.handle
= create_req
.handle
;
210 drmIoctl(kms_sw
->fd
, DRM_IOCTL_MODE_DESTROY_DUMB
, &destroy_req
);
217 kms_sw_displaytarget_destroy(struct sw_winsys
*ws
,
218 struct sw_displaytarget
*dt
)
220 struct kms_sw_winsys
*kms_sw
= kms_sw_winsys(ws
);
221 struct kms_sw_plane
*plane
= kms_sw_plane(dt
);
222 struct kms_sw_displaytarget
*kms_sw_dt
= plane
->dt
;
223 struct drm_mode_destroy_dumb destroy_req
;
225 kms_sw_dt
->ref_count
--;
226 if (kms_sw_dt
->ref_count
> 0)
229 if (kms_sw_dt
->map_count
> 0) {
230 DEBUG_PRINT("KMS-DEBUG: leaked map buffer %u\n", kms_sw_dt
->handle
);
233 memset(&destroy_req
, 0, sizeof destroy_req
);
234 destroy_req
.handle
= kms_sw_dt
->handle
;
235 drmIoctl(kms_sw
->fd
, DRM_IOCTL_MODE_DESTROY_DUMB
, &destroy_req
);
237 list_del(&kms_sw_dt
->link
);
239 DEBUG_PRINT("KMS-DEBUG: destroyed buffer %u\n", kms_sw_dt
->handle
);
241 struct kms_sw_plane
*tmp
;
242 LIST_FOR_EACH_ENTRY_SAFE(plane
, tmp
, &kms_sw_dt
->planes
, link
) {
250 kms_sw_displaytarget_map(struct sw_winsys
*ws
,
251 struct sw_displaytarget
*dt
,
254 struct kms_sw_winsys
*kms_sw
= kms_sw_winsys(ws
);
255 struct kms_sw_plane
*plane
= kms_sw_plane(dt
);
256 struct kms_sw_displaytarget
*kms_sw_dt
= plane
->dt
;
257 struct drm_mode_map_dumb map_req
;
260 memset(&map_req
, 0, sizeof map_req
);
261 map_req
.handle
= kms_sw_dt
->handle
;
262 ret
= drmIoctl(kms_sw
->fd
, DRM_IOCTL_MODE_MAP_DUMB
, &map_req
);
266 prot
= (flags
== PIPE_TRANSFER_READ
) ? PROT_READ
: (PROT_READ
| PROT_WRITE
);
267 void **ptr
= (flags
== PIPE_TRANSFER_READ
) ? &kms_sw_dt
->ro_mapped
: &kms_sw_dt
->mapped
;
268 if (*ptr
== MAP_FAILED
) {
269 void *tmp
= mmap(0, kms_sw_dt
->size
, prot
, MAP_SHARED
,
270 kms_sw
->fd
, map_req
.offset
);
271 if (tmp
== MAP_FAILED
)
276 DEBUG_PRINT("KMS-DEBUG: mapped buffer %u (size %u) at %p\n",
277 kms_sw_dt
->handle
, kms_sw_dt
->size
, *ptr
);
279 kms_sw_dt
->map_count
++;
281 return *ptr
+ plane
->offset
;
284 static struct kms_sw_displaytarget
*
285 kms_sw_displaytarget_find_and_ref(struct kms_sw_winsys
*kms_sw
,
286 unsigned int kms_handle
)
288 struct kms_sw_displaytarget
*kms_sw_dt
;
290 LIST_FOR_EACH_ENTRY(kms_sw_dt
, &kms_sw
->bo_list
, link
) {
291 if (kms_sw_dt
->handle
== kms_handle
) {
292 kms_sw_dt
->ref_count
++;
294 DEBUG_PRINT("KMS-DEBUG: imported buffer %u (size %u)\n",
295 kms_sw_dt
->handle
, kms_sw_dt
->size
);
304 static struct kms_sw_plane
*
305 kms_sw_displaytarget_add_from_prime(struct kms_sw_winsys
*kms_sw
, int fd
,
306 enum pipe_format format
,
307 unsigned width
, unsigned height
,
308 unsigned stride
, unsigned offset
)
310 uint32_t handle
= -1;
311 struct kms_sw_displaytarget
* kms_sw_dt
;
314 ret
= drmPrimeFDToHandle(kms_sw
->fd
, fd
, &handle
);
319 kms_sw_dt
= kms_sw_displaytarget_find_and_ref(kms_sw
, handle
);
320 struct kms_sw_plane
*plane
= NULL
;
322 plane
= get_plane(kms_sw_dt
, format
, width
, height
, stride
, offset
);
324 kms_sw_dt
->ref_count
--;
328 kms_sw_dt
= CALLOC_STRUCT(kms_sw_displaytarget
);
332 list_inithead(&kms_sw_dt
->planes
);
333 off_t lseek_ret
= lseek(fd
, 0, SEEK_END
);
334 if (lseek_ret
== -1) {
338 kms_sw_dt
->mapped
= MAP_FAILED
;
339 kms_sw_dt
->ro_mapped
= MAP_FAILED
;
340 kms_sw_dt
->size
= lseek_ret
;
341 kms_sw_dt
->ref_count
= 1;
342 kms_sw_dt
->handle
= handle
;
344 lseek(fd
, 0, SEEK_SET
);
345 plane
= get_plane(kms_sw_dt
, format
, width
, height
, stride
, offset
);
351 list_add(&kms_sw_dt
->link
, &kms_sw
->bo_list
);
357 kms_sw_displaytarget_unmap(struct sw_winsys
*ws
,
358 struct sw_displaytarget
*dt
)
360 struct kms_sw_plane
*plane
= kms_sw_plane(dt
);
361 struct kms_sw_displaytarget
*kms_sw_dt
= plane
->dt
;
363 if (!kms_sw_dt
->map_count
) {
364 DEBUG_PRINT("KMS-DEBUG: ignore duplicated unmap %u", kms_sw_dt
->handle
);
367 kms_sw_dt
->map_count
--;
368 if (kms_sw_dt
->map_count
) {
369 DEBUG_PRINT("KMS-DEBUG: ignore unmap for busy buffer %u", kms_sw_dt
->handle
);
373 DEBUG_PRINT("KMS-DEBUG: unmapped buffer %u (was %p)\n", kms_sw_dt
->handle
, kms_sw_dt
->mapped
);
374 DEBUG_PRINT("KMS-DEBUG: unmapped buffer %u (was %p)\n", kms_sw_dt
->handle
, kms_sw_dt
->ro_mapped
);
376 if (kms_sw_dt
->mapped
!= MAP_FAILED
) {
377 munmap(kms_sw_dt
->mapped
, kms_sw_dt
->size
);
378 kms_sw_dt
->mapped
= MAP_FAILED
;
380 if (kms_sw_dt
->ro_mapped
!= MAP_FAILED
) {
381 munmap(kms_sw_dt
->ro_mapped
, kms_sw_dt
->size
);
382 kms_sw_dt
->ro_mapped
= MAP_FAILED
;
386 static struct sw_displaytarget
*
387 kms_sw_displaytarget_from_handle(struct sw_winsys
*ws
,
388 const struct pipe_resource
*templ
,
389 struct winsys_handle
*whandle
,
392 struct kms_sw_winsys
*kms_sw
= kms_sw_winsys(ws
);
393 struct kms_sw_displaytarget
*kms_sw_dt
;
394 struct kms_sw_plane
*kms_sw_pl
;
397 assert(whandle
->type
== WINSYS_HANDLE_TYPE_KMS
||
398 whandle
->type
== WINSYS_HANDLE_TYPE_FD
);
400 switch(whandle
->type
) {
401 case WINSYS_HANDLE_TYPE_FD
:
402 kms_sw_pl
= kms_sw_displaytarget_add_from_prime(kms_sw
, whandle
->handle
,
409 *stride
= kms_sw_pl
->stride
;
410 return sw_displaytarget(kms_sw_pl
);
411 case WINSYS_HANDLE_TYPE_KMS
:
412 kms_sw_dt
= kms_sw_displaytarget_find_and_ref(kms_sw
, whandle
->handle
);
414 struct kms_sw_plane
*plane
;
415 LIST_FOR_EACH_ENTRY(plane
, &kms_sw_dt
->planes
, link
) {
416 if (whandle
->offset
== plane
->offset
) {
417 *stride
= plane
->stride
;
418 return sw_displaytarget(plane
);
421 kms_sw_dt
->ref_count
--;
433 kms_sw_displaytarget_get_handle(struct sw_winsys
*winsys
,
434 struct sw_displaytarget
*dt
,
435 struct winsys_handle
*whandle
)
437 struct kms_sw_winsys
*kms_sw
= kms_sw_winsys(winsys
);
438 struct kms_sw_plane
*plane
= kms_sw_plane(dt
);
439 struct kms_sw_displaytarget
*kms_sw_dt
= plane
->dt
;
441 switch(whandle
->type
) {
442 case WINSYS_HANDLE_TYPE_KMS
:
443 whandle
->handle
= kms_sw_dt
->handle
;
444 whandle
->stride
= plane
->stride
;
445 whandle
->offset
= plane
->offset
;
447 case WINSYS_HANDLE_TYPE_FD
:
448 if (!drmPrimeHandleToFD(kms_sw
->fd
, kms_sw_dt
->handle
,
449 DRM_CLOEXEC
, (int*)&whandle
->handle
)) {
450 whandle
->stride
= plane
->stride
;
451 whandle
->offset
= plane
->offset
;
464 kms_sw_displaytarget_display(struct sw_winsys
*ws
,
465 struct sw_displaytarget
*dt
,
466 void *context_private
,
467 struct pipe_box
*box
)
469 /* This function should not be called, instead the dri2 loader should
470 handle swap buffers internally.
477 kms_destroy_sw_winsys(struct sw_winsys
*winsys
)
483 kms_dri_create_winsys(int fd
)
485 struct kms_sw_winsys
*ws
;
487 ws
= CALLOC_STRUCT(kms_sw_winsys
);
492 list_inithead(&ws
->bo_list
);
494 ws
->base
.destroy
= kms_destroy_sw_winsys
;
496 ws
->base
.is_displaytarget_format_supported
= kms_sw_is_displaytarget_format_supported
;
498 /* screen texture functions */
499 ws
->base
.displaytarget_create
= kms_sw_displaytarget_create
;
500 ws
->base
.displaytarget_destroy
= kms_sw_displaytarget_destroy
;
501 ws
->base
.displaytarget_from_handle
= kms_sw_displaytarget_from_handle
;
502 ws
->base
.displaytarget_get_handle
= kms_sw_displaytarget_get_handle
;
504 /* texture functions */
505 ws
->base
.displaytarget_map
= kms_sw_displaytarget_map
;
506 ws
->base
.displaytarget_unmap
= kms_sw_displaytarget_unmap
;
508 ws
->base
.displaytarget_display
= kms_sw_displaytarget_display
;
513 /* vim: set sw=3 ts=8 sts=3 expandtab: */