1 /*************************************************************************/
2 /*  physics_2d_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 "physics_2d_server_wrap_mt.h"
31 
32 #include "os/os.h"
33 
thread_exit()34 void Physics2DServerWrapMT::thread_exit() {
35 
36 	exit = true;
37 }
38 
thread_step(float p_delta)39 void Physics2DServerWrapMT::thread_step(float p_delta) {
40 
41 	physics_2d_server->step(p_delta);
42 	step_sem->post();
43 }
44 
_thread_callback(void * _instance)45 void Physics2DServerWrapMT::_thread_callback(void *_instance) {
46 
47 	Physics2DServerWrapMT *vsmt = reinterpret_cast<Physics2DServerWrapMT *>(_instance);
48 
49 	vsmt->thread_loop();
50 }
51 
thread_loop()52 void Physics2DServerWrapMT::thread_loop() {
53 
54 	server_thread = Thread::get_caller_ID();
55 
56 	OS::get_singleton()->make_rendering_thread();
57 
58 	physics_2d_server->init();
59 
60 	exit = false;
61 	step_thread_up = true;
62 	while (!exit) {
63 		// flush commands one by one, until exit is requested
64 		command_queue.wait_and_flush_one();
65 	}
66 
67 	command_queue.flush_all(); // flush all
68 
69 	physics_2d_server->finish();
70 }
71 
72 /* EVENT QUEUING */
73 
step(float p_step)74 void Physics2DServerWrapMT::step(float p_step) {
75 
76 	if (create_thread) {
77 
78 		command_queue.push(this, &Physics2DServerWrapMT::thread_step, p_step);
79 	} else {
80 
81 		command_queue.flush_all(); //flush all pending from other threads
82 		physics_2d_server->step(p_step);
83 	}
84 }
85 
sync()86 void Physics2DServerWrapMT::sync() {
87 
88 	if (step_sem) {
89 		if (first_frame)
90 			first_frame = false;
91 		else
92 			step_sem->wait(); //must not wait if a step was not issued
93 	}
94 	physics_2d_server->sync();
95 }
96 
flush_queries()97 void Physics2DServerWrapMT::flush_queries() {
98 
99 	physics_2d_server->flush_queries();
100 }
101 
end_sync()102 void Physics2DServerWrapMT::end_sync() {
103 
104 	physics_2d_server->end_sync();
105 }
106 
init()107 void Physics2DServerWrapMT::init() {
108 
109 	if (create_thread) {
110 
111 		step_sem = Semaphore::create();
112 		print_line("Creating physics 2D thread");
113 		//OS::get_singleton()->release_rendering_thread();
114 		if (create_thread) {
115 			thread = Thread::create(_thread_callback, this);
116 			print_line("Starting physics 2D thread");
117 		}
118 		while (!step_thread_up) {
119 			OS::get_singleton()->delay_usec(1000);
120 		}
121 		print_line("Done physics 2D thread");
122 	} else {
123 
124 		physics_2d_server->init();
125 	}
126 }
127 
finish()128 void Physics2DServerWrapMT::finish() {
129 
130 	if (thread) {
131 
132 		command_queue.push(this, &Physics2DServerWrapMT::thread_exit);
133 		Thread::wait_to_finish(thread);
134 		memdelete(thread);
135 
136 		/*
137 		shape_free_cached_ids();
138 		area_free_cached_ids();
139 		body_free_cached_ids();
140 		pin_joint_free_cached_ids();
141 		groove_joint_free_cached_ids();
142 		damped_string_free_cached_ids();
143 */
144 		thread = NULL;
145 	} else {
146 		physics_2d_server->finish();
147 	}
148 
149 	if (step_sem)
150 		memdelete(step_sem);
151 }
152 
Physics2DServerWrapMT(Physics2DServer * p_contained,bool p_create_thread)153 Physics2DServerWrapMT::Physics2DServerWrapMT(Physics2DServer *p_contained, bool p_create_thread) :
154 		command_queue(p_create_thread) {
155 
156 	physics_2d_server = p_contained;
157 	create_thread = p_create_thread;
158 	thread = NULL;
159 	step_sem = NULL;
160 	step_pending = 0;
161 	step_thread_up = false;
162 	alloc_mutex = Mutex::create();
163 
164 	shape_pool_max_size = GLOBAL_DEF("core/thread_rid_pool_prealloc", 20);
165 	area_pool_max_size = GLOBAL_DEF("core/thread_rid_pool_prealloc", 20);
166 	body_pool_max_size = GLOBAL_DEF("core/thread_rid_pool_prealloc", 20);
167 	pin_joint_pool_max_size = GLOBAL_DEF("core/thread_rid_pool_prealloc", 20);
168 	groove_joint_pool_max_size = GLOBAL_DEF("core/thread_rid_pool_prealloc", 20);
169 	damped_spring_joint_pool_max_size = GLOBAL_DEF("core/thread_rid_pool_prealloc", 20);
170 
171 	if (!p_create_thread) {
172 		server_thread = Thread::get_caller_ID();
173 	} else {
174 		server_thread = 0;
175 	}
176 
177 	main_thread = Thread::get_caller_ID();
178 	first_frame = true;
179 }
180 
~Physics2DServerWrapMT()181 Physics2DServerWrapMT::~Physics2DServerWrapMT() {
182 
183 	memdelete(physics_2d_server);
184 	memdelete(alloc_mutex);
185 	//finish();
186 }
187