diff options
-rw-r--r-- | drivers/SCsub | 1 | ||||
-rw-r--r-- | drivers/rtaudio/audio_driver_rtaudio.cpp | 76 | ||||
-rw-r--r-- | drivers/unix/os_unix.cpp | 4 | ||||
-rw-r--r-- | drivers/unix/thread_posix.cpp | 15 | ||||
-rw-r--r-- | drivers/unix/thread_posix.h | 3 | ||||
-rw-r--r-- | drivers/wasapi/SCsub | 8 | ||||
-rw-r--r-- | drivers/wasapi/audio_driver_wasapi.cpp | 351 | ||||
-rw-r--r-- | drivers/wasapi/audio_driver_wasapi.h | 89 | ||||
-rw-r--r-- | editor/editor_node.cpp | 17 | ||||
-rw-r--r-- | editor/editor_settings.cpp | 1 | ||||
-rw-r--r-- | editor/plugins/polygon_2d_editor_plugin.cpp | 22 | ||||
-rw-r--r-- | main/main.cpp | 7 | ||||
-rw-r--r-- | main/main.h | 3 | ||||
-rw-r--r-- | platform/android/export/export.cpp | 14 | ||||
-rw-r--r-- | platform/android/java_glue.cpp | 4 | ||||
-rw-r--r-- | platform/android/thread_jandroid.cpp | 15 | ||||
-rw-r--r-- | platform/android/thread_jandroid.h | 3 | ||||
-rw-r--r-- | platform/windows/detect.py | 4 | ||||
-rw-r--r-- | platform/windows/os_windows.cpp | 3 | ||||
-rw-r--r-- | platform/windows/os_windows.h | 4 | ||||
-rw-r--r-- | scene/2d/light_2d.cpp | 2 | ||||
-rw-r--r-- | servers/visual/visual_server_canvas.cpp | 14 |
22 files changed, 573 insertions, 87 deletions
diff --git a/drivers/SCsub b/drivers/SCsub index 73a3f7898a..b8bba91378 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -16,6 +16,7 @@ SConscript('alsa/SCsub') SConscript('pulseaudio/SCsub') if (env["platform"] == "windows"): SConscript("rtaudio/SCsub") + SConscript("wasapi/SCsub") if (env["xaudio2"] == "yes"): SConscript("xaudio2/SCsub") diff --git a/drivers/rtaudio/audio_driver_rtaudio.cpp b/drivers/rtaudio/audio_driver_rtaudio.cpp index 8e52b53ad6..7de3ff192e 100644 --- a/drivers/rtaudio/audio_driver_rtaudio.cpp +++ b/drivers/rtaudio/audio_driver_rtaudio.cpp @@ -104,21 +104,14 @@ Error AudioDriverRtAudio::init() { RtAudio::StreamOptions options; // set the desired numberOfBuffers - unsigned int target_number_of_buffers = 4; - options.numberOfBuffers = target_number_of_buffers; - - //options. - //RtAudioStreamFlags flags; /*!< A bit-mask of stream flags (RTAUDIO_NONINTERLEAVED, RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE). */// - //unsigned int numberOfBuffers; /*!< Number of stream buffers. */ - //std::string streamName; /*!< A stream name (currently used only in Jack). */ - //int priority; /*!< Scheduling priority of callback thread (only used with flag RTAUDIO_SCHEDULE_REALTIME). */ + options.numberOfBuffers = 4; parameters.firstChannel = 0; mix_rate = GLOBAL_DEF("audio/mix_rate", 44100); int latency = GLOBAL_DEF("audio/output_latency", 25); - // calculate desired buffer_size, taking the desired numberOfBuffers into account (latency depends on numberOfBuffers*buffer_size) - unsigned int buffer_size = closest_power_of_2(latency * mix_rate / 1000 / target_number_of_buffers); + // calculate desired buffer_size + unsigned int buffer_size = closest_power_of_2(latency * mix_rate / 1000); if (OS::get_singleton()->is_stdout_verbose()) { print_line("audio buffer size: " + itos(buffer_size)); @@ -126,56 +119,28 @@ Error AudioDriverRtAudio::init() { short int tries = 2; - while (true) { - while (true) { - switch (speaker_mode) { - case SPEAKER_MODE_STEREO: parameters.nChannels = 2; break; - case SPEAKER_SURROUND_51: parameters.nChannels = 6; break; - case SPEAKER_SURROUND_71: parameters.nChannels = 8; break; - }; - - try { - dac->openStream(¶meters, NULL, RTAUDIO_SINT32, mix_rate, &buffer_size, &callback, this, &options); - active = true; - - break; - } catch (RtAudioError &e) { - // try with less channels - ERR_PRINT("Unable to open audio, retrying with fewer channels.."); - - switch (speaker_mode) { - case SPEAKER_MODE_STEREO: speaker_mode = SPEAKER_MODE_STEREO; break; - case SPEAKER_SURROUND_51: speaker_mode = SPEAKER_SURROUND_51; break; - case SPEAKER_SURROUND_71: speaker_mode = SPEAKER_SURROUND_71; break; - }; - } - } + while (tries >= 0) { + switch (speaker_mode) { + case SPEAKER_MODE_STEREO: parameters.nChannels = 2; break; + case SPEAKER_SURROUND_51: parameters.nChannels = 6; break; + case SPEAKER_SURROUND_71: parameters.nChannels = 8; break; + }; - // compare actual numberOfBuffers with the desired one. If not equal, close and reopen the stream with adjusted buffer size, so the desired output_latency is still correct - if (target_number_of_buffers != options.numberOfBuffers) { - if (tries <= 0) { - ERR_EXPLAIN("RtAudio: Unable to set correct number of buffers."); - ERR_FAIL_V(ERR_UNAVAILABLE); - break; - } + try { + dac->openStream(¶meters, NULL, RTAUDIO_SINT32, mix_rate, &buffer_size, &callback, this, &options); + active = true; - try { - dac->closeStream(); - active = false; - } catch (RtAudioError &e) { - ERR_PRINT(e.what()); - ERR_FAIL_V(ERR_UNAVAILABLE); - break; + break; + } catch (RtAudioError &e) { + // try with less channels + ERR_PRINT("Unable to open audio, retrying with fewer channels.."); + + switch (speaker_mode) { + case SPEAKER_SURROUND_51: speaker_mode = SPEAKER_MODE_STEREO; break; + case SPEAKER_SURROUND_71: speaker_mode = SPEAKER_SURROUND_51; break; } - if (OS::get_singleton()->is_stdout_verbose()) - print_line("RtAudio: Desired number of buffers (" + itos(target_number_of_buffers) + ") not available. Using " + itos(options.numberOfBuffers) + " instead. Reopening stream with adjusted buffer_size."); - // new buffer size dependent on the ratio between set and actual numberOfBuffers - buffer_size = buffer_size / (options.numberOfBuffers / target_number_of_buffers); - target_number_of_buffers = options.numberOfBuffers; tries--; - } else { - break; } } @@ -231,6 +196,7 @@ void AudioDriverRtAudio::finish() { AudioDriverRtAudio::AudioDriverRtAudio() { + active = false; mutex = NULL; dac = NULL; mix_rate = 44100; diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 992b12b7cd..75c8a153f6 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -315,7 +315,9 @@ OS::TimeZoneInfo OS_Unix::get_time_zone_info() const { void OS_Unix::delay_usec(uint32_t p_usec) const { - usleep(p_usec); + struct timespec rem = { p_usec / 1000000, (p_usec % 1000000) * 1000 }; + while (nanosleep(&rem, &rem) == EINTR) { + } } uint64_t OS_Unix::get_ticks_usec() const { diff --git a/drivers/unix/thread_posix.cpp b/drivers/unix/thread_posix.cpp index 2dd0b4a70a..5908246929 100644 --- a/drivers/unix/thread_posix.cpp +++ b/drivers/unix/thread_posix.cpp @@ -36,8 +36,18 @@ #include <pthread_np.h> #endif +#include "core/safe_refcount.h" #include "os/memory.h" +static pthread_key_t _create_thread_id_key() { + pthread_key_t key; + pthread_key_create(&key, NULL); + return key; +} + +pthread_key_t ThreadPosix::thread_id_key = _create_thread_id_key(); +Thread::ID ThreadPosix::next_thread_id = 0; + Thread::ID ThreadPosix::get_id() const { return id; @@ -51,7 +61,8 @@ Thread *ThreadPosix::create_thread_posix() { void *ThreadPosix::thread_callback(void *userdata) { ThreadPosix *t = reinterpret_cast<ThreadPosix *>(userdata); - t->id = (ID)pthread_self(); + t->id = atomic_increment(&next_thread_id); + pthread_setspecific(thread_id_key, (void *)t->id); ScriptServer::thread_enter(); //scripts may need to attach a stack @@ -77,7 +88,7 @@ Thread *ThreadPosix::create_func_posix(ThreadCreateCallback p_callback, void *p_ } Thread::ID ThreadPosix::get_thread_id_func_posix() { - return (ID)pthread_self(); + return (ID)pthread_getspecific(thread_id_key); } void ThreadPosix::wait_to_finish_func_posix(Thread *p_thread) { diff --git a/drivers/unix/thread_posix.h b/drivers/unix/thread_posix.h index a188d9c346..d6a41ed119 100644 --- a/drivers/unix/thread_posix.h +++ b/drivers/unix/thread_posix.h @@ -42,6 +42,9 @@ class ThreadPosix : public Thread { + static pthread_key_t thread_id_key; + static ID next_thread_id; + pthread_t pthread; pthread_attr_t pthread_attr; ThreadCreateCallback callback; diff --git a/drivers/wasapi/SCsub b/drivers/wasapi/SCsub new file mode 100644 index 0000000000..233593b0f9 --- /dev/null +++ b/drivers/wasapi/SCsub @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +Import('env') + +# Driver source files +env.add_source_files(env.drivers_sources, "*.cpp") + +Export('env') diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp new file mode 100644 index 0000000000..6e01b5f524 --- /dev/null +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -0,0 +1,351 @@ +/*************************************************************************/ +/* audio_driver_wasapi.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifdef WASAPI_ENABLED + +#include "audio_driver_wasapi.h" + +#include "os/os.h" +#include "project_settings.h" + +const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator); +const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); +const IID IID_IAudioClient = __uuidof(IAudioClient); +const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); + +Error AudioDriverWASAPI::init_device() { + + WAVEFORMATEX *pwfex; + IMMDeviceEnumerator *enumerator = NULL; + IMMDevice *device = NULL; + + CoInitialize(NULL); + + HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator); + ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + + hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device); + ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + + hr = device->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&audio_client); + ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + + hr = audio_client->GetMixFormat(&pwfex); + ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + + // Since we're using WASAPI Shared Mode we can't control any of these, we just tag along + channels = pwfex->nChannels; + mix_rate = pwfex->nSamplesPerSec; + format_tag = pwfex->wFormatTag; + bits_per_sample = pwfex->wBitsPerSample; + + if (format_tag == WAVE_FORMAT_EXTENSIBLE) { + WAVEFORMATEXTENSIBLE *wfex = (WAVEFORMATEXTENSIBLE *)pwfex; + + if (wfex->SubFormat == KSDATAFORMAT_SUBTYPE_PCM) { + format_tag = WAVE_FORMAT_PCM; + } else if (wfex->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) { + format_tag = WAVE_FORMAT_IEEE_FLOAT; + } else { + ERR_PRINT("WASAPI: Format not supported"); + ERR_FAIL_V(ERR_CANT_OPEN); + } + } else { + if (format_tag != WAVE_FORMAT_PCM && format_tag != WAVE_FORMAT_IEEE_FLOAT) { + ERR_PRINT("WASAPI: Format not supported"); + ERR_FAIL_V(ERR_CANT_OPEN); + } + } + + int latency = GLOBAL_DEF("audio/output_latency", 25); + buffer_size = closest_power_of_2(latency * mix_rate / 1000); + + if (OS::get_singleton()->is_stdout_verbose()) { + print_line("audio buffer size: " + itos(buffer_size)); + } + + hr = audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 0, 0, pwfex, NULL); + ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + + event = CreateEvent(NULL, FALSE, FALSE, NULL); + ERR_FAIL_COND_V(event == NULL, ERR_CANT_OPEN); + + hr = audio_client->SetEventHandle(event); + ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + + hr = audio_client->GetService(IID_IAudioRenderClient, (void **)&render_client); + ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + + hr = audio_client->GetBufferSize(&max_frames); + ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + + samples_in.resize(buffer_size); + buffer_frames = buffer_size / channels; + + return OK; +} + +Error AudioDriverWASAPI::finish_device() { + + if (audio_client) { + if (active) { + audio_client->Stop(); + active = false; + } + } + + if (render_client) { + render_client->Release(); + render_client = NULL; + } + + if (audio_client) { + audio_client->Release(); + audio_client = NULL; + } + + return OK; +} + +Error AudioDriverWASAPI::init() { + + Error err = init_device(); + ERR_FAIL_COND_V(err != OK, err); + + active = false; + exit_thread = false; + thread_exited = false; + + mutex = Mutex::create(true); + thread = Thread::create(thread_func, this); + + return OK; +} + +Error AudioDriverWASAPI::reopen() { + Error err = finish_device(); + if (err != OK) { + ERR_PRINT("WASAPI: finish_device error"); + } else { + err = init_device(); + if (err != OK) { + ERR_PRINT("WASAPI: init_device error"); + } else { + start(); + } + } + + return err; +} + +int AudioDriverWASAPI::get_mix_rate() const { + + return mix_rate; +} + +AudioDriver::SpeakerMode AudioDriverWASAPI::get_speaker_mode() const { + + return SPEAKER_MODE_STEREO; +} + +void AudioDriverWASAPI::thread_func(void *p_udata) { + + AudioDriverWASAPI *ad = (AudioDriverWASAPI *)p_udata; + + while (!ad->exit_thread) { + if (ad->active) { + ad->lock(); + + ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptr()); + + ad->unlock(); + } else { + for (unsigned int i = 0; i < ad->buffer_size; i++) { + ad->samples_in[i] = 0; + } + } + + unsigned int left_frames = ad->buffer_frames; + unsigned int buffer_idx = 0; + while (left_frames > 0) { + WaitForSingleObject(ad->event, 1000); + + UINT32 cur_frames; + HRESULT hr = ad->audio_client->GetCurrentPadding(&cur_frames); + if (hr == S_OK) { + // Check how much frames are available on the WASAPI buffer + UINT32 avail_frames = ad->max_frames - cur_frames; + UINT32 write_frames = avail_frames > left_frames ? left_frames : avail_frames; + + BYTE *buffer = NULL; + hr = ad->render_client->GetBuffer(write_frames, &buffer); + if (hr == S_OK) { + // We're using WASAPI Shared Mode so we must convert the buffer + + if (ad->format_tag == WAVE_FORMAT_PCM) { + switch (ad->bits_per_sample) { + case 8: + for (unsigned int i = 0; i < write_frames * ad->channels; i++) { + ((int8_t *)buffer)[i] = ad->samples_in[buffer_idx++] >> 24; + } + break; + + case 16: + for (unsigned int i = 0; i < write_frames * ad->channels; i++) { + ((int16_t *)buffer)[i] = ad->samples_in[buffer_idx++] >> 16; + } + break; + + case 24: + for (unsigned int i = 0; i < write_frames * ad->channels; i++) { + int32_t sample = ad->samples_in[buffer_idx++]; + ((int8_t *)buffer)[i * 3 + 2] = sample >> 24; + ((int8_t *)buffer)[i * 3 + 1] = sample >> 16; + ((int8_t *)buffer)[i * 3 + 0] = sample >> 8; + } + break; + + case 32: + for (unsigned int i = 0; i < write_frames * ad->channels; i++) { + ((int32_t *)buffer)[i] = ad->samples_in[buffer_idx++]; + } + break; + } + } else if (ad->format_tag == WAVE_FORMAT_IEEE_FLOAT) { + for (unsigned int i = 0; i < write_frames * ad->channels; i++) { + ((float *)buffer)[i] = (ad->samples_in[buffer_idx++] >> 16) / 32768.f; + } + } else { + ERR_PRINT("WASAPI: Unknown format tag"); + ad->exit_thread = true; + } + + hr = ad->render_client->ReleaseBuffer(write_frames, 0); + if (hr != S_OK) { + ERR_PRINT("WASAPI: Release buffer error"); + } + + left_frames -= write_frames; + } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) { + // Device is not valid anymore, reopen it + + Error err = ad->reopen(); + if (err != OK) { + ad->exit_thread = true; + } else { + // We reopened the device and samples_in may have resized, so invalidate the current left_frames + left_frames = 0; + } + } else { + ERR_PRINT("WASAPI: Get buffer error"); + ad->exit_thread = true; + } + } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) { + // Device is not valid anymore, reopen it + + Error err = ad->reopen(); + if (err != OK) { + ad->exit_thread = true; + } else { + // We reopened the device and samples_in may have resized, so invalidate the current left_frames + left_frames = 0; + } + } else { + ERR_PRINT("WASAPI: GetCurrentPadding error"); + } + } + } + + ad->thread_exited = true; +} + +void AudioDriverWASAPI::start() { + + HRESULT hr = audio_client->Start(); + if (hr != S_OK) { + ERR_PRINT("WASAPI: Start failed"); + } else { + active = true; + } +} + +void AudioDriverWASAPI::lock() { + + if (mutex) + mutex->lock(); +} + +void AudioDriverWASAPI::unlock() { + + if (mutex) + mutex->unlock(); +} + +void AudioDriverWASAPI::finish() { + + if (thread) { + exit_thread = true; + Thread::wait_to_finish(thread); + + memdelete(thread); + thread = NULL; + } + + finish_device(); + + if (mutex) { + memdelete(mutex); + mutex = NULL; + } +} + +AudioDriverWASAPI::AudioDriverWASAPI() { + + audio_client = NULL; + render_client = NULL; + mutex = NULL; + thread = NULL; + + max_frames = 0; + format_tag = 0; + bits_per_sample = 0; + + samples_in.clear(); + + buffer_size = 0; + channels = 0; + mix_rate = 0; + buffer_frames = 0; + + thread_exited = false; + exit_thread = false; + active = false; +} + +#endif diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h new file mode 100644 index 0000000000..b91751f87e --- /dev/null +++ b/drivers/wasapi/audio_driver_wasapi.h @@ -0,0 +1,89 @@ +/*************************************************************************/ +/* audio_driver_wasapi.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef AUDIO_DRIVER_WASAPI_H +#define AUDIO_DRIVER_WASAPI_H + +#ifdef WASAPI_ENABLED + +#include "core/os/mutex.h" +#include "core/os/thread.h" +#include "servers/audio_server.h" + +#include <audioclient.h> +#include <mmdeviceapi.h> +#include <windows.h> + +class AudioDriverWASAPI : public AudioDriver { + + HANDLE event; + IAudioClient *audio_client; + IAudioRenderClient *render_client; + Mutex *mutex; + Thread *thread; + + UINT32 max_frames; + WORD format_tag; + WORD bits_per_sample; + + Vector<int32_t> samples_in; + + unsigned int buffer_size; + unsigned int channels; + int mix_rate; + int buffer_frames; + + bool thread_exited; + mutable bool exit_thread; + bool active; + + static void thread_func(void *p_udata); + + Error init_device(); + Error finish_device(); + Error reopen(); + +public: + virtual const char *get_name() const { + return "WASAPI"; + } + + virtual Error init(); + virtual void start(); + virtual int get_mix_rate() const; + virtual SpeakerMode get_speaker_mode() const; + virtual void lock(); + virtual void unlock(); + virtual void finish(); + + AudioDriverWASAPI(); +}; + +#endif // AUDIO_DRIVER_WASAPI_H +#endif diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index c376efca34..a8edeca931 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -908,8 +908,10 @@ void EditorNode::_save_all_scenes() { for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { Node *scene = editor_data.get_edited_scene_root(i); if (scene && scene->get_filename() != "") { - // save in background if in the script editor - _save_scene_with_preview(scene->get_filename()); + if (i != editor_data.get_edited_scene()) + _save_scene(scene->get_filename(), i); + else + _save_scene_with_preview(scene->get_filename()); } // else: ignore new scenes } @@ -983,7 +985,10 @@ void EditorNode::_dialog_action(String p_file) { if (file->get_mode() == EditorFileDialog::MODE_SAVE_FILE) { _save_default_environment(); - _save_scene_with_preview(p_file); + if (scene_idx != editor_data.get_edited_scene()) + _save_scene(p_file, scene_idx); + else + _save_scene_with_preview(p_file); if (scene_idx != -1) _discard_changes(); @@ -1660,8 +1665,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { Node *scene = editor_data.get_edited_scene_root(scene_idx); if (scene && scene->get_filename() != "") { - // save in background if in the script editor - _save_scene_with_preview(scene->get_filename()); + if (scene_idx != editor_data.get_edited_scene()) + _save_scene(scene->get_filename(), scene_idx); + else + _save_scene_with_preview(scene->get_filename()); if (scene_idx != -1) _discard_changes(); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index b9a6414b08..6398bd1623 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -694,6 +694,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { set("editors/2d/pan_speed", 20); set("editors/poly_editor/point_grab_radius", 8); + set("editors/poly_editor/show_previous_outline", true); set("run/window_placement/rect", 1); hints["run/window_placement/rect"] = PropertyInfo(Variant::INT, "run/window_placement/rect", PROPERTY_HINT_ENUM, "Top Left,Centered,Custom Position,Force Maximized,Force Fullscreen"); diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 88158d4b20..d04184f055 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -402,6 +402,11 @@ bool Polygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { cpoint = canvas_item_editor->snap_point(cpoint); edited_point_pos = node->get_global_transform().affine_inverse().xform(cpoint); + Vector<Vector2> poly = Variant(node->get_polygon()); + ERR_FAIL_INDEX_V(edited_point, poly.size(), false); + poly[edited_point] = edited_point_pos - node->get_offset(); + node->set_polygon(Variant(poly)); + canvas_item_editor->get_viewport_control()->update(); } } @@ -425,6 +430,23 @@ void Polygon2DEditor::_canvas_draw() { Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons"); + if (edited_point >= 0 && EDITOR_DEF("editors/poly_editor/show_previous_outline", true)) { + + const Color col = node->get_color().contrasted(); + const int n = pre_move_edit.size(); + for (int i = 0; i < n; i++) { + + Vector2 p, p2; + p = pre_move_edit[i] + node->get_offset(); + p2 = pre_move_edit[(i + 1) % n] + node->get_offset(); + + Vector2 point = xform.xform(p); + Vector2 next_point = xform.xform(p2); + + vpc->draw_line(point, next_point, col, 2); + } + } + for (int i = 0; i < poly.size(); i++) { Vector2 p, p2; diff --git a/main/main.cpp b/main/main.cpp index 00cb43b0a8..532b5277b5 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -69,7 +69,6 @@ #include "core/io/file_access_zip.h" #include "core/io/stream_peer_ssl.h" #include "core/io/stream_peer_tcp.h" -#include "core/os/thread.h" #include "main/input_default.h" #include "performance.h" #include "translation.h" @@ -886,7 +885,11 @@ error: return ERR_INVALID_PARAMETER; } -Error Main::setup2() { +Error Main::setup2(Thread::ID p_main_tid_override) { + + if (p_main_tid_override) { + Thread::_main_thread_id = p_main_tid_override; + } OS::get_singleton()->initialize(video_mode, video_driver_idx, audio_driver_idx); if (init_use_custom_pos) { diff --git a/main/main.h b/main/main.h index f8db0225bf..2c1d42a163 100644 --- a/main/main.h +++ b/main/main.h @@ -34,6 +34,7 @@ @author Juan Linietsky <reduzio@gmail.com> */ +#include "core/os/thread.h" #include "error_list.h" #include "typedefs.h" @@ -49,7 +50,7 @@ class Main { public: static Error setup(const char *execpath, int argc, char *argv[], bool p_second_phase = true); - static Error setup2(); + static Error setup2(Thread::ID p_main_tid_override = 0); static bool start(); static bool iteration(); static void cleanup(); diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index eff3a7178d..8b3a64bbe6 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -1073,11 +1073,7 @@ public: //export_temp ep.step("Exporting APK", 0); - bool use_adb_over_usb = bool(EDITOR_DEF("export/android/use_remote_debug_over_adb", true)); - - if (use_adb_over_usb) { - p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST; - } + p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST; String export_to = EditorSettings::get_singleton()->get_settings_path() + "/tmp/tmpexport.apk"; Error err = export_project(p_preset, true, export_to, p_debug_flags); @@ -1123,7 +1119,7 @@ public: return ERR_CANT_CREATE; } - if (use_adb_over_usb) { + if (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) { args.clear(); args.push_back("-s"); @@ -1142,6 +1138,9 @@ public: OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv); print_line("Reverse result: " + itos(rv)); + } + + if (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT) { int fs_port = EditorSettings::get_singleton()->get("filesystem/file_server/port"); @@ -1294,7 +1293,7 @@ public: bool export_arm = p_preset->get("architecture/arm"); bool export_arm64 = p_preset->get("architecture/arm64"); - bool use_32_fb = p_preset->get("screen/use_32_bits_view"); + bool use_32_fb = p_preset->get("graphics/32_bits_framebuffer"); bool immersive = p_preset->get("screen/immersive_mode"); bool _signed = p_preset->get("package/signed"); @@ -1724,7 +1723,6 @@ void register_android_exporter() { EDITOR_DEF("export/android/force_system_user", false); EDITOR_DEF("export/android/timestamping_authority_url", ""); - EDITOR_DEF("export/android/use_remote_debug_over_adb", false); EDITOR_DEF("export/android/shutdown_adb_on_exit", true); Ref<EditorExportAndroid> exporter = Ref<EditorExportAndroid>(memnew(EditorExportAndroid)); diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp index 9abaae0a75..06abe9d751 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -1002,7 +1002,9 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, job ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("JavaClassWrapper", java_class_wrapper)); _initialize_java_modules(); - Main::setup2(); + // Since Godot is initialized on the UI thread, _main_thread_id was set to that thread's id, + // but for Godot purposes, the main thread is the one running the game loop + Main::setup2(Thread::get_caller_id()); ++step; suspend_mutex->unlock(); input_mutex->unlock(); diff --git a/platform/android/thread_jandroid.cpp b/platform/android/thread_jandroid.cpp index 9e2e5452ca..79488197ea 100644 --- a/platform/android/thread_jandroid.cpp +++ b/platform/android/thread_jandroid.cpp @@ -29,9 +29,19 @@ /*************************************************************************/ #include "thread_jandroid.h" +#include "core/safe_refcount.h" #include "os/memory.h" #include "script_language.h" +static pthread_key_t _create_thread_id_key() { + pthread_key_t key; + pthread_key_create(&key, NULL); + return key; +} + +pthread_key_t ThreadAndroid::thread_id_key = _create_thread_id_key(); +Thread::ID ThreadAndroid::next_thread_id = 0; + Thread::ID ThreadAndroid::get_id() const { return id; @@ -47,7 +57,8 @@ void *ThreadAndroid::thread_callback(void *userdata) { ThreadAndroid *t = reinterpret_cast<ThreadAndroid *>(userdata); setup_thread(); ScriptServer::thread_enter(); //scripts may need to attach a stack - t->id = (ID)pthread_self(); + t->id = atomic_increment(&next_thread_id); + pthread_setspecific(thread_id_key, (void *)t->id); t->callback(t->user); ScriptServer::thread_exit(); return NULL; @@ -68,7 +79,7 @@ Thread *ThreadAndroid::create_func_jandroid(ThreadCreateCallback p_callback, voi Thread::ID ThreadAndroid::get_thread_id_func_jandroid() { - return (ID)pthread_self(); + return (ID)pthread_getspecific(thread_id_key); } void ThreadAndroid::wait_to_finish_func_jandroid(Thread *p_thread) { diff --git a/platform/android/thread_jandroid.h b/platform/android/thread_jandroid.h index bacc1ce435..b854a83e23 100644 --- a/platform/android/thread_jandroid.h +++ b/platform/android/thread_jandroid.h @@ -41,6 +41,9 @@ class ThreadAndroid : public Thread { + static pthread_key_t thread_id_key; + static ID next_thread_id; + pthread_t pthread; pthread_attr_t pthread_attr; ThreadCreateCallback callback; diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 882e1a808e..d239ccf7d2 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -171,6 +171,7 @@ def configure(env): env.Append(CCFLAGS=['/DWINDOWS_ENABLED']) env.Append(CCFLAGS=['/DOPENGL_ENABLED']) env.Append(CCFLAGS=['/DRTAUDIO_ENABLED']) + env.Append(CCFLAGS=['/DWASAPI_ENABLED']) env.Append(CCFLAGS=['/DTYPED_METHOD_BIND']) env.Append(CCFLAGS=['/DWIN32']) env.Append(CCFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver]) @@ -252,8 +253,9 @@ def configure(env): env.Append(CCFLAGS=['-DWINDOWS_ENABLED', '-mwindows']) env.Append(CCFLAGS=['-DOPENGL_ENABLED']) env.Append(CCFLAGS=['-DRTAUDIO_ENABLED']) + env.Append(CCFLAGS=['-DWASAPI_ENABLED']) env.Append(CCFLAGS=['-DWINVER=%s' % winver, '-D_WIN32_WINNT=%s' % winver]) - env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid']) + env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid', 'ksuser']) env.Append(CPPFLAGS=['-DMINGW_ENABLED']) diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 7b12482383..deb9c25576 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -2359,6 +2359,9 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) { #endif user_proc = NULL; +#ifdef WASAPI_ENABLED + AudioDriverManager::add_driver(&driver_wasapi); +#endif #ifdef RTAUDIO_ENABLED AudioDriverManager::add_driver(&driver_rtaudio); #endif diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 01d904a4cc..0c5965bf51 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -32,6 +32,7 @@ #include "context_gl_win.h" #include "drivers/rtaudio/audio_driver_rtaudio.h" +#include "drivers/wasapi/audio_driver_wasapi.h" #include "os/input.h" #include "os/os.h" #include "power_windows.h" @@ -123,6 +124,9 @@ class OS_Windows : public OS { PowerWindows *power_manager; +#ifdef WASAPI_ENABLED + AudioDriverWASAPI driver_wasapi; +#endif #ifdef RTAUDIO_ENABLED AudioDriverRtAudio driver_rtaudio; #endif diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index 4abb51ef7c..ab8277ecf3 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -434,7 +434,7 @@ void Light2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_enabled"), "set_shadow_enabled", "is_shadow_enabled"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color"); ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_buffer_size", PROPERTY_HINT_RANGE, "32,16384,1"), "set_shadow_buffer_size", "get_shadow_buffer_size"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "shadow_gradient_length", PROPERTY_HINT_RANGE, "1,4096,0.1"), "set_shadow_gradient_length", "get_shadow_gradient_length"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "shadow_gradient_length", PROPERTY_HINT_RANGE, "0,4096,0.1"), "set_shadow_gradient_length", "get_shadow_gradient_length"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "shadow_filter", PROPERTY_HINT_ENUM, "None,PCF3,PCF5,PCF9,PCF13"), "set_shadow_filter", "get_shadow_filter"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "shadow_filter_smooth", PROPERTY_HINT_RANGE, "0,64,0.1"), "set_shadow_smooth", "get_shadow_smooth"); ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_item_cull_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_item_shadow_cull_mask", "get_item_shadow_cull_mask"); diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index ad6d0f6b2b..25724981eb 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -37,10 +37,8 @@ void VisualServerCanvas::_render_canvas_item_tree(Item *p_canvas_item, const Tra RasterizerCanvas::Item *z_list[z_range]; RasterizerCanvas::Item *z_last_list[z_range]; - for (int i = 0; i < z_range; i++) { - z_list[i] = NULL; - z_last_list[i] = NULL; - } + memset(z_list, 0, z_range * sizeof(RasterizerCanvas::Item *)); + memset(z_last_list, 0, z_range * sizeof(RasterizerCanvas::Item *)); _render_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, NULL, NULL); @@ -200,10 +198,9 @@ void VisualServerCanvas::render_canvas(Canvas *p_canvas, const Transform2D &p_tr RasterizerCanvas::Item *z_list[z_range]; RasterizerCanvas::Item *z_last_list[z_range]; - for (int i = 0; i < z_range; i++) { - z_list[i] = NULL; - z_last_list[i] = NULL; - } + memset(z_list, 0, z_range * sizeof(RasterizerCanvas::Item *)); + memset(z_last_list, 0, z_range * sizeof(RasterizerCanvas::Item *)); + for (int i = 0; i < l; i++) { _render_canvas_item(ci[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, NULL, NULL); } @@ -701,6 +698,7 @@ void VisualServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vector polygon->colors = p_colors; polygon->indices = indices; polygon->count = count; + polygon->antialiased = false; canvas_item->rect_dirty = true; canvas_item->commands.push_back(polygon); |