1 /*****************************************************************************
2 * picture_pool.c : picture pool functions
3 *****************************************************************************
4 * Copyright (C) 2009 VLC authors and VideoLAN
5 * Copyright (C) 2009 Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
8 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_picture_pool.h>
37 /*****************************************************************************
39 *****************************************************************************/
40 struct picture_gc_sys_t
{
42 void (*destroy
)(picture_t
*);
46 int (*lock
)(picture_t
*);
47 void (*unlock
)(picture_t
*);
54 struct picture_pool_t
{
56 picture_pool_t
*master
;
61 bool *picture_reserved
;
64 static void Destroy(picture_t
*);
65 static int Lock(picture_t
*);
66 static void Unlock(picture_t
*);
68 static picture_pool_t
*Create(picture_pool_t
*master
, int picture_count
)
70 picture_pool_t
*pool
= calloc(1, sizeof(*pool
));
74 pool
->master
= master
;
75 pool
->tick
= master
? master
->tick
: 1;
76 pool
->picture_count
= picture_count
;
77 pool
->picture
= calloc(pool
->picture_count
, sizeof(*pool
->picture
));
78 pool
->picture_reserved
= calloc(pool
->picture_count
, sizeof(*pool
->picture_reserved
));
79 if (!pool
->picture
|| !pool
->picture_reserved
) {
81 free(pool
->picture_reserved
);
88 picture_pool_t
*picture_pool_NewExtended(const picture_pool_configuration_t
*cfg
)
90 picture_pool_t
*pool
= Create(NULL
, cfg
->picture_count
);
95 * NOTE: When a pooled picture is released, it must be returned to the list
96 * of available pictures from its pool, rather than destroyed.
97 * This requires a dedicated release callback, a pointer to the pool and a
98 * reference count. For simplicity, rather than allocate a whole new
99 * picture_t structure, the pool overrides gc.pf_destroy and gc.p_sys when
100 * created, and restores them when destroyed.
101 * There are some implications to keep in mind:
102 * - The original creator of the picture (e.g. video output display) must
103 * not manipulate the gc parameters while the picture is pooled.
104 * - The picture cannot be pooled more than once, in other words, pools
105 * cannot be stacked/layered.
106 * - The picture must be available and its reference count equal to one
107 * when it gets pooled.
108 * - Picture plane pointers and sizes must not be mangled in any case.
110 for (int i
= 0; i
< cfg
->picture_count
; i
++) {
111 picture_t
*picture
= cfg
->picture
[i
];
113 /* Save the original garbage collector */
114 picture_gc_sys_t
*gc_sys
= malloc(sizeof(*gc_sys
));
115 if (unlikely(gc_sys
== NULL
))
117 gc_sys
->destroy
= picture
->gc
.pf_destroy
;
118 gc_sys
->destroy_sys
= picture
->gc
.p_sys
;
119 gc_sys
->lock
= cfg
->lock
;
120 gc_sys
->unlock
= cfg
->unlock
;
121 atomic_init(&gc_sys
->zombie
, false);
124 /* Override the garbage collector */
125 assert(atomic_load(&picture
->gc
.refcount
) == 1);
126 atomic_init(&picture
->gc
.refcount
, 0);
127 picture
->gc
.pf_destroy
= Destroy
;
128 picture
->gc
.p_sys
= gc_sys
;
131 pool
->picture
[i
] = picture
;
132 pool
->picture_reserved
[i
] = false;
138 picture_pool_t
*picture_pool_New(int picture_count
, picture_t
*picture
[])
140 picture_pool_configuration_t cfg
;
142 memset(&cfg
, 0, sizeof(cfg
));
143 cfg
.picture_count
= picture_count
;
144 cfg
.picture
= picture
;
146 return picture_pool_NewExtended(&cfg
);
149 picture_pool_t
*picture_pool_NewFromFormat(const video_format_t
*fmt
, int picture_count
)
151 picture_t
*picture
[picture_count
];
153 for (int i
= 0; i
< picture_count
; i
++) {
154 picture
[i
] = picture_NewFromFormat(fmt
);
158 picture_pool_t
*pool
= picture_pool_New(picture_count
, picture
);
165 for (int i
= 0; i
< picture_count
; i
++) {
168 picture_Release(picture
[i
]);
173 picture_pool_t
*picture_pool_Reserve(picture_pool_t
*master
, int count
)
175 picture_pool_t
*pool
= Create(master
, count
);
180 for (int i
= 0; i
< master
->picture_count
&& found
< count
; i
++) {
181 if (master
->picture_reserved
[i
])
184 assert(atomic_load(&master
->picture
[i
]->gc
.refcount
) == 0);
185 master
->picture_reserved
[i
] = true;
187 pool
->picture
[found
] = master
->picture
[i
];
188 pool
->picture_reserved
[found
] = false;
192 picture_pool_Delete(pool
);
198 void picture_pool_Delete(picture_pool_t
*pool
)
200 for (int i
= 0; i
< pool
->picture_count
; i
++) {
201 picture_t
*picture
= pool
->picture
[i
];
203 for (int j
= 0; j
< pool
->master
->picture_count
; j
++) {
204 if (pool
->master
->picture
[j
] == picture
)
205 pool
->master
->picture_reserved
[j
] = false;
208 picture_gc_sys_t
*gc_sys
= picture
->gc
.p_sys
;
210 assert(!pool
->picture_reserved
[i
]);
212 /* Restore the original garbage collector */
213 if (atomic_fetch_add(&picture
->gc
.refcount
, 1) == 0)
214 { /* Simple case: the picture is not locked, destroy it now. */
215 picture
->gc
.pf_destroy
= gc_sys
->destroy
;
216 picture
->gc
.p_sys
= gc_sys
->destroy_sys
;
219 else /* Intricate case: the picture is still locked and the gc
220 cannot be modified (w/o memory synchronization). */
221 atomic_store(&gc_sys
->zombie
, true);
223 picture_Release(picture
);
226 free(pool
->picture_reserved
);
231 picture_t
*picture_pool_Get(picture_pool_t
*pool
)
233 for (int i
= 0; i
< pool
->picture_count
; i
++) {
234 if (pool
->picture_reserved
[i
])
237 picture_t
*picture
= pool
->picture
[i
];
238 if (atomic_load(&picture
->gc
.refcount
) > 0)
245 picture
->p_next
= NULL
;
246 picture
->gc
.p_sys
->tick
= pool
->tick
++;
247 picture_Hold(picture
);
253 void picture_pool_NonEmpty(picture_pool_t
*pool
, bool reset
)
255 picture_t
*old
= NULL
;
257 for (int i
= 0; i
< pool
->picture_count
; i
++) {
258 if (pool
->picture_reserved
[i
])
261 picture_t
*picture
= pool
->picture
[i
];
263 if (atomic_load(&picture
->gc
.refcount
) > 0)
265 atomic_store(&picture
->gc
.refcount
, 0);
266 } else if (atomic_load(&picture
->gc
.refcount
) == 0) {
268 } else if (!old
|| picture
->gc
.p_sys
->tick
< old
->gc
.p_sys
->tick
) {
273 if (atomic_load(&old
->gc
.refcount
) > 0)
275 atomic_store(&old
->gc
.refcount
, 0);
278 int picture_pool_GetSize(picture_pool_t
*pool
)
280 return pool
->picture_count
;
283 static void Destroy(picture_t
*picture
)
285 picture_gc_sys_t
*gc_sys
= picture
->gc
.p_sys
;
289 if (atomic_load(&gc_sys
->zombie
))
290 { /* Picture from an already destroyed pool */
291 picture
->gc
.pf_destroy
= gc_sys
->destroy
;
292 picture
->gc
.p_sys
= gc_sys
->destroy_sys
;
295 picture
->gc
.pf_destroy(picture
);
299 static int Lock(picture_t
*picture
)
301 picture_gc_sys_t
*gc_sys
= picture
->gc
.p_sys
;
303 return gc_sys
->lock(picture
);
307 static void Unlock(picture_t
*picture
)
309 picture_gc_sys_t
*gc_sys
= picture
->gc
.p_sys
;
311 gc_sys
->unlock(picture
);