@@ -778,127 +778,137 @@ LightmapperRD::BakeError LightmapperRD::_dilate(RenderingDevice *rd, Ref<RDShade
778778 return BAKE_OK;
779779}
780780
781- Error LightmapperRD::_store_pfm (RenderingDevice *p_rd, RID p_atlas_tex, int p_index, const Size2i &p_atlas_size, const String &p_name) {
782- Vector<uint8_t > data = p_rd->texture_get_data (p_atlas_tex, p_index);
783- Ref<Image> img = Image::create_from_data (p_atlas_size.width , p_atlas_size.height , false , Image::FORMAT_RGBAH, data);
784- img->convert (Image::FORMAT_RGBF);
785- Vector<uint8_t > data_float = img->get_data ();
786-
787- Error err = OK;
788- Ref<FileAccess> file = FileAccess::open (p_name, FileAccess::WRITE, &err);
789- ERR_FAIL_COND_V_MSG (err, err, vformat (" Can't save PFN at path: '%s'." , p_name));
790- file->store_line (" PF" );
791- file->store_line (vformat (" %d %d" , img->get_width (), img->get_height ()));
792- #ifdef BIG_ENDIAN_ENABLED
793- file->store_line (" 1.0" );
794- #else
795- file->store_line (" -1.0" );
796- #endif
797- file->store_buffer (data_float);
798- file->close ();
781+ bool LightmapperRD::_load_oidn (const String &p_library_path) {
782+ if (oidn_lib_path == p_library_path) {
783+ return oidn_lib_handle != nullptr ;
784+ }
785+ oidn_lib_path = p_library_path;
799786
800- return OK;
787+ Ref<DirAccess> da = DirAccess::create (DirAccess::ACCESS_FILESYSTEM);
788+ String lib_name;
789+ if (OS::get_singleton ()->get_name () == " macOS" ) {
790+ lib_name = " libOpenImageDenoise.dylib" ;
791+ } else if (OS::get_singleton ()->get_name () == " Windows" ) {
792+ lib_name = " OpenImageDenoise.dll" ;
793+ } else {
794+ lib_name = " libOpenImageDenoise.so" ;
795+ }
796+ String lib_path = oidn_lib_path.path_join (lib_name);
797+ if (!da->file_exists (lib_path)) {
798+ lib_path = oidn_lib_path.path_join (" lib" ).path_join (lib_name);
799+ }
800+ if (!da->file_exists (lib_path)) {
801+ lib_path = oidn_lib_path.path_join (" .." ).path_join (" lib" ).path_join (lib_name);
802+ }
803+
804+ _unload_oidn ();
805+
806+ if (OS::get_singleton ()->open_dynamic_library (lib_path, oidn_lib_handle, true ) != OK) {
807+ oidn_lib_handle = nullptr ;
808+ ERR_PRINT (vformat (" Failed to load %s." , lib_path));
809+ return false ;
810+ }
811+ bool symbols_ok = true ;
812+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnNewDevice" , (void *&)oidnNewDevice) == OK);
813+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnCommitDevice" , (void *&)oidnCommitDevice) == OK);
814+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnNewFilter" , (void *&)oidnNewFilter) == OK);
815+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnSetSharedFilterImage" , (void *&)oidnSetSharedFilterImage) == OK);
816+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnSetFilterBool" , (void *&)oidnSetFilterBool) == OK);
817+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnCommitFilter" , (void *&)oidnCommitFilter) == OK);
818+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnExecuteFilter" , (void *&)oidnExecuteFilter) == OK);
819+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnGetDeviceError" , (void *&)oidnGetDeviceError) == OK);
820+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnReleaseFilter" , (void *&)oidnReleaseFilter) == OK);
821+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnReleaseDevice" , (void *&)oidnReleaseDevice) == OK);
822+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnNewBuffer" , (void *&)oidnNewBuffer) == OK);
823+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnGetBufferData" , (void *&)oidnGetBufferData) == OK);
824+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnReadBuffer" , (void *&)oidnReadBuffer) == OK);
825+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnWriteBuffer" , (void *&)oidnWriteBuffer) == OK);
826+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnReleaseBuffer" , (void *&)oidnReleaseBuffer) == OK);
827+ if (!symbols_ok) {
828+ ERR_PRINT (" Failed to load OIDN symbols." );
829+ _unload_oidn ();
830+ return false ;
831+ }
832+
833+ oidn_device = oidnNewDevice (OIDN_DEVICE_TYPE_DEFAULT);
834+ oidnCommitDevice (oidn_device);
835+ const char *msg = nullptr ;
836+ if (oidnGetDeviceError (oidn_device, &msg) != OIDN_ERROR_NONE) {
837+ ERR_PRINT (vformat (" Failed to load OIDN device: %s" , msg));
838+ _unload_oidn ();
839+ return false ;
840+ }
841+
842+ return true ;
801843}
802844
803- Ref<Image> LightmapperRD::_read_pfm (const String &p_name) {
804- Error err = OK;
805- Ref<FileAccess> file = FileAccess::open (p_name, FileAccess::READ, &err);
806- ERR_FAIL_COND_V_MSG (err, Ref<Image>(), vformat (" Can't load PFM at path: '%s'." , p_name));
807- ERR_FAIL_COND_V (file->get_line () != " PF" , Ref<Image>());
808-
809- Vector<String> new_size = file->get_line ().split (" " );
810- ERR_FAIL_COND_V (new_size.size () != 2 , Ref<Image>());
811- int new_width = new_size[0 ].to_int ();
812- int new_height = new_size[1 ].to_int ();
813-
814- float endian = file->get_line ().to_float ();
815- Vector<uint8_t > new_data = file->get_buffer (file->get_length () - file->get_position ());
816- file->close ();
817-
818- #ifdef BIG_ENDIAN_ENABLED
819- if (unlikely (endian < 0.0 )) {
820- uint32_t count = new_data.size () / 4 ;
821- uint16_t *dst = (uint16_t *)new_data.ptrw ();
822- for (uint32_t j = 0 ; j < count; j++) {
823- dst[j * 4 ] = BSWAP32 (dst[j * 4 ]);
824- }
825- }
826- #else
827- if (unlikely (endian > 0.0 )) {
828- uint32_t count = new_data.size () / 4 ;
829- uint16_t *dst = (uint16_t *)new_data.ptrw ();
830- for (uint32_t j = 0 ; j < count; j++) {
831- dst[j * 4 ] = BSWAP32 (dst[j * 4 ]);
845+ void LightmapperRD::_unload_oidn () {
846+ if (oidn_lib_handle) {
847+ if (oidn_device) {
848+ oidnReleaseDevice (oidn_device);
849+ oidn_device = nullptr ;
832850 }
851+
852+ OS::get_singleton ()->close_dynamic_library (oidn_lib_handle);
853+ oidn_lib_handle = nullptr ;
833854 }
834- #endif
835- Ref<Image> img = Image::create_from_data (new_width, new_height, false , Image::FORMAT_RGBF, new_data);
836- img->convert (Image::FORMAT_RGBAH);
837- return img;
838855}
839856
840- LightmapperRD::BakeError LightmapperRD::_denoise_oidn (RenderingDevice *p_rd, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, const String &p_exe) {
841- Ref<DirAccess> da = DirAccess::create (DirAccess::ACCESS_FILESYSTEM);
842-
857+ LightmapperRD::BakeError LightmapperRD::_denoise_oidn (RenderingDevice *p_rd, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh) {
843858 for (int i = 0 ; i < p_atlas_slices; i++) {
844- String fname_norm_in = EditorPaths::get_singleton ()->get_cache_dir ().path_join (vformat (" temp_norm_%d.pfm" , i));
845- _store_pfm (p_rd, p_source_normal_tex, i, p_atlas_size, fname_norm_in);
859+ Vector<uint8_t > sn = p_rd->texture_get_data (p_source_normal_tex, i);
860+
861+ Ref<Image> imgn = Image::create_from_data (p_atlas_size.width , p_atlas_size.height , false , Image::FORMAT_RGBAH, sn);
862+ imgn->convert (Image::FORMAT_RGBF);
863+ Vector<uint8_t > datan = imgn->get_data ();
864+ void *bufn = oidnNewBuffer (oidn_device, datan.size ());
865+ oidnWriteBuffer (bufn, 0 , datan.size (), (void *)datan.ptrw ());
846866
847867 for (int j = 0 ; j < (p_bake_sh ? 4 : 1 ); j++) {
848868 int index = i * (p_bake_sh ? 4 : 1 ) + j;
849- String fname_light_in = EditorPaths::get_singleton ()->get_cache_dir ().path_join (vformat (" temp_light_%d.pfm" , index));
850- String fname_out = EditorPaths::get_singleton ()->get_cache_dir ().path_join (vformat (" temp_denoised_%d.pfm" , index));
851-
852- _store_pfm (p_rd, p_source_light_tex, index, p_atlas_size, fname_light_in);
853-
854- List<String> args;
855- args.push_back (" --device" );
856- args.push_back (" default" );
857-
858- args.push_back (" --filter" );
859- args.push_back (" RTLightmap" );
860869
861- args.push_back (" --hdr" );
862- args.push_back (fname_light_in);
870+ Vector<uint8_t > sl = p_rd->texture_get_data (p_source_light_tex, index);
863871
864- args.push_back (" --nrm" );
865- args.push_back (fname_norm_in);
872+ Ref<Image> imgl = Image::create_from_data (p_atlas_size.width , p_atlas_size.height , false , Image::FORMAT_RGBAH, sl);
873+ imgl->convert (Image::FORMAT_RGBF);
874+ Vector<uint8_t > datal = imgl->get_data ();
866875
867- args. push_back ( " --output " );
868- args. push_back (fname_out );
876+ void *bufl = oidnNewBuffer (oidn_device, datal. size () );
877+ oidnWriteBuffer (bufl, 0 , datal. size (), ( void *)datal. ptrw () );
869878
870- String str;
871- int exitcode = 0 ;
879+ void *filter = oidnNewFilter (oidn_device, " RTLightmap" );
880+ oidnSetSharedFilterImage (filter, " color" , oidnGetBufferData (bufl), OIDN_FORMAT_FLOAT3, imgl->get_width (), imgl->get_height (), 0 , 0 , 0 );
881+ oidnSetSharedFilterImage (filter, " normal" , oidnGetBufferData (bufn), OIDN_FORMAT_FLOAT3, imgn->get_width (), imgn->get_height (), 0 , 0 , 0 );
882+ oidnSetSharedFilterImage (filter, " output" , oidnGetBufferData (bufl), OIDN_FORMAT_FLOAT3, imgl->get_width (), imgl->get_height (), 0 , 0 , 0 );
883+ oidnSetFilterBool (filter, " hdr" , true );
884+ oidnCommitFilter (filter);
885+ oidnExecuteFilter (filter);
872886
873- Error err = OS::get_singleton ()->execute (p_exe, args, &str, &exitcode, true );
874-
875- da->remove (fname_light_in);
876-
877- if (err != OK || exitcode != 0 ) {
878- da->remove (fname_out);
879- print_verbose (str);
880- ERR_FAIL_V_MSG (BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, vformat (" OIDN denoiser failed, return code: %d" , exitcode));
887+ const char *msg = nullptr ;
888+ if (oidnGetDeviceError (oidn_device, &msg) != OIDN_ERROR_NONE) {
889+ oidnReleaseFilter (filter);
890+ ERR_FAIL_V_MSG (BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, String (msg));
881891 }
882-
883- Ref<Image> img = _read_pfm (fname_out);
884- da->remove (fname_out);
885-
886- ERR_FAIL_COND_V (img.is_null (), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES);
887-
888- Vector<uint8_t > old_data = p_rd->texture_get_data (p_source_light_tex, index);
889- Vector<uint8_t > new_data = img->get_data ();
890- img.unref (); // Avoid copy on write.
891-
892- uint32_t count = old_data.size () / 2 ;
893- const uint16_t *src = (const uint16_t *)old_data.ptr ();
894- uint16_t *dst = (uint16_t *)new_data.ptrw ();
895- for (uint32_t k = 0 ; k < count; k += 4 ) {
896- dst[k + 3 ] = src[k + 3 ];
892+ oidnReleaseFilter (filter);
893+
894+ oidnReadBuffer (bufl, 0 , datal.size (), (void *)datal.ptrw ());
895+ oidnReleaseBuffer (bufl);
896+
897+ imgl->set_data (imgl->get_width (), imgl->get_height (), false , imgl->get_format (), datal);
898+ imgl->convert (Image::FORMAT_RGBAH);
899+ Vector<uint8_t > ds = imgl->get_data ();
900+ imgl.unref (); // Avoid copy on write.
901+ { // Restore alpha.
902+ uint32_t count = sl.size () / 2 ;
903+ const uint16_t *src = (const uint16_t *)sl.ptr ();
904+ uint16_t *dst = (uint16_t *)ds.ptrw ();
905+ for (uint32_t k = 0 ; k < count; k += 4 ) {
906+ dst[k + 3 ] = src[k + 3 ];
907+ }
897908 }
898-
899- p_rd->texture_update (p_dest_light_tex, index, new_data);
909+ p_rd->texture_update (p_dest_light_tex, index, ds);
900910 }
901- da-> remove (fname_norm_in );
911+ oidnReleaseBuffer (bufn );
902912 }
903913 return BAKE_OK;
904914}
@@ -980,15 +990,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
980990 if (p_use_denoiser && denoiser == 1 ) {
981991 // OIDN (external).
982992 Ref<DirAccess> da = DirAccess::create (DirAccess::ACCESS_FILESYSTEM);
983-
984- if (da->dir_exists (oidn_path)) {
985- if (OS::get_singleton ()->get_name () == " Windows" ) {
986- oidn_path = oidn_path.path_join (" oidnDenoise.exe" );
987- } else {
988- oidn_path = oidn_path.path_join (" oidnDenoise" );
989- }
990- }
991- ERR_FAIL_COND_V_MSG (oidn_path.is_empty () || !da->file_exists (oidn_path), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, " OIDN denoiser is selected in the project settings, but no or invalid OIDN executable path is configured in the editor settings." );
993+ ERR_FAIL_COND_V_MSG (oidn_path.is_empty () || !_load_oidn (oidn_path), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, " OIDN denoiser is selected in the project settings, but no or invalid OIDN library path is configured in the editor settings." );
992994 }
993995
994996 if (p_step_function) {
@@ -1749,7 +1751,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
17491751 BakeError error;
17501752 if (denoiser == 1 ) {
17511753 // OIDN (external).
1752- error = _denoise_oidn (rd, light_accum_tex, normal_tex, light_accum_tex, atlas_size, atlas_slices, p_bake_sh, oidn_path );
1754+ error = _denoise_oidn (rd, light_accum_tex, normal_tex, light_accum_tex, atlas_size, atlas_slices, p_bake_sh);
17531755 } else {
17541756 // JNLM (built-in).
17551757 SWAP (light_accum_tex, light_accum_tex2);
@@ -2018,3 +2020,7 @@ Vector<Color> LightmapperRD::get_bake_probe_sh(int p_probe) const {
20182020
20192021LightmapperRD::LightmapperRD () {
20202022}
2023+
2024+ LightmapperRD::~LightmapperRD () {
2025+ _unload_oidn ();
2026+ }
0 commit comments