diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gles3/rasterizer_scene_gles3.cpp | 69 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_storage_gles3.cpp | 57 | ||||
-rw-r--r-- | drivers/gles3/shader_compiler_gles3.cpp | 64 | ||||
-rw-r--r-- | drivers/gles3/shaders/canvas.glsl | 2 | ||||
-rw-r--r-- | drivers/gles3/shaders/copy.glsl | 4 | ||||
-rw-r--r-- | drivers/unix/file_access_unix.cpp | 5 | ||||
-rw-r--r-- | drivers/unix/file_access_unix.h | 1 | ||||
-rw-r--r-- | drivers/unix/stream_peer_tcp_posix.cpp | 2 | ||||
-rw-r--r-- | drivers/unix/stream_peer_tcp_posix.h | 2 | ||||
-rw-r--r-- | drivers/wasapi/audio_driver_wasapi.cpp | 88 | ||||
-rw-r--r-- | drivers/windows/file_access_windows.cpp | 47 | ||||
-rw-r--r-- | drivers/windows/file_access_windows.h | 1 | ||||
-rw-r--r-- | drivers/windows/stream_peer_tcp_winsock.cpp | 2 | ||||
-rw-r--r-- | drivers/windows/stream_peer_tcp_winsock.h | 2 |
14 files changed, 281 insertions, 65 deletions
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index da6df7198d..7c053e8f60 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -4234,17 +4234,14 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const clear_color = env->bg_color.to_linear(); storage->frame.clear_request = false; - } else if (env->bg_mode == VS::ENV_BG_SKY || env->bg_mode == VS::ENV_BG_COLOR_SKY) { + } else if (env->bg_mode == VS::ENV_BG_SKY) { - sky = storage->sky_owner.getornull(env->sky); + storage->frame.clear_request = false; - if (sky) { - env_radiance_tex = sky->radiance; - } + } else if (env->bg_mode == VS::ENV_BG_COLOR_SKY) { + + clear_color = env->bg_color.to_linear(); storage->frame.clear_request = false; - if (env->bg_mode == VS::ENV_BG_COLOR_SKY) { - clear_color = env->bg_color.to_linear(); - } } else { storage->frame.clear_request = false; @@ -4254,34 +4251,48 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const glClearBufferfv(GL_COLOR, 0, clear_color.components); // specular } - if (env && env->bg_mode == VS::ENV_BG_CANVAS) { - //copy canvas to 3d buffer and convert it to linear + if (env) { + switch (env->bg_mode) { + case VS::ENV_BG_COLOR_SKY: + + case VS::ENV_BG_SKY: - glDisable(GL_BLEND); - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); + sky = storage->sky_owner.getornull(env->sky); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); + if (sky) { + env_radiance_tex = sky->radiance; + } + break; + case VS::ENV_BG_CANVAS: + //copy canvas to 3d buffer and convert it to linear - storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, true); + glDisable(GL_BLEND); + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); - storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, true); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); - storage->shaders.copy.bind(); + storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, true); - _copy_screen(true, true); + storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, true); - //turn off everything used - storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, false); - storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false); + storage->shaders.copy.bind(); - //restore - glEnable(GL_BLEND); - glDepthMask(GL_TRUE); - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); + _copy_screen(true, true); + + //turn off everything used + storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, false); + storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false); + + //restore + glEnable(GL_BLEND); + glDepthMask(GL_TRUE); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + break; + } } state.texscreen_copied = false; @@ -4916,7 +4927,6 @@ void RasterizerSceneGLES3::initialize() { const int ubo_light_size = 160; state.ubo_light_size = ubo_light_size; state.max_ubo_lights = MIN(RenderList::MAX_LIGHTS, max_ubo_size / ubo_light_size); - print_line("GLES3: max ubo light: " + itos(state.max_ubo_lights)); state.spot_array_tmp = (uint8_t *)memalloc(ubo_light_size * state.max_ubo_lights); state.omni_array_tmp = (uint8_t *)memalloc(ubo_light_size * state.max_ubo_lights); @@ -4942,7 +4952,6 @@ void RasterizerSceneGLES3::initialize() { state.scene_shader.add_custom_define("#define MAX_FORWARD_LIGHTS " + itos(state.max_forward_lights_per_object) + "\n"); state.max_ubo_reflections = MIN(RenderList::MAX_REFLECTIONS, max_ubo_size / sizeof(ReflectionProbeDataUBO)); - print_line("GLES3: max ubo reflections: " + itos(state.max_ubo_reflections) + ", ubo size: " + itos(sizeof(ReflectionProbeDataUBO))); state.reflection_array_tmp = (uint8_t *)memalloc(sizeof(ReflectionProbeDataUBO) * state.max_ubo_reflections); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 3255726c1f..0fc095a868 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -876,11 +876,34 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, VS::CubeMapSi } } + Image::Format img_format; + + //convert special case RGB10_A2 to RGBA8 because it's not a supported image format + if (texture->gl_internal_format_cache == GL_RGB10_A2) { + + img_format = Image::FORMAT_RGBA8; + + uint32_t *ptr = (uint32_t *)wb.ptr(); + uint32_t num_pixels = data_size / 4; + + for (int ofs = 0; ofs < num_pixels; ofs++) { + uint32_t px = ptr[ofs]; + uint32_t a = px >> 30 & 0xFF; + + ptr[ofs] = (px >> 2 & 0xFF) | + (px >> 12 & 0xFF) << 8 | + (px >> 22 & 0xFF) << 16 | + (a | a << 2 | a << 4 | a << 6) << 24; + } + } else { + img_format = texture->format; + } + wb = PoolVector<uint8_t>::Write(); data.resize(data_size); - Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1 ? true : false, texture->format, data)); + Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1 ? true : false, img_format, data)); return Ref<Image>(img); #else @@ -2184,10 +2207,15 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy Transform2D v = value; GLfloat *gui = (GLfloat *)data; + //in std140 members of mat2 are treated as vec4s gui[0] = v.elements[0][0]; gui[1] = v.elements[0][1]; - gui[2] = v.elements[1][0]; - gui[3] = v.elements[1][1]; + gui[2] = 0; + gui[3] = 0; + gui[4] = v.elements[1][0]; + gui[5] = v.elements[1][1]; + gui[6] = 0; + gui[7] = 0; } break; case ShaderLanguage::TYPE_MAT3: { @@ -2362,9 +2390,15 @@ _FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, case ShaderLanguage::TYPE_MAT2: { GLfloat *gui = (GLfloat *)data; - for (int i = 0; i < 2; i++) { - gui[i] = value[i].real; - } + //in std140 members of mat2 are treated as vec4s + gui[0] = value[0].real; + gui[1] = value[1].real; + gui[2] = 0; + gui[3] = 0; + gui[4] = value[2].real; + gui[5] = value[3].real; + gui[6] = 0; + gui[7] = 0; } break; case ShaderLanguage::TYPE_MAT3: { @@ -2418,11 +2452,14 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, case ShaderLanguage::TYPE_BVEC4: case ShaderLanguage::TYPE_IVEC4: case ShaderLanguage::TYPE_UVEC4: - case ShaderLanguage::TYPE_VEC4: - case ShaderLanguage::TYPE_MAT2: { + case ShaderLanguage::TYPE_VEC4: { zeromem(data, 16); } break; + case ShaderLanguage::TYPE_MAT2: { + + zeromem(data, 32); + } break; case ShaderLanguage::TYPE_MAT3: { zeromem(data, 48); @@ -5332,7 +5369,7 @@ void RasterizerStorageGLES3::particles_set_emitting(RID p_particles, bool p_emit Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); if (p_emitting != particles->emitting) { - // Restart is overriden by set_emitting + // Restart is overridden by set_emitting particles->restart_request = false; } particles->emitting = p_emitting; @@ -5680,6 +5717,7 @@ void RasterizerStorageGLES3::_particles_process(Particles *p_particles, float p_ SWAP(p_particles->particle_buffers[0], p_particles->particle_buffers[1]); SWAP(p_particles->particle_vaos[0], p_particles->particle_vaos[1]); + glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0); glBindVertexArray(0); /* //debug particles :D glBindBuffer(GL_ARRAY_BUFFER, p_particles->particle_buffers[0]); @@ -6950,6 +6988,7 @@ bool RasterizerStorageGLES3::free(RID p_rid) { memdelete(cls); } else if (particles_owner.owns(p_rid)) { Particles *particles = particles_owner.get(p_rid); + particles->instance_remove_deps(); particles_owner.free(p_rid); memdelete(particles); } else { diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index ada7acb879..f1d7085d54 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -56,6 +56,41 @@ static int _get_datatype_size(SL::DataType p_type) { case SL::TYPE_VOID: return 0; case SL::TYPE_BOOL: return 4; case SL::TYPE_BVEC2: return 8; + case SL::TYPE_BVEC3: return 12; + case SL::TYPE_BVEC4: return 16; + case SL::TYPE_INT: return 4; + case SL::TYPE_IVEC2: return 8; + case SL::TYPE_IVEC3: return 12; + case SL::TYPE_IVEC4: return 16; + case SL::TYPE_UINT: return 4; + case SL::TYPE_UVEC2: return 8; + case SL::TYPE_UVEC3: return 12; + case SL::TYPE_UVEC4: return 16; + case SL::TYPE_FLOAT: return 4; + case SL::TYPE_VEC2: return 8; + case SL::TYPE_VEC3: return 12; + case SL::TYPE_VEC4: return 16; + case SL::TYPE_MAT2: + return 32; //4 * 4 + 4 * 4 + case SL::TYPE_MAT3: + return 48; // 4 * 4 + 4 * 4 + 4 * 4 + case SL::TYPE_MAT4: return 64; + case SL::TYPE_SAMPLER2D: return 16; + case SL::TYPE_ISAMPLER2D: return 16; + case SL::TYPE_USAMPLER2D: return 16; + case SL::TYPE_SAMPLERCUBE: return 16; + } + + ERR_FAIL_V(0); +} + +static int _get_datatype_alignment(SL::DataType p_type) { + + switch (p_type) { + + case SL::TYPE_VOID: return 0; + case SL::TYPE_BOOL: return 4; + case SL::TYPE_BVEC2: return 8; case SL::TYPE_BVEC3: return 16; case SL::TYPE_BVEC4: return 16; case SL::TYPE_INT: return 4; @@ -71,8 +106,8 @@ static int _get_datatype_size(SL::DataType p_type) { case SL::TYPE_VEC3: return 16; case SL::TYPE_VEC4: return 16; case SL::TYPE_MAT2: return 16; - case SL::TYPE_MAT3: return 48; - case SL::TYPE_MAT4: return 64; + case SL::TYPE_MAT3: return 16; + case SL::TYPE_MAT4: return 16; case SL::TYPE_SAMPLER2D: return 16; case SL::TYPE_ISAMPLER2D: return 16; case SL::TYPE_USAMPLER2D: return 16; @@ -81,7 +116,6 @@ static int _get_datatype_size(SL::DataType p_type) { ERR_FAIL_V(0); } - static String _interpstr(SL::DataInterpolation p_interp) { switch (p_interp) { @@ -341,7 +375,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener } uniform_defines[E->get().order] = ucode; uniform_sizes[E->get().order] = _get_datatype_size(E->get().type); - uniform_alignments[E->get().order] = MIN(16, _get_datatype_size(E->get().type)); + uniform_alignments[E->get().order] = _get_datatype_alignment(E->get().type); } p_actions.uniforms->insert(E->key(), E->get()); @@ -350,6 +384,27 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener for (int i = 0; i < max_uniforms; i++) { r_gen_code.uniforms += uniform_defines[i]; } +#if 1 + // add up + int offset = 0; + for (int i = 0; i < uniform_sizes.size(); i++) { + + int align = offset % uniform_alignments[i]; + + if (align != 0) { + offset += uniform_alignments[i] - align; + } + + r_gen_code.uniform_offsets.push_back(offset); + + offset += uniform_sizes[i]; + } + + r_gen_code.uniform_total_size = offset; + if (r_gen_code.uniform_total_size % 16 != 0) { //UBO sizes must be multiples of 16 + r_gen_code.uniform_total_size += r_gen_code.uniform_total_size % 16; + } +#else // add up for (int i = 0; i < uniform_sizes.size(); i++) { @@ -389,6 +444,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener } else { r_gen_code.uniform_total_size = 0; } +#endif for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) { diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 46641482ec..f436ef06f7 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -285,7 +285,7 @@ MATERIAL_UNIFORMS FRAGMENT_SHADER_GLOBALS -void light_compute(inout vec3 light,vec3 light_vec,float light_height,vec4 light_color,vec2 light_uv,vec4 shadow,vec3 normal,vec2 uv,vec2 screen_uv,vec4 color) { +void light_compute(inout vec4 light,vec2 light_vec,float light_height,vec4 light_color,vec2 light_uv,vec4 shadow,vec3 normal,vec2 uv,vec2 screen_uv,vec4 color) { #if defined(USE_LIGHT_SHADER_CODE) diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl index 743fe122d1..1b7c626d3c 100644 --- a/drivers/gles3/shaders/copy.glsl +++ b/drivers/gles3/shaders/copy.glsl @@ -131,7 +131,7 @@ void main() { #elif defined(USE_ASYM_PANO) - // When an assymetrical projection matrix is used (applicable for stereoscopic rendering i.e. VR) we need to do this calculation per fragment to get a perspective correct result. + // When an asymmetrical projection matrix is used (applicable for stereoscopic rendering i.e. VR) we need to do this calculation per fragment to get a perspective correct result. // Note that we're ignoring the x-offset for IPD, with Z sufficiently in the distance it becomes neglectible, as a result we could probably just set cube_normal.z to -1. // The Matrix[2][0] (= asym_proj.x) and Matrix[2][1] (= asym_proj.z) values are what provide the right shift in the image. @@ -161,7 +161,7 @@ void main() { #ifdef SRGB_TO_LINEAR - color.rgb = mix(pow((color.rgb + vec3(0.055)) * (1.0 / (1 + 0.055)),vec3(2.4)),color.rgb * (1.0 / 12.92),lessThan(color.rgb,vec3(0.04045))); + color.rgb = mix(pow((color.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)),vec3(2.4)),color.rgb * (1.0 / 12.92),lessThan(color.rgb,vec3(0.04045))); #endif #ifdef DEBUG_GRADIENT diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index 1ed3999e1e..5b093a5885 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -236,6 +236,11 @@ void FileAccessUnix::store_8(uint8_t p_dest) { ERR_FAIL_COND(fwrite(&p_dest, 1, 1, f) != 1); } +void FileAccessUnix::store_buffer(const uint8_t *p_src, int p_length) { + ERR_FAIL_COND(!f); + ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != p_length); +} + bool FileAccessUnix::file_exists(const String &p_path) { int err; diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index 6f792076b8..dbb1c9f3b5 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -75,6 +75,7 @@ public: virtual void flush(); virtual void store_8(uint8_t p_dest); ///< store a byte + virtual void store_buffer(const uint8_t *p_src, int p_length); ///< store an array of bytes virtual bool file_exists(const String &p_path); ///< return true if a file exists diff --git a/drivers/unix/stream_peer_tcp_posix.cpp b/drivers/unix/stream_peer_tcp_posix.cpp index ba9481d36b..17112e5ab5 100644 --- a/drivers/unix/stream_peer_tcp_posix.cpp +++ b/drivers/unix/stream_peer_tcp_posix.cpp @@ -304,7 +304,7 @@ Error StreamPeerTCPPosix::read(uint8_t *p_buffer, int p_bytes, int &r_received, return OK; }; -void StreamPeerTCPPosix::set_nodelay(bool p_enabled) { +void StreamPeerTCPPosix::set_no_delay(bool p_enabled) { ERR_FAIL_COND(!is_connected_to_host()); int flag = p_enabled ? 1 : 0; diff --git a/drivers/unix/stream_peer_tcp_posix.h b/drivers/unix/stream_peer_tcp_posix.h index 5770ae48f4..bcebe57771 100644 --- a/drivers/unix/stream_peer_tcp_posix.h +++ b/drivers/unix/stream_peer_tcp_posix.h @@ -77,7 +77,7 @@ public: virtual Status get_status() const; virtual void disconnect_from_host(); - virtual void set_nodelay(bool p_enabled); + virtual void set_no_delay(bool p_enabled); static void make_default(); diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index 4c80e70a95..36acfb10d1 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -40,6 +40,76 @@ const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); const IID IID_IAudioClient = __uuidof(IAudioClient); const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); +static bool default_device_changed = false; + +class CMMNotificationClient : public IMMNotificationClient { + LONG _cRef; + IMMDeviceEnumerator *_pEnumerator; + +public: + CMMNotificationClient() : + _cRef(1), + _pEnumerator(NULL) {} + ~CMMNotificationClient() { + if ((_pEnumerator) != NULL) { + (_pEnumerator)->Release(); + (_pEnumerator) = NULL; + } + } + + ULONG STDMETHODCALLTYPE AddRef() { + return InterlockedIncrement(&_cRef); + } + + ULONG STDMETHODCALLTYPE Release() { + ULONG ulRef = InterlockedDecrement(&_cRef); + if (0 == ulRef) { + delete this; + } + return ulRef; + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface) { + if (IID_IUnknown == riid) { + AddRef(); + *ppvInterface = (IUnknown *)this; + } else if (__uuidof(IMMNotificationClient) == riid) { + AddRef(); + *ppvInterface = (IMMNotificationClient *)this; + } else { + *ppvInterface = NULL; + return E_NOINTERFACE; + } + return S_OK; + } + + HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId) { + return S_OK; + }; + + HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId) { + return S_OK; + } + + HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) { + return S_OK; + } + + HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId) { + if (flow == eRender && role == eConsole) { + default_device_changed = true; + } + + return S_OK; + } + + HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) { + return S_OK; + } +}; + +static CMMNotificationClient notif_client; + Error AudioDriverWASAPI::init_device(bool reinit) { WAVEFORMATEX *pwfex; @@ -54,7 +124,7 @@ Error AudioDriverWASAPI::init_device(bool reinit) { hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device); if (reinit) { // In case we're trying to re-initialize the device prevent throwing this error on the console, - // otherwise if there is currently no devie available this will spam the console. + // otherwise if there is currently no device available this will spam the console. if (hr != S_OK) { return ERR_CANT_OPEN; } @@ -62,6 +132,11 @@ Error AudioDriverWASAPI::init_device(bool reinit) { ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); } + hr = enumerator->RegisterEndpointNotificationCallback(¬if_client); + if (hr != S_OK) { + ERR_PRINT("WASAPI: RegisterEndpointNotificationCallback error"); + } + hr = device->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&audio_client); if (reinit) { if (hr != S_OK) { @@ -148,6 +223,8 @@ Error AudioDriverWASAPI::finish_device() { if (audio_client) { if (active) { audio_client->Stop(); + audio_client->Release(); + audio_client = NULL; active = false; } } @@ -323,6 +400,15 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { } } + if (default_device_changed) { + Error err = ad->finish_device(); + if (err != OK) { + ERR_PRINT("WASAPI: finish_device error"); + } + + default_device_changed = false; + } + if (!ad->audio_client) { Error err = ad->init_device(true); if (err == OK) { diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index dbffac8ebd..072790876f 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -31,6 +31,7 @@ #ifdef WINDOWS_ENABLED #include "file_access_windows.h" +#include "os/os.h" #include "shlwapi.h" #include <windows.h> @@ -115,28 +116,41 @@ void FileAccessWindows::close() { //_wunlink(save_path.c_str()); //unlink if exists //int rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str()); - bool rename_error; + bool rename_error = true; + int attempts = 4; + while (rename_error && attempts) { + // This workaround of trying multiple times is added to deal with paranoid Windows + // antiviruses that love reading just written files even if they are not executable, thus + // locking the file and preventing renaming from happening. #ifdef UWP_ENABLED - // UWP has no PathFileExists, so we check attributes instead - DWORD fileAttr; + // UWP has no PathFileExists, so we check attributes instead + DWORD fileAttr; - fileAttr = GetFileAttributesW(save_path.c_str()); - if (INVALID_FILE_ATTRIBUTES == fileAttr) { + fileAttr = GetFileAttributesW(save_path.c_str()); + if (INVALID_FILE_ATTRIBUTES == fileAttr) { #else - if (!PathFileExistsW(save_path.c_str())) { + if (!PathFileExistsW(save_path.c_str())) { #endif - //creating new file - rename_error = _wrename((save_path + ".tmp").c_str(), save_path.c_str()) != 0; - } else { - //atomic replace for existing file - rename_error = !ReplaceFileW(save_path.c_str(), (save_path + ".tmp").c_str(), NULL, 2 | 4, NULL, NULL); - } - if (rename_error && close_fail_notify) { - close_fail_notify(save_path); + //creating new file + rename_error = _wrename((save_path + ".tmp").c_str(), save_path.c_str()) != 0; + } else { + //atomic replace for existing file + rename_error = !ReplaceFileW(save_path.c_str(), (save_path + ".tmp").c_str(), NULL, 2 | 4, NULL, NULL); + } + if (rename_error && close_fail_notify) { + close_fail_notify(save_path); + } + if (rename_error) { + attempts--; + OS::get_singleton()->delay_usec(1000000); //wait 100msec and try again + } } save_path = ""; + if (rename_error) { + ERR_EXPLAIN("Safe save failed. This may be a permissions problem, but also may happen because you are running a paranoid antivirus. If this is the case, please switch to Windows Defender or disable the 'safe save' option in editor settings. This makes it work, but increases the risk of file corruption in a crash."); + } ERR_FAIL_COND(rename_error); } } @@ -221,6 +235,11 @@ void FileAccessWindows::store_8(uint8_t p_dest) { fwrite(&p_dest, 1, 1, f); } +void FileAccessWindows::store_buffer(const uint8_t *p_src, int p_length) { + ERR_FAIL_COND(!f); + ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != p_length); +} + bool FileAccessWindows::file_exists(const String &p_name) { FILE *g; diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h index bbdf830c96..26bd08b7af 100644 --- a/drivers/windows/file_access_windows.h +++ b/drivers/windows/file_access_windows.h @@ -67,6 +67,7 @@ public: virtual void flush(); virtual void store_8(uint8_t p_dest); ///< store a byte + virtual void store_buffer(const uint8_t *p_src, int p_length); ///< store an array of bytes virtual bool file_exists(const String &p_name); ///< return true if a file exists diff --git a/drivers/windows/stream_peer_tcp_winsock.cpp b/drivers/windows/stream_peer_tcp_winsock.cpp index d6a320fb5e..55775fc231 100644 --- a/drivers/windows/stream_peer_tcp_winsock.cpp +++ b/drivers/windows/stream_peer_tcp_winsock.cpp @@ -332,7 +332,7 @@ Error StreamPeerTCPWinsock::connect_to_host(const IP_Address &p_host, uint16_t p return OK; }; -void StreamPeerTCPWinsock::set_nodelay(bool p_enabled) { +void StreamPeerTCPWinsock::set_no_delay(bool p_enabled) { ERR_FAIL_COND(!is_connected_to_host()); int flag = p_enabled ? 1 : 0; setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)); diff --git a/drivers/windows/stream_peer_tcp_winsock.h b/drivers/windows/stream_peer_tcp_winsock.h index 9be8414878..a0177d374e 100644 --- a/drivers/windows/stream_peer_tcp_winsock.h +++ b/drivers/windows/stream_peer_tcp_winsock.h @@ -81,7 +81,7 @@ public: static void make_default(); static void cleanup(); - virtual void set_nodelay(bool p_enabled); + virtual void set_no_delay(bool p_enabled); StreamPeerTCPWinsock(); ~StreamPeerTCPWinsock(); |