summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/SCsub1
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp2
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h8
-rw-r--r--drivers/gles3/shader_compiler_gles3.cpp4
-rw-r--r--drivers/gles3/shaders/SCsub2
-rw-r--r--drivers/gles3/shaders/scene.glsl12
-rw-r--r--drivers/gles3/shaders/ssao_blur.glsl7
-rw-r--r--drivers/rtaudio/audio_driver_rtaudio.cpp76
-rw-r--r--drivers/unix/SCsub2
-rw-r--r--drivers/unix/os_unix.cpp4
-rw-r--r--drivers/unix/thread_posix.cpp15
-rw-r--r--drivers/unix/thread_posix.h3
-rw-r--r--drivers/wasapi/SCsub8
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp351
-rw-r--r--drivers/wasapi/audio_driver_wasapi.h89
15 files changed, 505 insertions, 79 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/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 9c7a1dd859..f4dd9682a1 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -3259,6 +3259,8 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_
state.ssao_blur_shader.set_uniform(SsaoBlurShaderGLES3::CAMERA_Z_NEAR, p_cam_projection.get_z_near());
GLint axis[2] = { i, 1 - i };
glUniform2iv(state.ssao_blur_shader.get_uniform(SsaoBlurShaderGLES3::AXIS), 1, axis);
+ glUniform2iv(state.ssao_blur_shader.get_uniform(SsaoBlurShaderGLES3::SCREEN_SIZE), 1, ss);
+
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.ssao.blur_red[i]);
glActiveTexture(GL_TEXTURE1);
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index 1ab2afe664..659408b455 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -108,7 +108,7 @@ public:
TonemapShaderGLES3 tonemap_shader;
struct SceneDataUBO {
-
+ //this is a std140 compatible struct. Please read the OpenGL 3.3 Specificaiton spec before doing any changes
float projection_matrix[16];
float camera_inverse_matrix[16];
float camera_matrix[16];
@@ -133,12 +133,12 @@ public:
float subsurface_scatter_width;
float ambient_occlusion_affect_light;
- bool fog_depth_enabled;
+ uint32_t fog_depth_enabled;
float fog_depth_begin;
float fog_depth_curve;
- bool fog_transmit_enabled;
+ uint32_t fog_transmit_enabled;
float fog_transmit_curve;
- bool fog_height_enabled;
+ uint32_t fog_height_enabled;
float fog_height_min;
float fog_height_max;
float fog_height_curve;
diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp
index d793ea446d..c308e9eddb 100644
--- a/drivers/gles3/shader_compiler_gles3.cpp
+++ b/drivers/gles3/shader_compiler_gles3.cpp
@@ -608,6 +608,9 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
} else {
code = "return;";
}
+ } else if (cfnode->flow_op == SL::FLOW_OP_DISCARD) {
+
+ code = "discard;";
}
} break;
@@ -752,7 +755,6 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength";
actions[VS::SHADER_SPATIAL].renames["AO"] = "ao";
actions[VS::SHADER_SPATIAL].renames["EMISSION"] = "emission";
- actions[VS::SHADER_SPATIAL].renames["DISCARD"] = "_discard";
//actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"]=ShaderLanguage::TYPE_VEC2;
actions[VS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord";
actions[VS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom";
diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub
index 0c69c8cf74..f1811fa7b5 100644
--- a/drivers/gles3/shaders/SCsub
+++ b/drivers/gles3/shaders/SCsub
@@ -2,7 +2,7 @@
Import('env')
-if env['BUILDERS'].has_key('GLES3_GLSL'):
+if 'GLES3_GLSL' in env['BUILDERS']:
env.GLES3_GLSL('copy.glsl');
env.GLES3_GLSL('resolve.glsl');
env.GLES3_GLSL('canvas.glsl');
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index c9e9dacdb5..ef4925895c 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -1559,10 +1559,6 @@ void main() {
vec2 screen_uv = gl_FragCoord.xy*screen_pixel_size;
#endif
-#if defined(ENABLE_DISCARD)
- bool discard_=false;
-#endif
-
#if defined (ENABLE_SSS)
float sss_strength=0.0;
#endif
@@ -1603,13 +1599,6 @@ FRAGMENT_SHADER_CODE
#endif
-#if defined(ENABLE_DISCARD)
- if (discard_) {
- //easy to eliminate dead code
- discard;
- }
-#endif
-
#ifdef ENABLE_CLIP_ALPHA
if (albedo.a<0.99) {
//used for doublepass and shadowmapping
@@ -1971,7 +1960,6 @@ FRAGMENT_SHADER_CODE
#ifdef SHADELESS
- frag_color=vec4(albedo,alpha);
diffuse_buffer=vec4(albedo.rgb,0.0);
specular_buffer=vec4(0.0);
diff --git a/drivers/gles3/shaders/ssao_blur.glsl b/drivers/gles3/shaders/ssao_blur.glsl
index ce4154f50c..c7c978dc37 100644
--- a/drivers/gles3/shaders/ssao_blur.glsl
+++ b/drivers/gles3/shaders/ssao_blur.glsl
@@ -56,6 +56,8 @@ uniform ivec2 axis;
uniform float camera_z_far;
uniform float camera_z_near;
+uniform ivec2 screen_size;
+
void main() {
ivec2 ssC = ivec2(gl_FragCoord.xy);
@@ -83,6 +85,7 @@ void main() {
float totalWeight = BASE;
sum *= totalWeight;
+ ivec2 clamp_limit = screen_size - ivec2(1);
for (int r = -R; r <= R; ++r) {
// We already handled the zero case above. This loop should be unrolled and the static branch optimized out,
@@ -90,8 +93,8 @@ void main() {
if (r != 0) {
ivec2 ppos = ssC + axis * (r * SCALE);
- float value = texelFetch(source_ssao, ppos, 0).r;
- float temp_depth = texelFetch(source_depth, ssC, 0).r;
+ float value = texelFetch(source_ssao, clamp(ppos,ivec2(0),clamp_limit), 0).r;
+ float temp_depth = texelFetch(source_depth, clamp(ssC,ivec2(0),clamp_limit), 0).r;
temp_depth = temp_depth * 2.0 - 1.0;
temp_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - temp_depth * (camera_z_far - camera_z_near));
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(&parameters, 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(&parameters, 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/SCsub b/drivers/unix/SCsub
index 96efc91b7a..5ced44dfda 100644
--- a/drivers/unix/SCsub
+++ b/drivers/unix/SCsub
@@ -8,7 +8,7 @@ g_set_p += 'String OS_Unix::get_global_settings_path() const {\n'
g_set_p += '\treturn "' + env["unix_global_settings_path"] + '";\n'
g_set_p += '}\n'
g_set_p += '#endif'
-f = open("os_unix_global_settings_path.gen.cpp", "wb")
+f = open("os_unix_global_settings_path.gen.cpp", "w")
f.write(g_set_p)
f.close()
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