summaryrefslogtreecommitdiff
path: root/src/til.c
blob: 651a23a7da20da8f4d42905e632e4ebe376e75f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <inttypes.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>

#include "til.h"
#include "til_fb.h"
#include "til_settings.h"
#include "til_threads.h"
#include "til_util.h"

/* Copyright (C) 2016 Vito Caputo <vcaputo@pengaru.com> */

#define DEFAULT_MODULE	"rtv"

static til_threads_t	*til_threads;

extern til_module_t	compose_module;
extern til_module_t	drizzle_module;
extern til_module_t	flui2d_module;
extern til_module_t	julia_module;
extern til_module_t	meta2d_module;
extern til_module_t	montage_module;
extern til_module_t	pixbounce_module;
extern til_module_t	plasma_module;
extern til_module_t	plato_module;
extern til_module_t	ray_module;
extern til_module_t	roto_module;
extern til_module_t	rtv_module;
extern til_module_t	snow_module;
extern til_module_t	sparkler_module;
extern til_module_t	spiro_module;
extern til_module_t	stars_module;
extern til_module_t	submit_module;
extern til_module_t	swab_module;
extern til_module_t	swarm_module;

static const til_module_t	*modules[] = {
	&compose_module,
	&drizzle_module,
	&flui2d_module,
	&julia_module,
	&meta2d_module,
	&montage_module,
	&pixbounce_module,
	&plasma_module,
	&plato_module,
	&ray_module,
	&roto_module,
	&rtv_module,
	&snow_module,
	&sparkler_module,
	&spiro_module,
	&stars_module,
	&submit_module,
	&swab_module,
	&swarm_module,
};


/* initialize rototiller (create rendering threads) */
int til_init(void)
{
	/* Various modules seed srand(), just do it here so they don't need to.
	 * At some point in the future this might become undesirable, if reproducible
	 * pseudo-randomized output is actually desirable.  But that should probably be
	 * achieved using rand_r() anyways, since modules can't prevent others from playing
	 * with srand().
	 */
	srand(time(NULL) + getpid());

	if (!(til_threads = til_threads_create()))
		return -errno;

	return 0;
}


/* wait for all threads to be idle */
void til_quiesce(void)
{
	til_threads_wait_idle(til_threads);
}


void til_shutdown(void)
{
	til_threads_destroy(til_threads);
}


const til_module_t * til_lookup_module(const char *name)
{
	assert(name);

	for (size_t i = 0; i < nelems(modules); i++) {
		if (!strcasecmp(name, modules[i]->name))
			return modules[i];
	}

	return NULL;
}


void til_get_modules(const til_module_t ***res_modules, size_t *res_n_modules)
{
	assert(res_modules);
	assert(res_n_modules);

	*res_modules = modules;
	*res_n_modules = nelems(modules);
}


static void module_render_fragment(const til_module_t *module, void *context, til_threads_t *threads, unsigned ticks, til_fb_fragment_t *fragment)
{
	assert(module);
	assert(threads);
	assert(fragment);

	if (module->prepare_frame) {
		til_fragmenter_t	fragmenter;

		module->prepare_frame(context, ticks, til_threads_num_threads(threads), fragment, &fragmenter);

		if (module->render_fragment) {
			til_threads_frame_submit(threads, fragment, fragmenter, module->render_fragment, context, ticks);
			til_threads_wait_idle(threads);
		}

	} else if (module->render_fragment)
		module->render_fragment(context, ticks, 0, fragment);

	if (module->finish_frame)
		module->finish_frame(context, ticks, fragment);
}


/* This is a public interface to the threaded module rendering intended for use by
 * modules that wish to get the output of other modules for their own use.
 */
void til_module_render(const til_module_t *module, void *context, unsigned ticks, til_fb_fragment_t *fragment)
{
	module_render_fragment(module, context, til_threads, ticks, fragment);
}


int til_module_create_context(const til_module_t *module, unsigned ticks, void *setup, void **res_context)
{
	void	*context;

	assert(module);
	assert(res_context);

	if (!module->create_context)
		return 0;

	context = module->create_context(ticks, til_threads_num_threads(til_threads), setup);
	if (!context)
		return -ENOMEM;

	*res_context = context;

	return 0;
}


void * til_module_destroy_context(const til_module_t *module, void *context)
{
	assert(module);

	if (!module->destroy_context)
		return NULL;

	module->destroy_context(context);

	return NULL;
}


/* select module if not yet selected, then setup the module. */
int til_module_setup(til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, void **res_setup)
{
	til_setting_t		*setting;
	const til_module_t	*module;
	const char		*name;

	name = til_settings_get_key(settings, 0, &setting);
	if (!name) {
		const char		*values[nelems(modules) + 1] = {};
		const char		*annotations[nelems(modules) + 1] = {};
		til_setting_desc_t	*desc;
		int			r;

		for (unsigned i = 0; i < nelems(modules); i++) {
			values[i] = modules[i]->name;
			annotations[i] = modules[i]->description;
		}

		r = til_setting_desc_clone(&(til_setting_desc_t){
						.name = "Renderer module",
						.key = NULL,
						.regex = "[a-zA-Z0-9]+",
						.preferred = DEFAULT_MODULE,
						.values = values,
						.annotations = annotations
					}, res_desc);
		if (r < 0)
			return r;

		*res_setting = name ? setting : NULL;

		return 1;
	}

	module = til_lookup_module(name);
	if (!module)
		return -EINVAL;

	if (module->setup)
		return module->setup(settings, res_setting, res_desc, res_setup);

	return 0;
}
© All Rights Reserved