1 /*************************************************************************/
2 /*  visual_server_wrap_mt.cpp                                            */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 #include "visual_server_wrap_mt.h"
31 #include "globals.h"
32 #include "os/os.h"
thread_exit()33 void VisualServerWrapMT::thread_exit() {
34 
35 	exit = true;
36 }
37 
thread_draw()38 void VisualServerWrapMT::thread_draw() {
39 
40 	draw_mutex->lock();
41 
42 	draw_pending--;
43 	bool draw = (draw_pending == 0); // only draw when no more flushes are pending
44 
45 	draw_mutex->unlock();
46 
47 	if (draw) {
48 
49 		visual_server->draw();
50 	}
51 }
52 
thread_flush()53 void VisualServerWrapMT::thread_flush() {
54 
55 	draw_mutex->lock();
56 
57 	draw_pending--;
58 
59 	draw_mutex->unlock();
60 }
61 
_thread_callback(void * _instance)62 void VisualServerWrapMT::_thread_callback(void *_instance) {
63 
64 	VisualServerWrapMT *vsmt = reinterpret_cast<VisualServerWrapMT *>(_instance);
65 
66 	vsmt->thread_loop();
67 }
68 
thread_loop()69 void VisualServerWrapMT::thread_loop() {
70 
71 	server_thread = Thread::get_caller_ID();
72 
73 	OS::get_singleton()->make_rendering_thread();
74 
75 	visual_server->init();
76 
77 	exit = false;
78 	draw_thread_up = true;
79 	while (!exit) {
80 		// flush commands one by one, until exit is requested
81 		command_queue.wait_and_flush_one();
82 	}
83 
84 	command_queue.flush_all(); // flush all
85 
86 	visual_server->finish();
87 }
88 
89 /* EVENT QUEUING */
90 
sync()91 void VisualServerWrapMT::sync() {
92 
93 	if (create_thread) {
94 
95 		/* TODO: sync with the thread */
96 
97 		/*
98 		ERR_FAIL_COND(!draw_mutex);
99 		draw_mutex->lock();
100 		draw_pending++; //cambiar por un saferefcount
101 		draw_mutex->unlock();
102 		*/
103 		//command_queue.push( this, &VisualServerWrapMT::thread_flush);
104 	} else {
105 
106 		command_queue.flush_all(); //flush all pending from other threads
107 	}
108 }
109 
draw()110 void VisualServerWrapMT::draw() {
111 
112 	if (create_thread) {
113 
114 		/* TODO: Make it draw
115 		ERR_FAIL_COND(!draw_mutex);
116 		draw_mutex->lock();
117 		draw_pending++; //cambiar por un saferefcount
118 		draw_mutex->unlock();
119 
120 		command_queue.push( this, &VisualServerWrapMT::thread_draw);
121 		*/
122 	} else {
123 
124 		visual_server->draw();
125 	}
126 }
127 
init()128 void VisualServerWrapMT::init() {
129 
130 	if (create_thread) {
131 
132 		draw_mutex = Mutex::create();
133 		print_line("Creating render thread");
134 		OS::get_singleton()->release_rendering_thread();
135 		if (create_thread) {
136 			thread = Thread::create(_thread_callback, this);
137 			print_line("Starting render thread");
138 		}
139 		while (!draw_thread_up) {
140 			OS::get_singleton()->delay_usec(1000);
141 		}
142 		print_line("Done render thread");
143 	} else {
144 
145 		visual_server->init();
146 	}
147 }
148 
finish()149 void VisualServerWrapMT::finish() {
150 
151 	if (thread) {
152 
153 		command_queue.push(this, &VisualServerWrapMT::thread_exit);
154 		Thread::wait_to_finish(thread);
155 		memdelete(thread);
156 
157 		texture_free_cached_ids();
158 		mesh_free_cached_ids();
159 
160 		thread = NULL;
161 	} else {
162 		visual_server->finish();
163 	}
164 
165 	if (draw_mutex)
166 		memdelete(draw_mutex);
167 }
168 
VisualServerWrapMT(VisualServer * p_contained,bool p_create_thread)169 VisualServerWrapMT::VisualServerWrapMT(VisualServer *p_contained, bool p_create_thread) :
170 		command_queue(p_create_thread) {
171 
172 	visual_server = p_contained;
173 	create_thread = p_create_thread;
174 	thread = NULL;
175 	draw_mutex = NULL;
176 	draw_pending = 0;
177 	draw_thread_up = false;
178 	alloc_mutex = Mutex::create();
179 	texture_pool_max_size = GLOBAL_DEF("render/thread_textures_prealloc", 5);
180 	mesh_pool_max_size = GLOBAL_DEF("core/rid_pool_prealloc", 20);
181 	if (!p_create_thread) {
182 		server_thread = Thread::get_caller_ID();
183 	} else {
184 		server_thread = 0;
185 	}
186 }
187 
~VisualServerWrapMT()188 VisualServerWrapMT::~VisualServerWrapMT() {
189 
190 	memdelete(visual_server);
191 	memdelete(alloc_mutex);
192 	//finish();
193 }
194