fix for crash when a python operator or render engine was freed in the C code and...
[blender.git] / source / blender / render / intern / source / external_engine.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2006 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/render/intern/source/external_engine.c
29  *  \ingroup render
30  */
31
32 #include <stddef.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLF_translation.h"
39
40 #include "BLI_listbase.h"
41 #include "BLI_string.h"
42 #include "BLI_utildefines.h"
43
44 #include "BKE_global.h"
45 #include "BKE_report.h"
46 #include "BKE_scene.h"
47
48 #include "IMB_imbuf.h"
49 #include "IMB_imbuf_types.h"
50
51 #ifdef WITH_PYTHON
52 #include "BPY_extern.h"
53 #endif
54
55 #include "RE_engine.h"
56 #include "RE_pipeline.h"
57
58 #include "initrender.h"
59 #include "render_types.h"
60 #include "render_result.h"
61
62 /* Render Engine Types */
63
64 static RenderEngineType internal_render_type = {
65         NULL, NULL,
66         "BLENDER_RENDER", N_("Blender Render"), RE_INTERNAL,
67         NULL, NULL, NULL, NULL,
68         {NULL, NULL, NULL}
69 };
70
71 #ifdef WITH_GAMEENGINE
72
73 static RenderEngineType internal_game_type = {
74         NULL, NULL,
75         "BLENDER_GAME", N_("Blender Game"), RE_INTERNAL | RE_GAME,
76         NULL, NULL, NULL, NULL,
77         {NULL, NULL, NULL}
78 };
79
80 #endif
81
82 ListBase R_engines = {NULL, NULL};
83
84 void RE_engines_init(void)
85 {
86         BLI_addtail(&R_engines, &internal_render_type);
87 #ifdef WITH_GAMEENGINE
88         BLI_addtail(&R_engines, &internal_game_type);
89 #endif
90 }
91
92 void RE_engines_exit(void)
93 {
94         RenderEngineType *type, *next;
95
96         for (type = R_engines.first; type; type = next) {
97                 next = type->next;
98
99                 BLI_remlink(&R_engines, type);
100
101                 if (!(type->flag & RE_INTERNAL)) {
102                         if (type->ext.free)
103                                 type->ext.free(type->ext.data);
104
105                         MEM_freeN(type);
106                 }
107         }
108 }
109
110 RenderEngineType *RE_engines_find(const char *idname)
111 {
112         RenderEngineType *type;
113         
114         type = BLI_findstring(&R_engines, idname, offsetof(RenderEngineType, idname));
115         if (!type)
116                 type = &internal_render_type;
117
118         return type;
119 }
120
121 int RE_engine_is_external(Render *re)
122 {
123         RenderEngineType *type = RE_engines_find(re->r.engine);
124         return (type && type->render);
125 }
126
127 /* Create, Free */
128
129 RenderEngine *RE_engine_create(RenderEngineType *type)
130 {
131         RenderEngine *engine = MEM_callocN(sizeof(RenderEngine), "RenderEngine");
132         engine->type = type;
133
134         return engine;
135 }
136
137 void RE_engine_free(RenderEngine *engine)
138 {
139 #ifdef WITH_PYTHON
140         if (engine->py_instance) {
141                 BPY_RNA_DECREF_INVALIDATE(engine->py_instance);
142         }
143 #endif
144
145         if (engine->text)
146                 MEM_freeN(engine->text);
147
148         MEM_freeN(engine);
149 }
150
151 /* Render Results */
152
153 RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername)
154 {
155         Render *re = engine->re;
156         RenderResult *result;
157         rcti disprect;
158
159         /* ensure the coordinates are within the right limits */
160         CLAMP(x, 0, re->result->rectx);
161         CLAMP(y, 0, re->result->recty);
162         CLAMP(w, 0, re->result->rectx);
163         CLAMP(h, 0, re->result->recty);
164
165         if (x + w > re->result->rectx)
166                 w = re->result->rectx - x;
167         if (y + h > re->result->recty)
168                 h = re->result->recty - y;
169
170         /* allocate a render result */
171         disprect.xmin = x;
172         disprect.xmax = x + w;
173         disprect.ymin = y;
174         disprect.ymax = y + h;
175
176         result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername);
177
178         /* todo: make this thread safe */
179
180         /* can be NULL if we CLAMP the width or height to 0 */
181         if (result) {
182                 BLI_addtail(&engine->fullresult, result);
183
184                 result->tilerect.xmin += re->disprect.xmin;
185                 result->tilerect.xmax += re->disprect.xmin;
186                 result->tilerect.ymin += re->disprect.ymin;
187                 result->tilerect.ymax += re->disprect.ymin;
188         }
189
190         return result;
191 }
192
193 void RE_engine_update_result(RenderEngine *engine, RenderResult *result)
194 {
195         Render *re = engine->re;
196
197         if (result) {
198                 result->renlay = result->layers.first; /* weak, draws first layer always */
199                 re->display_draw(re->ddh, result, NULL);
200         }
201 }
202
203 void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel)
204 {
205         Render *re = engine->re;
206         RenderPart *pa;
207
208         if (!result) {
209                 return;
210         }
211
212         /* merge. on break, don't merge in result for preview renders, looks nicer */
213         if (!cancel) {
214                 /* for exr tile render, detect tiles that are done */
215                 for (pa = re->parts.first; pa; pa = pa->next) {
216                         if (result->tilerect.xmin == pa->disprect.xmin &&
217                             result->tilerect.ymin == pa->disprect.ymin &&
218                             result->tilerect.xmax == pa->disprect.xmax &&
219                             result->tilerect.ymax == pa->disprect.ymax)
220                         {
221                                 pa->ready = 1;
222                         }
223                 }
224
225                 if (re->result->do_exr_tile)
226                         render_result_exr_file_merge(re->result, result);
227                 else if (!(re->test_break(re->tbh) && (re->r.scemode & R_PREVIEWBUTS)))
228                         render_result_merge(re->result, result);
229
230                 /* draw */
231                 if (!re->test_break(re->tbh)) {
232                         result->renlay = result->layers.first; /* weak, draws first layer always */
233                         re->display_draw(re->ddh, result, NULL);
234                 }
235         }
236
237         /* free */
238         BLI_remlink(&engine->fullresult, result);
239         render_result_free(result);
240 }
241
242 /* Cancel */
243
244 int RE_engine_test_break(RenderEngine *engine)
245 {
246         Render *re = engine->re;
247
248         if (re)
249                 return re->test_break(re->tbh);
250         
251         return 0;
252 }
253
254 /* Statistics */
255
256 void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info)
257 {
258         Render *re = engine->re;
259
260         /* stats draw callback */
261         if (re) {
262                 re->i.statstr = stats;
263                 re->i.infostr = info;
264                 re->stats_draw(re->sdh, &re->i);
265                 re->i.infostr = NULL;
266                 re->i.statstr = NULL;
267         }
268
269         /* set engine text */
270         if (engine->text) {
271                 MEM_freeN(engine->text);
272                 engine->text = NULL;
273         }
274
275         if (stats && stats[0] && info && info[0])
276                 engine->text = BLI_sprintfN("%s | %s", stats, info);
277         else if (info && info[0])
278                 engine->text = BLI_strdup(info);
279         else if (stats && stats[0])
280                 engine->text = BLI_strdup(stats);
281 }
282
283 void RE_engine_update_progress(RenderEngine *engine, float progress)
284 {
285         Render *re = engine->re;
286
287         if (re) {
288                 CLAMP(progress, 0.0f, 1.0f);
289                 re->progress(re->prh, progress);
290         }
291 }
292
293 void RE_engine_report(RenderEngine *engine, int type, const char *msg)
294 {
295         BKE_report(engine->re->reports, type, msg);
296 }
297
298 /* Render */
299
300 int RE_engine_render(Render *re, int do_all)
301 {
302         RenderEngineType *type = RE_engines_find(re->r.engine);
303         RenderEngine *engine;
304
305         /* verify if we can render */
306         if (!type->render)
307                 return 0;
308         if ((re->r.scemode & R_PREVIEWBUTS) && !(type->flag & RE_USE_PREVIEW))
309                 return 0;
310         if (do_all && !(type->flag & RE_USE_POSTPROCESS))
311                 return 0;
312         if (!do_all && (type->flag & RE_USE_POSTPROCESS))
313                 return 0;
314
315         /* create render result */
316         BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
317         if (re->result == NULL || !(re->r.scemode & R_PREVIEWBUTS)) {
318                 int savebuffers;
319
320                 if (re->result)
321                         render_result_free(re->result);
322
323                 savebuffers = (re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM;
324                 re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS);
325         }
326         BLI_rw_mutex_unlock(&re->resultmutex);
327
328         if (re->result == NULL)
329                 return 1;
330
331         /* set render info */
332         re->i.cfra = re->scene->r.cfra;
333         BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name));
334         re->i.totface = re->i.totvert = re->i.totstrand = re->i.totlamp = re->i.tothalo = 0;
335
336         /* render */
337         engine = RE_engine_create(type);
338         engine->re = re;
339
340         if (re->flag & R_ANIMATION)
341                 engine->flag |= RE_ENGINE_ANIMATION;
342         if (re->r.scemode & R_PREVIEWBUTS)
343                 engine->flag |= RE_ENGINE_PREVIEW;
344         engine->camera_override = re->camera_override;
345
346         engine->resolution_x = re->winx;
347         engine->resolution_y = re->winy;
348
349         if ((re->r.scemode & (R_NO_FRAME_UPDATE | R_PREVIEWBUTS)) == 0)
350                 BKE_scene_update_for_newframe(re->main, re->scene, re->lay);
351
352         initparts(re, FALSE);
353         engine->tile_x = re->partx;
354         engine->tile_y = re->party;
355
356         if (re->result->do_exr_tile)
357                 render_result_exr_file_begin(re);
358
359         if (type->update)
360                 type->update(engine, re->main, re->scene);
361         
362         if (type->render)
363                 type->render(engine, re->scene);
364
365         if (re->result->do_exr_tile) {
366                 BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
367                 render_result_exr_file_end(re);
368                 BLI_rw_mutex_unlock(&re->resultmutex);
369         }
370
371         engine->tile_x = 0;
372         engine->tile_y = 0;
373         freeparts(re);
374
375         render_result_free_list(&engine->fullresult, engine->fullresult.first);
376
377         RE_engine_free(engine);
378
379         if (BKE_reports_contain(re->reports, RPT_ERROR))
380                 G.is_break = TRUE;
381         
382         return 1;
383 }
384