1 #include "pipe/p_defines.h"
2 #include "pipe/p_screen.h"
3 #include "pipe/p_state.h"
5 #include "util/u_memory.h"
6 #include "util/u_inlines.h"
7 #include "util/u_format.h"
12 #include "nouveau/nouveau_bo.h"
13 #include "nouveau_winsys.h"
14 #include "nouveau_screen.h"
16 /* XXX this should go away */
17 #include "state_tracker/drm_api.h"
20 nouveau_screen_get_name(struct pipe_screen
*pscreen
)
22 struct nouveau_device
*dev
= nouveau_screen(pscreen
)->device
;
23 static char buffer
[128];
25 snprintf(buffer
, sizeof(buffer
), "NV%02X", dev
->chipset
);
30 nouveau_screen_get_vendor(struct pipe_screen
*pscreen
)
35 static struct pipe_buffer
*
36 nouveau_screen_bo_skel(struct pipe_screen
*pscreen
, struct nouveau_bo
*bo
,
37 unsigned alignment
, unsigned usage
, unsigned size
)
39 struct pipe_buffer
*pb
;
41 pb
= CALLOC(1, sizeof(struct pipe_buffer
)+sizeof(struct nouveau_bo
*));
43 nouveau_bo_ref(NULL
, &bo
);
47 pipe_reference_init(&pb
->reference
, 1);
49 pb
->alignment
= alignment
;
52 *(struct nouveau_bo
**)(pb
+ 1) = bo
;
56 static struct pipe_buffer
*
57 nouveau_screen_bo_new(struct pipe_screen
*pscreen
, unsigned alignment
,
58 unsigned usage
, unsigned size
)
60 struct nouveau_device
*dev
= nouveau_screen(pscreen
)->device
;
61 struct nouveau_bo
*bo
= NULL
;
62 uint32_t flags
= NOUVEAU_BO_MAP
, tile_mode
= 0, tile_flags
= 0;
65 if (usage
& NOUVEAU_BUFFER_USAGE_TRANSFER
)
66 flags
|= NOUVEAU_BO_GART
;
68 if (usage
& PIPE_BUFFER_USAGE_VERTEX
) {
69 if (pscreen
->get_param(pscreen
, NOUVEAU_CAP_HW_VTXBUF
))
70 flags
|= NOUVEAU_BO_GART
;
72 if (usage
& PIPE_BUFFER_USAGE_INDEX
) {
73 if (pscreen
->get_param(pscreen
, NOUVEAU_CAP_HW_IDXBUF
))
74 flags
|= NOUVEAU_BO_GART
;
77 if (usage
& PIPE_BUFFER_USAGE_PIXEL
) {
78 if (usage
& NOUVEAU_BUFFER_USAGE_TEXTURE
)
79 flags
|= NOUVEAU_BO_GART
;
80 if (!(usage
& PIPE_BUFFER_USAGE_CPU_READ_WRITE
))
81 flags
|= NOUVEAU_BO_VRAM
;
83 if (dev
->chipset
== 0x50 || dev
->chipset
>= 0x80) {
84 if (usage
& NOUVEAU_BUFFER_USAGE_ZETA
)
91 ret
= nouveau_bo_new_tile(dev
, flags
, alignment
, size
,
92 tile_mode
, tile_flags
, &bo
);
96 return nouveau_screen_bo_skel(pscreen
, bo
, alignment
, usage
, size
);
99 static struct pipe_buffer
*
100 nouveau_screen_bo_user(struct pipe_screen
*pscreen
, void *ptr
, unsigned bytes
)
102 struct nouveau_device
*dev
= nouveau_screen(pscreen
)->device
;
103 struct nouveau_bo
*bo
= NULL
;
106 ret
= nouveau_bo_user(dev
, ptr
, bytes
, &bo
);
110 return nouveau_screen_bo_skel(pscreen
, bo
, 0, 0, bytes
);
113 static inline uint32_t
114 nouveau_screen_map_flags(unsigned pipe
)
118 if (pipe
& PIPE_BUFFER_USAGE_CPU_READ
)
119 flags
|= NOUVEAU_BO_RD
;
120 if (pipe
& PIPE_BUFFER_USAGE_CPU_WRITE
)
121 flags
|= NOUVEAU_BO_WR
;
122 if (pipe
& PIPE_BUFFER_USAGE_DISCARD
)
123 flags
|= NOUVEAU_BO_INVAL
;
124 if (pipe
& PIPE_BUFFER_USAGE_DONTBLOCK
)
125 flags
|= NOUVEAU_BO_NOWAIT
;
127 if (pipe
& PIPE_BUFFER_USAGE_UNSYNCHRONIZED
)
128 flags
|= NOUVEAU_BO_NOSYNC
;
134 nouveau_screen_bo_map(struct pipe_screen
*pscreen
, struct pipe_buffer
*pb
,
137 struct nouveau_bo
*bo
= nouveau_bo(pb
);
138 struct nouveau_screen
*nscreen
= nouveau_screen(pscreen
);
141 if (nscreen
->pre_pipebuffer_map_callback
) {
142 ret
= nscreen
->pre_pipebuffer_map_callback(pscreen
, pb
, usage
);
144 debug_printf("pre_pipebuffer_map_callback failed %d\n",
150 ret
= nouveau_bo_map(bo
, nouveau_screen_map_flags(usage
));
152 debug_printf("map failed: %d\n", ret
);
160 nouveau_screen_bo_map_range(struct pipe_screen
*pscreen
, struct pipe_buffer
*pb
,
161 unsigned offset
, unsigned length
, unsigned usage
)
163 struct nouveau_bo
*bo
= nouveau_bo(pb
);
164 struct nouveau_screen
*nscreen
= nouveau_screen(pscreen
);
165 uint32_t flags
= nouveau_screen_map_flags(usage
);
168 if (nscreen
->pre_pipebuffer_map_callback
) {
169 ret
= nscreen
->pre_pipebuffer_map_callback(pscreen
, pb
, usage
);
171 debug_printf("pre_pipebuffer_map_callback failed %d\n",
177 ret
= nouveau_bo_map_range(bo
, offset
, length
, flags
);
179 nouveau_bo_unmap(bo
);
180 if (!(flags
& NOUVEAU_BO_NOWAIT
) || ret
!= -EBUSY
)
181 debug_printf("map_range failed: %d\n", ret
);
185 return (char *)bo
->map
- offset
; /* why gallium? why? */
189 nouveau_screen_bo_map_flush(struct pipe_screen
*pscreen
, struct pipe_buffer
*pb
,
190 unsigned offset
, unsigned length
)
192 struct nouveau_bo
*bo
= nouveau_bo(pb
);
194 nouveau_bo_map_flush(bo
, offset
, length
);
198 nouveau_screen_bo_unmap(struct pipe_screen
*pscreen
, struct pipe_buffer
*pb
)
200 struct nouveau_bo
*bo
= nouveau_bo(pb
);
202 nouveau_bo_unmap(bo
);
206 nouveau_screen_bo_del(struct pipe_buffer
*pb
)
208 struct nouveau_bo
*bo
= nouveau_bo(pb
);
210 nouveau_bo_ref(NULL
, &bo
);
215 nouveau_screen_fence_ref(struct pipe_screen
*pscreen
,
216 struct pipe_fence_handle
**ptr
,
217 struct pipe_fence_handle
*pfence
)
223 nouveau_screen_fence_signalled(struct pipe_screen
*screen
,
224 struct pipe_fence_handle
*pfence
,
231 nouveau_screen_fence_finish(struct pipe_screen
*screen
,
232 struct pipe_fence_handle
*pfence
,
240 * Both texture_{from|get}_handle use drm api defines directly which they
241 * shouldn't do. The problem is that from|get are pipe functions and as
242 * such they should be defined in the pipe level. If nouveau had a propper
243 * winsys interface we would have added from|get to that interface using
244 * the winsys_handle struct as done with other drivers. However this code
245 * calls directly into the libdrm_nouveau.so functions (nouveau_bo_*). So
246 * we need to translate the handle into something they understand.
248 static struct pipe_texture
*
249 nouveau_screen_texture_from_handle(struct pipe_screen
*pscreen
,
250 const struct pipe_texture
*templ
,
251 struct winsys_handle
*whandle
)
253 struct nouveau_device
*dev
= nouveau_screen(pscreen
)->device
;
254 struct pipe_texture
*pt
;
255 struct pipe_buffer
*pb
;
258 pb
= CALLOC(1, sizeof(struct pipe_buffer
) + sizeof(struct nouveau_bo
*));
262 ret
= nouveau_bo_handle_ref(dev
, whandle
->handle
, (struct nouveau_bo
**)(pb
+1));
264 debug_printf("%s: ref name 0x%08x failed with %d\n",
265 __func__
, whandle
->handle
, ret
);
270 pipe_reference_init(&pb
->reference
, 1);
271 pb
->screen
= pscreen
;
273 pb
->usage
= PIPE_BUFFER_USAGE_GPU_READ_WRITE
|
274 PIPE_BUFFER_USAGE_CPU_READ_WRITE
;
275 pb
->size
= nouveau_bo(pb
)->size
;
276 pt
= nouveau_screen(pscreen
)->texture_blanket(pscreen
, templ
,
277 &whandle
->stride
, pb
);
278 pipe_buffer_reference(&pb
, NULL
);
283 nouveau_screen_texture_get_handle(struct pipe_screen
*pscreen
,
284 struct pipe_texture
*pt
,
285 struct winsys_handle
*whandle
)
287 struct nouveau_miptree
*mt
= nouveau_miptree(pt
);
292 whandle
->stride
= util_format_get_stride(mt
->base
.format
, mt
->base
.width0
);
294 if (whandle
->type
== DRM_API_HANDLE_TYPE_SHARED
) {
295 return nouveau_bo_handle_get(mt
->bo
, &whandle
->handle
) == 0;
296 } else if (whandle
->type
== DRM_API_HANDLE_TYPE_KMS
) {
297 whandle
->handle
= mt
->bo
->handle
;
305 nouveau_screen_init(struct nouveau_screen
*screen
, struct nouveau_device
*dev
)
307 struct pipe_screen
*pscreen
= &screen
->base
;
310 ret
= nouveau_channel_alloc(dev
, 0xbeef0201, 0xbeef0202,
314 screen
->device
= dev
;
316 pscreen
->get_name
= nouveau_screen_get_name
;
317 pscreen
->get_vendor
= nouveau_screen_get_vendor
;
319 pscreen
->buffer_create
= nouveau_screen_bo_new
;
320 pscreen
->user_buffer_create
= nouveau_screen_bo_user
;
321 pscreen
->buffer_map
= nouveau_screen_bo_map
;
322 pscreen
->buffer_map_range
= nouveau_screen_bo_map_range
;
323 pscreen
->buffer_flush_mapped_range
= nouveau_screen_bo_map_flush
;
324 pscreen
->buffer_unmap
= nouveau_screen_bo_unmap
;
325 pscreen
->buffer_destroy
= nouveau_screen_bo_del
;
327 pscreen
->fence_reference
= nouveau_screen_fence_ref
;
328 pscreen
->fence_signalled
= nouveau_screen_fence_signalled
;
329 pscreen
->fence_finish
= nouveau_screen_fence_finish
;
331 pscreen
->texture_from_handle
= nouveau_screen_texture_from_handle
;
332 pscreen
->texture_get_handle
= nouveau_screen_texture_get_handle
;
338 nouveau_screen_fini(struct nouveau_screen
*screen
)
340 struct pipe_winsys
*ws
= screen
->base
.winsys
;
341 nouveau_channel_free(&screen
->channel
);