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