r600g: add support for kernel bo
[mesa.git] / src / gallium / winsys / r600 / drm / radeon_bo_pb.c
1 #include "radeon_priv.h"
2
3 #include "util/u_inlines.h"
4 #include "util/u_memory.h"
5 #include "util/u_double_list.h"
6 #include "pipebuffer/pb_buffer.h"
7 #include "pipebuffer/pb_bufmgr.h"
8
9 struct radeon_bo_pb {
10 struct pb_buffer b;
11 struct radeon_bo *bo;
12
13 struct radeon_bo_pbmgr *mgr;
14 struct list_head maplist;
15 };
16
17 extern const struct pb_vtbl radeon_bo_pb_vtbl;
18
19 static INLINE struct radeon_bo_pb *radeon_bo_pb(struct pb_buffer *buf)
20 {
21 assert(buf);
22 assert(buf->vtbl == &radeon_bo_pb_vtbl);
23 return (struct radeon_bo_pb *)buf;
24 }
25
26 struct radeon_bo_pbmgr {
27 struct pb_manager b;
28 struct radeon *radeon;
29 struct list_head buffer_map_list;
30 };
31
32 static INLINE struct radeon_bo_pbmgr *radeon_bo_pbmgr(struct pb_manager *mgr)
33 {
34 assert(mgr);
35 return (struct radeon_bo_pbmgr *)mgr;
36 }
37
38 static void radeon_bo_pb_destroy(struct pb_buffer *_buf)
39 {
40 struct radeon_bo_pb *buf = radeon_bo_pb(_buf);
41
42 if (buf->bo->data != NULL) {
43 LIST_DEL(&buf->maplist);
44 radeon_bo_unmap(buf->mgr->radeon, buf->bo);
45 }
46 radeon_bo_reference(buf->mgr->radeon, &buf->bo, NULL);
47 FREE(buf);
48 }
49
50 static void *
51 radeon_bo_pb_map_internal(struct pb_buffer *_buf,
52 unsigned flags, void *ctx)
53 {
54 struct radeon_bo_pb *buf = radeon_bo_pb(_buf);
55
56 if (flags & PB_USAGE_DONTBLOCK) {
57 if (p_atomic_read(&buf->bo->reference.count) > 1)
58 return NULL;
59 }
60 if (buf->bo->data != NULL)
61 return buf->bo->data;
62
63 if (flags & PB_USAGE_DONTBLOCK) {
64 uint32_t domain;
65 if (radeon_bo_busy(buf->mgr->radeon, buf->bo, &domain))
66 return NULL;
67 }
68
69 if (p_atomic_read(&buf->bo->reference.count) > 1 && ctx) {
70 r600_flush_ctx(ctx);
71 }
72 if (radeon_bo_map(buf->mgr->radeon, buf->bo)) {
73 return NULL;
74 }
75 LIST_ADDTAIL(&buf->maplist, &buf->mgr->buffer_map_list);
76 return buf->bo->data;
77 }
78
79 static void radeon_bo_pb_unmap_internal(struct pb_buffer *_buf)
80 {
81 (void)_buf;
82 }
83
84 static void
85 radeon_bo_pb_get_base_buffer(struct pb_buffer *buf,
86 struct pb_buffer **base_buf,
87 unsigned *offset)
88 {
89 *base_buf = buf;
90 *offset = 0;
91 }
92
93 static enum pipe_error
94 radeon_bo_pb_validate(struct pb_buffer *_buf,
95 struct pb_validate *vl,
96 unsigned flags)
97 {
98 /* Always pinned */
99 return PIPE_OK;
100 }
101
102 static void
103 radeon_bo_pb_fence(struct pb_buffer *buf,
104 struct pipe_fence_handle *fence)
105 {
106 }
107
108 const struct pb_vtbl radeon_bo_pb_vtbl = {
109 radeon_bo_pb_destroy,
110 radeon_bo_pb_map_internal,
111 radeon_bo_pb_unmap_internal,
112 radeon_bo_pb_validate,
113 radeon_bo_pb_fence,
114 radeon_bo_pb_get_base_buffer,
115 };
116
117 struct pb_buffer *
118 radeon_bo_pb_create_buffer_from_handle(struct pb_manager *_mgr,
119 uint32_t handle)
120 {
121 struct radeon_bo_pbmgr *mgr = radeon_bo_pbmgr(_mgr);
122 struct radeon *radeon = mgr->radeon;
123 struct radeon_bo_pb *bo;
124 struct radeon_bo *hw_bo;
125
126 hw_bo = radeon_bo(radeon, handle, 0, 0, NULL);
127 if (hw_bo == NULL)
128 return NULL;
129
130 bo = CALLOC_STRUCT(radeon_bo_pb);
131 if (!bo) {
132 radeon_bo_reference(radeon, &hw_bo, NULL);
133 return NULL;
134 }
135
136 LIST_INITHEAD(&bo->maplist);
137 pipe_reference_init(&bo->b.base.reference, 1);
138 bo->b.base.alignment = 0;
139 bo->b.base.usage = PB_USAGE_GPU_WRITE | PB_USAGE_GPU_READ;
140 bo->b.base.size = hw_bo->size;
141 bo->b.vtbl = &radeon_bo_pb_vtbl;
142 bo->mgr = mgr;
143
144 bo->bo = hw_bo;
145
146 return &bo->b;
147 }
148
149 static struct pb_buffer *
150 radeon_bo_pb_create_buffer(struct pb_manager *_mgr,
151 pb_size size,
152 const struct pb_desc *desc)
153 {
154 struct radeon_bo_pbmgr *mgr = radeon_bo_pbmgr(_mgr);
155 struct radeon *radeon = mgr->radeon;
156 struct radeon_bo_pb *bo;
157 uint32_t domain;
158
159 bo = CALLOC_STRUCT(radeon_bo_pb);
160 if (!bo)
161 goto error1;
162
163 pipe_reference_init(&bo->b.base.reference, 1);
164 bo->b.base.alignment = desc->alignment;
165 bo->b.base.usage = desc->usage;
166 bo->b.base.size = size;
167 bo->b.vtbl = &radeon_bo_pb_vtbl;
168 bo->mgr = mgr;
169
170 LIST_INITHEAD(&bo->maplist);
171
172 bo->bo = radeon_bo(radeon, 0, size,
173 desc->alignment, NULL);
174 if (bo->bo == NULL)
175 goto error2;
176 return &bo->b;
177
178 error2:
179 FREE(bo);
180 error1:
181 return NULL;
182 }
183
184 static void
185 radeon_bo_pbmgr_flush(struct pb_manager *mgr)
186 {
187 /* NOP */
188 }
189
190 static void
191 radeon_bo_pbmgr_destroy(struct pb_manager *_mgr)
192 {
193 struct radeon_bo_pbmgr *mgr = radeon_bo_pbmgr(_mgr);
194 FREE(mgr);
195 }
196
197 struct pb_manager *radeon_bo_pbmgr_create(struct radeon *radeon)
198 {
199 struct radeon_bo_pbmgr *mgr;
200
201 mgr = CALLOC_STRUCT(radeon_bo_pbmgr);
202 if (!mgr)
203 return NULL;
204
205 mgr->b.destroy = radeon_bo_pbmgr_destroy;
206 mgr->b.create_buffer = radeon_bo_pb_create_buffer;
207 mgr->b.flush = radeon_bo_pbmgr_flush;
208
209 mgr->radeon = radeon;
210 LIST_INITHEAD(&mgr->buffer_map_list);
211 return &mgr->b;
212 }
213
214 void radeon_bo_pbmgr_flush_maps(struct pb_manager *_mgr)
215 {
216 struct radeon_bo_pbmgr *mgr = radeon_bo_pbmgr(_mgr);
217 struct radeon_bo_pb *rpb, *t_rpb;
218
219 LIST_FOR_EACH_ENTRY_SAFE(rpb, t_rpb, &mgr->buffer_map_list, maplist) {
220 radeon_bo_unmap(mgr->radeon, rpb->bo);
221 LIST_DEL(&rpb->maplist);
222 }
223
224 LIST_INITHEAD(&mgr->buffer_map_list);
225 }
226
227 struct radeon_bo *radeon_bo_pb_get_bo(struct pb_buffer *_buf)
228 {
229 struct radeon_bo_pb *buf;
230 if (_buf->vtbl == &radeon_bo_pb_vtbl) {
231 buf = radeon_bo_pb(_buf);
232 return buf->bo;
233 } else {
234 struct pb_buffer *base_buf;
235 pb_size offset;
236 pb_get_base_buffer(_buf, &base_buf, &offset);
237 if (base_buf->vtbl == &radeon_bo_pb_vtbl) {
238 buf = radeon_bo_pb(base_buf);
239 return buf->bo;
240 }
241 }
242 return NULL;
243 }