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