r600g: Buffer object maps imply a wait.
[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 LIST_DEL(&buf->maplist);
43
44 if (buf->bo->data != NULL) {
45 radeon_bo_unmap(buf->mgr->radeon, buf->bo);
46 }
47 radeon_bo_reference(buf->mgr->radeon, &buf->bo, NULL);
48 FREE(buf);
49 }
50
51 static void *
52 radeon_bo_pb_map_internal(struct pb_buffer *_buf,
53 unsigned flags, void *ctx)
54 {
55 struct radeon_bo_pb *buf = radeon_bo_pb(_buf);
56
57 if (p_atomic_read(&buf->bo->reference.count) > 1) {
58 if (flags & PB_USAGE_DONTBLOCK) {
59 return NULL;
60 }
61 if (ctx) {
62 r600_flush_ctx(ctx);
63 }
64 }
65
66 if (flags & PB_USAGE_DONTBLOCK) {
67 uint32_t domain;
68 if (radeon_bo_busy(buf->mgr->radeon, buf->bo, &domain))
69 return NULL;
70 }
71
72 if (buf->bo->data != NULL) {
73 if (radeon_bo_wait(buf->mgr->radeon, buf->bo)) {
74 return NULL;
75 }
76 } else {
77 if (radeon_bo_map(buf->mgr->radeon, buf->bo)) {
78 return NULL;
79 }
80 if (radeon_bo_wait(buf->mgr->radeon, buf->bo)) {
81 radeon_bo_unmap(buf->mgr->radeon, buf->bo);
82 return NULL;
83 }
84 }
85
86 LIST_DELINIT(&buf->maplist);
87 return buf->bo->data;
88 }
89
90 static void radeon_bo_pb_unmap_internal(struct pb_buffer *_buf)
91 {
92 struct radeon_bo_pb *buf = radeon_bo_pb(_buf);
93 LIST_ADDTAIL(&buf->maplist, &buf->mgr->buffer_map_list);
94 }
95
96 static void
97 radeon_bo_pb_get_base_buffer(struct pb_buffer *buf,
98 struct pb_buffer **base_buf,
99 unsigned *offset)
100 {
101 *base_buf = buf;
102 *offset = 0;
103 }
104
105 static enum pipe_error
106 radeon_bo_pb_validate(struct pb_buffer *_buf,
107 struct pb_validate *vl,
108 unsigned flags)
109 {
110 /* Always pinned */
111 return PIPE_OK;
112 }
113
114 static void
115 radeon_bo_pb_fence(struct pb_buffer *buf,
116 struct pipe_fence_handle *fence)
117 {
118 }
119
120 const struct pb_vtbl radeon_bo_pb_vtbl = {
121 radeon_bo_pb_destroy,
122 radeon_bo_pb_map_internal,
123 radeon_bo_pb_unmap_internal,
124 radeon_bo_pb_validate,
125 radeon_bo_pb_fence,
126 radeon_bo_pb_get_base_buffer,
127 };
128
129 struct pb_buffer *
130 radeon_bo_pb_create_buffer_from_handle(struct pb_manager *_mgr,
131 uint32_t handle)
132 {
133 struct radeon_bo_pbmgr *mgr = radeon_bo_pbmgr(_mgr);
134 struct radeon *radeon = mgr->radeon;
135 struct radeon_bo_pb *bo;
136 struct radeon_bo *hw_bo;
137
138 hw_bo = radeon_bo(radeon, handle, 0, 0, NULL);
139 if (hw_bo == NULL)
140 return NULL;
141
142 bo = CALLOC_STRUCT(radeon_bo_pb);
143 if (!bo) {
144 radeon_bo_reference(radeon, &hw_bo, NULL);
145 return NULL;
146 }
147
148 LIST_INITHEAD(&bo->maplist);
149 pipe_reference_init(&bo->b.base.reference, 1);
150 bo->b.base.alignment = 0;
151 bo->b.base.usage = PB_USAGE_GPU_WRITE | PB_USAGE_GPU_READ;
152 bo->b.base.size = hw_bo->size;
153 bo->b.vtbl = &radeon_bo_pb_vtbl;
154 bo->mgr = mgr;
155
156 bo->bo = hw_bo;
157
158 return &bo->b;
159 }
160
161 static struct pb_buffer *
162 radeon_bo_pb_create_buffer(struct pb_manager *_mgr,
163 pb_size size,
164 const struct pb_desc *desc)
165 {
166 struct radeon_bo_pbmgr *mgr = radeon_bo_pbmgr(_mgr);
167 struct radeon *radeon = mgr->radeon;
168 struct radeon_bo_pb *bo;
169 uint32_t domain;
170
171 bo = CALLOC_STRUCT(radeon_bo_pb);
172 if (!bo)
173 goto error1;
174
175 pipe_reference_init(&bo->b.base.reference, 1);
176 bo->b.base.alignment = desc->alignment;
177 bo->b.base.usage = desc->usage;
178 bo->b.base.size = size;
179 bo->b.vtbl = &radeon_bo_pb_vtbl;
180 bo->mgr = mgr;
181
182 LIST_INITHEAD(&bo->maplist);
183
184 bo->bo = radeon_bo(radeon, 0, size,
185 desc->alignment, NULL);
186 if (bo->bo == NULL)
187 goto error2;
188 return &bo->b;
189
190 error2:
191 FREE(bo);
192 error1:
193 return NULL;
194 }
195
196 static void
197 radeon_bo_pbmgr_flush(struct pb_manager *mgr)
198 {
199 /* NOP */
200 }
201
202 static void
203 radeon_bo_pbmgr_destroy(struct pb_manager *_mgr)
204 {
205 struct radeon_bo_pbmgr *mgr = radeon_bo_pbmgr(_mgr);
206 FREE(mgr);
207 }
208
209 struct pb_manager *radeon_bo_pbmgr_create(struct radeon *radeon)
210 {
211 struct radeon_bo_pbmgr *mgr;
212
213 mgr = CALLOC_STRUCT(radeon_bo_pbmgr);
214 if (!mgr)
215 return NULL;
216
217 mgr->b.destroy = radeon_bo_pbmgr_destroy;
218 mgr->b.create_buffer = radeon_bo_pb_create_buffer;
219 mgr->b.flush = radeon_bo_pbmgr_flush;
220
221 mgr->radeon = radeon;
222 LIST_INITHEAD(&mgr->buffer_map_list);
223 return &mgr->b;
224 }
225
226 void radeon_bo_pbmgr_flush_maps(struct pb_manager *_mgr)
227 {
228 struct radeon_bo_pbmgr *mgr = radeon_bo_pbmgr(_mgr);
229 struct radeon_bo_pb *rpb = NULL;
230 struct radeon_bo_pb *t_rpb;
231
232 LIST_FOR_EACH_ENTRY_SAFE(rpb, t_rpb, &mgr->buffer_map_list, maplist) {
233 radeon_bo_unmap(mgr->radeon, rpb->bo);
234 LIST_DELINIT(&rpb->maplist);
235 }
236
237 LIST_INITHEAD(&mgr->buffer_map_list);
238 }
239
240 struct radeon_bo *radeon_bo_pb_get_bo(struct pb_buffer *_buf)
241 {
242 struct radeon_bo_pb *buf;
243 if (_buf->vtbl == &radeon_bo_pb_vtbl) {
244 buf = radeon_bo_pb(_buf);
245 return buf->bo;
246 } else {
247 struct pb_buffer *base_buf;
248 pb_size offset;
249 pb_get_base_buffer(_buf, &base_buf, &offset);
250 if (base_buf->vtbl == &radeon_bo_pb_vtbl) {
251 buf = radeon_bo_pb(base_buf);
252 return buf->bo;
253 }
254 }
255 return NULL;
256 }