Merge branch 'gallium-0.1' into gallium-tex-surfaces
[mesa.git] / src / gallium / auxiliary / pipebuffer / pb_bufmgr_mm.c
1 /**************************************************************************
2 *
3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /**
29 * \file
30 * Buffer manager using the old texture memory manager.
31 *
32 * \author José Fonseca <jrfonseca@tungstengraphics.com>
33 */
34
35
36 #include "pipe/p_defines.h"
37 #include "pipe/p_debug.h"
38 #include "pipe/p_thread.h"
39 #include "pipe/p_util.h"
40 #include "util/u_double_list.h"
41 #include "util/u_mm.h"
42 #include "pb_buffer.h"
43 #include "pb_bufmgr.h"
44
45
46 /**
47 * Convenience macro (type safe).
48 */
49 #define SUPER(__derived) (&(__derived)->base)
50
51
52 struct mm_pb_manager
53 {
54 struct pb_manager base;
55
56 _glthread_Mutex mutex;
57
58 size_t size;
59 struct mem_block *heap;
60
61 size_t align2;
62
63 struct pb_buffer *buffer;
64 void *map;
65 };
66
67
68 static INLINE struct mm_pb_manager *
69 mm_pb_manager(struct pb_manager *mgr)
70 {
71 assert(mgr);
72 return (struct mm_pb_manager *)mgr;
73 }
74
75
76 struct mm_buffer
77 {
78 struct pb_buffer base;
79
80 struct mm_pb_manager *mgr;
81
82 struct mem_block *block;
83 };
84
85
86 static INLINE struct mm_buffer *
87 mm_buffer(struct pb_buffer *buf)
88 {
89 assert(buf);
90 return (struct mm_buffer *)buf;
91 }
92
93
94 static void
95 mm_buffer_destroy(struct pb_buffer *buf)
96 {
97 struct mm_buffer *mm_buf = mm_buffer(buf);
98 struct mm_pb_manager *mm = mm_buf->mgr;
99
100 assert(buf->base.refcount == 0);
101
102 _glthread_LOCK_MUTEX(mm->mutex);
103 mmFreeMem(mm_buf->block);
104 FREE(buf);
105 _glthread_UNLOCK_MUTEX(mm->mutex);
106 }
107
108
109 static void *
110 mm_buffer_map(struct pb_buffer *buf,
111 unsigned flags)
112 {
113 struct mm_buffer *mm_buf = mm_buffer(buf);
114 struct mm_pb_manager *mm = mm_buf->mgr;
115
116 return (unsigned char *) mm->map + mm_buf->block->ofs;
117 }
118
119
120 static void
121 mm_buffer_unmap(struct pb_buffer *buf)
122 {
123 /* No-op */
124 }
125
126
127 static void
128 mm_buffer_get_base_buffer(struct pb_buffer *buf,
129 struct pb_buffer **base_buf,
130 unsigned *offset)
131 {
132 struct mm_buffer *mm_buf = mm_buffer(buf);
133 struct mm_pb_manager *mm = mm_buf->mgr;
134 pb_get_base_buffer(mm->buffer, base_buf, offset);
135 *offset += mm_buf->block->ofs;
136 }
137
138
139 static const struct pb_vtbl
140 mm_buffer_vtbl = {
141 mm_buffer_destroy,
142 mm_buffer_map,
143 mm_buffer_unmap,
144 mm_buffer_get_base_buffer
145 };
146
147
148 static struct pb_buffer *
149 mm_bufmgr_create_buffer(struct pb_manager *mgr,
150 size_t size,
151 const struct pb_desc *desc)
152 {
153 struct mm_pb_manager *mm = mm_pb_manager(mgr);
154 struct mm_buffer *mm_buf;
155
156 /* We don't handle alignments larger then the one initially setup */
157 assert(desc->alignment % (1 << mm->align2) == 0);
158 if(desc->alignment % (1 << mm->align2))
159 return NULL;
160
161 _glthread_LOCK_MUTEX(mm->mutex);
162
163 mm_buf = CALLOC_STRUCT(mm_buffer);
164 if (!mm_buf) {
165 _glthread_UNLOCK_MUTEX(mm->mutex);
166 return NULL;
167 }
168
169 mm_buf->base.base.refcount = 1;
170 mm_buf->base.base.alignment = desc->alignment;
171 mm_buf->base.base.usage = desc->usage;
172 mm_buf->base.base.size = size;
173
174 mm_buf->base.vtbl = &mm_buffer_vtbl;
175
176 mm_buf->mgr = mm;
177
178 mm_buf->block = mmAllocMem(mm->heap, size, mm->align2, 0);
179 if(!mm_buf->block) {
180 debug_printf("warning: heap full\n");
181 #if 0
182 mmDumpMemInfo(mm->heap);
183 #endif
184
185 mm_buf->block = mmAllocMem(mm->heap, size, mm->align2, 0);
186 if(!mm_buf->block) {
187 assert(0);
188 FREE(mm_buf);
189 _glthread_UNLOCK_MUTEX(mm->mutex);
190 return NULL;
191 }
192 }
193
194 /* Some sanity checks */
195 assert(0 <= (unsigned)mm_buf->block->ofs && (unsigned)mm_buf->block->ofs < mm->size);
196 assert(size <= (unsigned)mm_buf->block->size && (unsigned)mm_buf->block->ofs + (unsigned)mm_buf->block->size <= mm->size);
197
198 _glthread_UNLOCK_MUTEX(mm->mutex);
199 return SUPER(mm_buf);
200 }
201
202
203 static void
204 mm_bufmgr_destroy(struct pb_manager *mgr)
205 {
206 struct mm_pb_manager *mm = mm_pb_manager(mgr);
207
208 _glthread_LOCK_MUTEX(mm->mutex);
209
210 mmDestroy(mm->heap);
211
212 pb_unmap(mm->buffer);
213 pb_reference(&mm->buffer, NULL);
214
215 _glthread_UNLOCK_MUTEX(mm->mutex);
216
217 FREE(mgr);
218 }
219
220
221 struct pb_manager *
222 mm_bufmgr_create_from_buffer(struct pb_buffer *buffer,
223 size_t size, size_t align2)
224 {
225 struct mm_pb_manager *mm;
226
227 if(!buffer)
228 return NULL;
229
230 mm = CALLOC_STRUCT(mm_pb_manager);
231 if (!mm)
232 return NULL;
233
234 mm->base.create_buffer = mm_bufmgr_create_buffer;
235 mm->base.destroy = mm_bufmgr_destroy;
236
237 mm->size = size;
238 mm->align2 = align2; /* 64-byte alignment */
239
240 _glthread_INIT_MUTEX(mm->mutex);
241
242 mm->buffer = buffer;
243
244 mm->map = pb_map(mm->buffer,
245 PIPE_BUFFER_USAGE_CPU_READ |
246 PIPE_BUFFER_USAGE_CPU_WRITE);
247 if(!mm->map)
248 goto failure;
249
250 mm->heap = mmInit(0, size);
251 if (!mm->heap)
252 goto failure;
253
254 return SUPER(mm);
255
256 failure:
257 if(mm->heap)
258 mmDestroy(mm->heap);
259 if(mm->map)
260 pb_unmap(mm->buffer);
261 if(mm)
262 FREE(mm);
263 return NULL;
264 }
265
266
267 struct pb_manager *
268 mm_bufmgr_create(struct pb_manager *provider,
269 size_t size, size_t align2)
270 {
271 struct pb_buffer *buffer;
272 struct pb_manager *mgr;
273 struct pb_desc desc;
274
275 assert(provider);
276 assert(provider->create_buffer);
277
278 memset(&desc, 0, sizeof(desc));
279 desc.alignment = 1 << align2;
280
281 buffer = provider->create_buffer(provider, size, &desc);
282 if (!buffer)
283 return NULL;
284
285 mgr = mm_bufmgr_create_from_buffer(buffer, size, align2);
286 if (!mgr) {
287 pb_reference(&buffer, NULL);
288 return NULL;
289 }
290
291 return mgr;
292 }