@@ -677,127 +677,137 @@ LightmapperRD::BakeError LightmapperRD::_dilate(RenderingDevice *rd, Ref<RDShade
677677 return BAKE_OK;
678678}
679679
680- Error LightmapperRD::_store_pfm (RenderingDevice *p_rd, RID p_atlas_tex, int p_index, const Size2i &p_atlas_size, const String &p_name) {
681- Vector<uint8_t > data = p_rd->texture_get_data (p_atlas_tex, p_index);
682- Ref<Image> img = Image::create_from_data (p_atlas_size.width , p_atlas_size.height , false , Image::FORMAT_RGBAH, data);
683- img->convert (Image::FORMAT_RGBF);
684- Vector<uint8_t > data_float = img->get_data ();
685-
686- Error err = OK;
687- Ref<FileAccess> file = FileAccess::open (p_name, FileAccess::WRITE, &err);
688- ERR_FAIL_COND_V_MSG (err, err, vformat (" Can't save PFN at path: '%s'." , p_name));
689- file->store_line (" PF" );
690- file->store_line (vformat (" %d %d" , img->get_width (), img->get_height ()));
691- #ifdef BIG_ENDIAN_ENABLED
692- file->store_line (" 1.0" );
693- #else
694- file->store_line (" -1.0" );
695- #endif
696- file->store_buffer (data_float);
697- file->close ();
680+ bool LightmapperRD::_load_oidn (const String &p_library_path) {
681+ if (oidn_lib_path == p_library_path) {
682+ return oidn_lib_handle != nullptr ;
683+ }
684+ oidn_lib_path = p_library_path;
698685
699- return OK;
686+ Ref<DirAccess> da = DirAccess::create (DirAccess::ACCESS_FILESYSTEM);
687+ String lib_name;
688+ if (OS::get_singleton ()->get_name () == " macOS" ) {
689+ lib_name = " libOpenImageDenoise.dylib" ;
690+ } else if (OS::get_singleton ()->get_name () == " Windows" ) {
691+ lib_name = " OpenImageDenoise.dll" ;
692+ } else {
693+ lib_name = " libOpenImageDenoise.so" ;
694+ }
695+ String lib_path = oidn_lib_path.path_join (lib_name);
696+ if (!da->file_exists (lib_path)) {
697+ lib_path = oidn_lib_path.path_join (" lib" ).path_join (lib_name);
698+ }
699+ if (!da->file_exists (lib_path)) {
700+ lib_path = oidn_lib_path.path_join (" .." ).path_join (" lib" ).path_join (lib_name);
701+ }
702+
703+ _unload_oidn ();
704+
705+ if (OS::get_singleton ()->open_dynamic_library (lib_path, oidn_lib_handle, true ) != OK) {
706+ oidn_lib_handle = nullptr ;
707+ ERR_PRINT (vformat (TTR (" Failed to load %s." ), lib_path));
708+ return false ;
709+ }
710+ bool symbols_ok = true ;
711+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnNewDevice" , (void *&)oidnNewDevice) == OK);
712+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnCommitDevice" , (void *&)oidnCommitDevice) == OK);
713+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnNewFilter" , (void *&)oidnNewFilter) == OK);
714+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnSetSharedFilterImage" , (void *&)oidnSetSharedFilterImage) == OK);
715+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnSetFilterBool" , (void *&)oidnSetFilterBool) == OK);
716+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnCommitFilter" , (void *&)oidnCommitFilter) == OK);
717+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnExecuteFilter" , (void *&)oidnExecuteFilter) == OK);
718+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnGetDeviceError" , (void *&)oidnGetDeviceError) == OK);
719+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnReleaseFilter" , (void *&)oidnReleaseFilter) == OK);
720+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnReleaseDevice" , (void *&)oidnReleaseDevice) == OK);
721+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnNewBuffer" , (void *&)oidnNewBuffer) == OK);
722+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnGetBufferData" , (void *&)oidnGetBufferData) == OK);
723+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnReadBuffer" , (void *&)oidnReadBuffer) == OK);
724+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnWriteBuffer" , (void *&)oidnWriteBuffer) == OK);
725+ symbols_ok = symbols_ok && (OS::get_singleton ()->get_dynamic_library_symbol_handle (oidn_lib_handle, " oidnReleaseBuffer" , (void *&)oidnReleaseBuffer) == OK);
726+ if (!symbols_ok) {
727+ ERR_PRINT (TTR (" Failed to load OIDN symbols." ));
728+ _unload_oidn ();
729+ return false ;
730+ }
731+
732+ oidn_device = oidnNewDevice (OIDN_DEVICE_TYPE_DEFAULT);
733+ oidnCommitDevice (oidn_device);
734+ const char *msg = nullptr ;
735+ if (oidnGetDeviceError (oidn_device, &msg) != OIDN_ERROR_NONE) {
736+ ERR_PRINT (vformat (TTR (" Failed to load OIDN device: %s" ), msg));
737+ _unload_oidn ();
738+ return false ;
739+ }
740+
741+ return true ;
700742}
701743
702- Ref<Image> LightmapperRD::_read_pfm (const String &p_name) {
703- Error err = OK;
704- Ref<FileAccess> file = FileAccess::open (p_name, FileAccess::READ, &err);
705- ERR_FAIL_COND_V_MSG (err, Ref<Image>(), vformat (" Can't load PFM at path: '%s'." , p_name));
706- ERR_FAIL_COND_V (file->get_line () != " PF" , Ref<Image>());
707-
708- Vector<String> new_size = file->get_line ().split (" " );
709- ERR_FAIL_COND_V (new_size.size () != 2 , Ref<Image>());
710- int new_width = new_size[0 ].to_int ();
711- int new_height = new_size[1 ].to_int ();
712-
713- float endian = file->get_line ().to_float ();
714- Vector<uint8_t > new_data = file->get_buffer (file->get_length () - file->get_position ());
715- file->close ();
716-
717- #ifdef BIG_ENDIAN_ENABLED
718- if (unlikely (endian < 0.0 )) {
719- uint32_t count = new_data.size () / 4 ;
720- uint16_t *dst = (uint16_t *)new_data.ptrw ();
721- for (uint32_t j = 0 ; j < count; j++) {
722- dst[j * 4 ] = BSWAP32 (dst[j * 4 ]);
723- }
724- }
725- #else
726- if (unlikely (endian > 0.0 )) {
727- uint32_t count = new_data.size () / 4 ;
728- uint16_t *dst = (uint16_t *)new_data.ptrw ();
729- for (uint32_t j = 0 ; j < count; j++) {
730- dst[j * 4 ] = BSWAP32 (dst[j * 4 ]);
744+ void LightmapperRD::_unload_oidn () {
745+ if (oidn_lib_handle) {
746+ if (oidn_device) {
747+ oidnReleaseDevice (oidn_device);
748+ oidn_device = nullptr ;
731749 }
750+
751+ OS::get_singleton ()->close_dynamic_library (oidn_lib_handle);
752+ oidn_lib_handle = nullptr ;
732753 }
733- #endif
734- Ref<Image> img = Image::create_from_data (new_width, new_height, false , Image::FORMAT_RGBF, new_data);
735- img->convert (Image::FORMAT_RGBAH);
736- return img;
737754}
738755
739- 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) {
740- Ref<DirAccess> da = DirAccess::create (DirAccess::ACCESS_FILESYSTEM);
741-
756+ 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) {
742757 for (int i = 0 ; i < p_atlas_slices; i++) {
743- String fname_norm_in = EditorPaths::get_singleton ()->get_cache_dir ().path_join (vformat (" temp_norm_%d.pfm" , i));
744- _store_pfm (p_rd, p_source_normal_tex, i, p_atlas_size, fname_norm_in);
758+ Vector<uint8_t > sn = p_rd->texture_get_data (p_source_normal_tex, i);
759+
760+ Ref<Image> imgn = Image::create_from_data (p_atlas_size.width , p_atlas_size.height , false , Image::FORMAT_RGBAH, sn);
761+ imgn->convert (Image::FORMAT_RGBF);
762+ Vector<uint8_t > datan = imgn->get_data ();
763+ void *bufn = oidnNewBuffer (oidn_device, datan.size ());
764+ oidnWriteBuffer (bufn, 0 , datan.size (), (void *)datan.ptrw ());
745765
746766 for (int j = 0 ; j < (p_bake_sh ? 4 : 1 ); j++) {
747767 int index = i * (p_bake_sh ? 4 : 1 ) + j;
748- String fname_light_in = EditorPaths::get_singleton ()->get_cache_dir ().path_join (vformat (" temp_light_%d.pfm" , index));
749- String fname_out = EditorPaths::get_singleton ()->get_cache_dir ().path_join (vformat (" temp_denoised_%d.pfm" , index));
750-
751- _store_pfm (p_rd, p_source_light_tex, index, p_atlas_size, fname_light_in);
752-
753- List<String> args;
754- args.push_back (" --device" );
755- args.push_back (" default" );
756-
757- args.push_back (" --filter" );
758- args.push_back (" RTLightmap" );
759-
760- args.push_back (" --hdr" );
761- args.push_back (fname_light_in);
762768
763- args.push_back (" --nrm" );
764- args.push_back (fname_norm_in);
769+ Vector<uint8_t > sl = p_rd->texture_get_data (p_source_light_tex, index);
765770
766- args.push_back (" --output" );
767- args.push_back (fname_out);
771+ Ref<Image> imgl = Image::create_from_data (p_atlas_size.width , p_atlas_size.height , false , Image::FORMAT_RGBAH, sl);
772+ imgl->convert (Image::FORMAT_RGBF);
773+ Vector<uint8_t > datal = imgl->get_data ();
768774
769- String str ;
770- int exitcode = 0 ;
775+ void *bufl = oidnNewBuffer (oidn_device, datal. size ()) ;
776+ oidnWriteBuffer (bufl, 0 , datal. size (), ( void *)datal. ptrw ()) ;
771777
772- Error err = OS::get_singleton ()->execute (p_exe, args, &str, &exitcode, true );
778+ void *filter = oidnNewFilter (oidn_device, " RTLightmap" );
779+ oidnSetSharedFilterImage (filter, " color" , oidnGetBufferData (bufl), OIDN_FORMAT_FLOAT3, imgl->get_width (), imgl->get_height (), 0 , 0 , 0 );
780+ oidnSetSharedFilterImage (filter, " normal" , oidnGetBufferData (bufn), OIDN_FORMAT_FLOAT3, imgn->get_width (), imgn->get_height (), 0 , 0 , 0 );
781+ oidnSetSharedFilterImage (filter, " output" , oidnGetBufferData (bufl), OIDN_FORMAT_FLOAT3, imgl->get_width (), imgl->get_height (), 0 , 0 , 0 );
782+ oidnSetFilterBool (filter, " hdr" , true );
783+ oidnCommitFilter (filter);
784+ oidnExecuteFilter (filter);
773785
774- da->remove (fname_light_in);
775-
776- if (err != OK || exitcode != 0 ) {
777- da->remove (fname_out);
778- print_verbose (str);
779- ERR_FAIL_V_MSG (BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, vformat (TTR (" OIDN denoiser failed, return code: %d" ), exitcode));
786+ const char *msg = nullptr ;
787+ if (oidnGetDeviceError (oidn_device, &msg) != OIDN_ERROR_NONE) {
788+ oidnReleaseFilter (filter);
789+ ERR_FAIL_V_MSG (BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, String (msg));
780790 }
781-
782- Ref<Image> img = _read_pfm (fname_out);
783- da->remove (fname_out);
784-
785- ERR_FAIL_COND_V (img.is_null (), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES);
786-
787- Vector<uint8_t > old_data = p_rd->texture_get_data (p_source_light_tex, index);
788- Vector<uint8_t > new_data = img->get_data ();
789- img.unref (); // Avoid copy on write.
790-
791- uint32_t count = old_data.size () / 2 ;
792- const uint16_t *src = (const uint16_t *)old_data.ptr ();
793- uint16_t *dst = (uint16_t *)new_data.ptrw ();
794- for (uint32_t k = 0 ; k < count; k += 4 ) {
795- dst[k + 3 ] = src[k + 3 ];
791+ oidnReleaseFilter (filter);
792+
793+ oidnReadBuffer (bufl, 0 , datal.size (), (void *)datal.ptrw ());
794+ oidnReleaseBuffer (bufl);
795+
796+ imgl->set_data (imgl->get_width (), imgl->get_height (), false , imgl->get_format (), datal);
797+ imgl->convert (Image::FORMAT_RGBAH);
798+ Vector<uint8_t > ds = imgl->get_data ();
799+ imgl.unref (); // Avoid copy on write.
800+ { // Restore alpha.
801+ uint32_t count = sl.size () / 2 ;
802+ const uint16_t *src = (const uint16_t *)sl.ptr ();
803+ uint16_t *dst = (uint16_t *)ds.ptrw ();
804+ for (uint32_t k = 0 ; k < count; k += 4 ) {
805+ dst[k + 3 ] = src[k + 3 ];
806+ }
796807 }
797-
798- p_rd->texture_update (p_dest_light_tex, index, new_data);
808+ p_rd->texture_update (p_dest_light_tex, index, ds);
799809 }
800- da-> remove (fname_norm_in );
810+ oidnReleaseBuffer (bufn );
801811 }
802812 return BAKE_OK;
803813}
@@ -879,15 +889,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
879889 if (p_use_denoiser && denoiser == 1 ) {
880890 // OIDN (external).
881891 Ref<DirAccess> da = DirAccess::create (DirAccess::ACCESS_FILESYSTEM);
882-
883- if (da->dir_exists (oidn_path)) {
884- if (OS::get_singleton ()->get_name () == " Windows" ) {
885- oidn_path = oidn_path.path_join (" oidnDenoise.exe" );
886- } else {
887- oidn_path = oidn_path.path_join (" oidnDenoise" );
888- }
889- }
890- ERR_FAIL_COND_V_MSG (oidn_path.is_empty () || !da->file_exists (oidn_path), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, TTR (" OIDN denoiser is selected in the project settings, but no or invalid OIDN executable path is configured in the editor settings." ));
892+ ERR_FAIL_COND_V_MSG (oidn_path.is_empty () || !_load_oidn (oidn_path), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, TTR (" OIDN denoiser is selected in the project settings, but no or invalid OIDN library path is configured in the editor settings." ));
891893 }
892894
893895 if (p_step_function) {
@@ -1627,7 +1629,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
16271629 BakeError error;
16281630 if (denoiser == 1 ) {
16291631 // OIDN (external).
1630- error = _denoise_oidn (rd, light_accum_tex, normal_tex, light_accum_tex, atlas_size, atlas_slices, p_bake_sh, oidn_path );
1632+ error = _denoise_oidn (rd, light_accum_tex, normal_tex, light_accum_tex, atlas_size, atlas_slices, p_bake_sh);
16311633 } else {
16321634 // JNLM (built-in).
16331635 SWAP (light_accum_tex, light_accum_tex2);
@@ -1896,3 +1898,7 @@ Vector<Color> LightmapperRD::get_bake_probe_sh(int p_probe) const {
18961898
18971899LightmapperRD::LightmapperRD () {
18981900}
1901+
1902+ LightmapperRD::~LightmapperRD () {
1903+ _unload_oidn ();
1904+ }
0 commit comments