1/**************************************************************************
2 *
3 * Copyright 2008 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 * A variation of malloc buffers which get transferred to real graphics memory
31 * when there is an attempt to validate them.
32 *
33 * @author Jose Fonseca <jrfonseca@tungstengraphics.com>
34 */
35
36
37#include "util/u_debug.h"
38#include "util/u_memory.h"
39#include "pb_buffer.h"
40#include "pb_bufmgr.h"
41
42
43struct pb_ondemand_manager;
44
45
46struct pb_ondemand_buffer
47{
48   struct pb_buffer base;
49
50   struct pb_ondemand_manager *mgr;
51
52   /** Regular malloc'ed memory */
53   void *data;
54   unsigned mapcount;
55
56   /** Real buffer */
57   struct pb_buffer *buffer;
58   pb_size size;
59   struct pb_desc desc;
60};
61
62
63struct pb_ondemand_manager
64{
65   struct pb_manager base;
66
67   struct pb_manager *provider;
68};
69
70
71extern const struct pb_vtbl pb_ondemand_buffer_vtbl;
72
73static INLINE struct pb_ondemand_buffer *
74pb_ondemand_buffer(struct pb_buffer *buf)
75{
76   assert(buf);
77   if (!buf)
78      return NULL;
79   assert(buf->vtbl == &pb_ondemand_buffer_vtbl);
80   return (struct pb_ondemand_buffer *)buf;
81}
82
83static INLINE struct pb_ondemand_manager *
84pb_ondemand_manager(struct pb_manager *mgr)
85{
86   assert(mgr);
87   return (struct pb_ondemand_manager *)mgr;
88}
89
90
91static void
92pb_ondemand_buffer_destroy(struct pb_buffer *_buf)
93{
94   struct pb_ondemand_buffer *buf = pb_ondemand_buffer(_buf);
95
96   pb_reference(&buf->buffer, NULL);
97
98   align_free(buf->data);
99
100   FREE(buf);
101}
102
103
104static void *
105pb_ondemand_buffer_map(struct pb_buffer *_buf,
106                       unsigned flags, void *flush_ctx)
107{
108   struct pb_ondemand_buffer *buf = pb_ondemand_buffer(_buf);
109
110   if(buf->buffer) {
111      assert(!buf->data);
112      return pb_map(buf->buffer, flags, flush_ctx);
113   }
114   else {
115      assert(buf->data);
116      ++buf->mapcount;
117      return buf->data;
118   }
119}
120
121
122static void
123pb_ondemand_buffer_unmap(struct pb_buffer *_buf)
124{
125   struct pb_ondemand_buffer *buf = pb_ondemand_buffer(_buf);
126
127   if(buf->buffer) {
128      assert(!buf->data);
129      pb_unmap(buf->buffer);
130   }
131   else {
132      assert(buf->data);
133      assert(buf->mapcount);
134      if(buf->mapcount)
135         --buf->mapcount;
136   }
137}
138
139
140static enum pipe_error
141pb_ondemand_buffer_instantiate(struct pb_ondemand_buffer *buf)
142{
143   if(!buf->buffer) {
144      struct pb_manager *provider = buf->mgr->provider;
145      uint8_t *map;
146
147      assert(!buf->mapcount);
148
149      buf->buffer = provider->create_buffer(provider, buf->size, &buf->desc);
150      if(!buf->buffer)
151         return PIPE_ERROR_OUT_OF_MEMORY;
152
153      map = pb_map(buf->buffer, PB_USAGE_CPU_READ, NULL);
154      if(!map) {
155         pb_reference(&buf->buffer, NULL);
156         return PIPE_ERROR;
157      }
158
159      memcpy(map, buf->data, buf->size);
160
161      pb_unmap(buf->buffer);
162
163      if(!buf->mapcount) {
164         FREE(buf->data);
165         buf->data = NULL;
166      }
167   }
168
169   return PIPE_OK;
170}
171
172static enum pipe_error
173pb_ondemand_buffer_validate(struct pb_buffer *_buf,
174                            struct pb_validate *vl,
175                            unsigned flags)
176{
177   struct pb_ondemand_buffer *buf = pb_ondemand_buffer(_buf);
178   enum pipe_error ret;
179
180   assert(!buf->mapcount);
181   if(buf->mapcount)
182      return PIPE_ERROR;
183
184   ret = pb_ondemand_buffer_instantiate(buf);
185   if(ret != PIPE_OK)
186      return ret;
187
188   return pb_validate(buf->buffer, vl, flags);
189}
190
191
192static void
193pb_ondemand_buffer_fence(struct pb_buffer *_buf,
194                         struct pipe_fence_handle *fence)
195{
196   struct pb_ondemand_buffer *buf = pb_ondemand_buffer(_buf);
197
198   assert(buf->buffer);
199   if(!buf->buffer)
200      return;
201
202   pb_fence(buf->buffer, fence);
203}
204
205
206static void
207pb_ondemand_buffer_get_base_buffer(struct pb_buffer *_buf,
208                                   struct pb_buffer **base_buf,
209                                   pb_size *offset)
210{
211   struct pb_ondemand_buffer *buf = pb_ondemand_buffer(_buf);
212
213   if(pb_ondemand_buffer_instantiate(buf) != PIPE_OK) {
214      assert(0);
215      *base_buf = &buf->base;
216      *offset = 0;
217      return;
218   }
219
220   pb_get_base_buffer(buf->buffer, base_buf, offset);
221}
222
223
224const struct pb_vtbl
225pb_ondemand_buffer_vtbl = {
226      pb_ondemand_buffer_destroy,
227      pb_ondemand_buffer_map,
228      pb_ondemand_buffer_unmap,
229      pb_ondemand_buffer_validate,
230      pb_ondemand_buffer_fence,
231      pb_ondemand_buffer_get_base_buffer
232};
233
234
235static struct pb_buffer *
236pb_ondemand_manager_create_buffer(struct pb_manager *_mgr,
237                                  pb_size size,
238                                  const struct pb_desc *desc)
239{
240   struct pb_ondemand_manager *mgr = pb_ondemand_manager(_mgr);
241   struct pb_ondemand_buffer *buf;
242
243   buf = CALLOC_STRUCT(pb_ondemand_buffer);
244   if(!buf)
245      return NULL;
246
247   pipe_reference_init(&buf->base.reference, 1);
248   buf->base.alignment = desc->alignment;
249   buf->base.usage = desc->usage;
250   buf->base.size = size;
251   buf->base.vtbl = &pb_ondemand_buffer_vtbl;
252
253   buf->mgr = mgr;
254
255   buf->data = align_malloc(size, desc->alignment < sizeof(void*) ? sizeof(void*) : desc->alignment);
256   if(!buf->data) {
257      FREE(buf);
258      return NULL;
259   }
260
261   buf->size = size;
262   buf->desc = *desc;
263
264   return &buf->base;
265}
266
267
268static void
269pb_ondemand_manager_flush(struct pb_manager *_mgr)
270{
271   struct pb_ondemand_manager *mgr = pb_ondemand_manager(_mgr);
272
273   mgr->provider->flush(mgr->provider);
274}
275
276
277static void
278pb_ondemand_manager_destroy(struct pb_manager *_mgr)
279{
280   struct pb_ondemand_manager *mgr = pb_ondemand_manager(_mgr);
281
282   FREE(mgr);
283}
284
285
286struct pb_manager *
287pb_ondemand_manager_create(struct pb_manager *provider)
288{
289   struct pb_ondemand_manager *mgr;
290
291   if(!provider)
292      return NULL;
293
294   mgr = CALLOC_STRUCT(pb_ondemand_manager);
295   if(!mgr)
296      return NULL;
297
298   mgr->base.destroy = pb_ondemand_manager_destroy;
299   mgr->base.create_buffer = pb_ondemand_manager_create_buffer;
300   mgr->base.flush = pb_ondemand_manager_flush;
301
302   mgr->provider = provider;
303
304   return &mgr->base;
305}
306