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