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