resource_loader.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /*
  2. * Copyright (c) 2012-2018 Daniele Bartolini and individual contributors.
  3. * License: https://github.com/dbartolini/crown/blob/master/LICENSE
  4. */
  5. #include "config.h"
  6. #include "core/containers/hash_map.h"
  7. #include "core/containers/queue.h"
  8. #include "core/filesystem/file.h"
  9. #include "core/filesystem/filesystem.h"
  10. #include "core/filesystem/path.h"
  11. #include "core/memory/memory.h"
  12. #include "core/memory/temp_allocator.h"
  13. #include "core/os.h"
  14. #include "core/strings/dynamic_string.h"
  15. #include "device/log.h"
  16. #include "resource/resource_loader.h"
  17. namespace { const crown::log_internal::System RESOURCE_LOADER = { "resource_loader" }; }
  18. namespace crown
  19. {
  20. static s32 thread_proc(void* thiz)
  21. {
  22. return ((ResourceLoader*)thiz)->run();
  23. }
  24. ResourceLoader::ResourceLoader(Filesystem& data_filesystem)
  25. : _data_filesystem(data_filesystem)
  26. , _requests(default_allocator())
  27. , _loaded(default_allocator())
  28. , _fallback(default_allocator())
  29. , _exit(false)
  30. {
  31. _thread.start(thread_proc, this);
  32. }
  33. ResourceLoader::~ResourceLoader()
  34. {
  35. _exit = true;
  36. _thread.stop();
  37. }
  38. void ResourceLoader::add_request(const ResourceRequest& rr)
  39. {
  40. ScopedMutex sm(_mutex);
  41. queue::push_back(_requests, rr);
  42. }
  43. void ResourceLoader::flush()
  44. {
  45. while (num_requests()) {}
  46. }
  47. u32 ResourceLoader::num_requests()
  48. {
  49. ScopedMutex sm(_mutex);
  50. return queue::size(_requests);
  51. }
  52. void ResourceLoader::add_loaded(ResourceRequest rr)
  53. {
  54. ScopedMutex sm(_loaded_mutex);
  55. queue::push_back(_loaded, rr);
  56. }
  57. void ResourceLoader::get_loaded(Array<ResourceRequest>& loaded)
  58. {
  59. ScopedMutex sm(_loaded_mutex);
  60. const u32 num = queue::size(_loaded);
  61. array::reserve(loaded, num);
  62. for (u32 i = 0; i < num; ++i)
  63. {
  64. array::push_back(loaded, queue::front(_loaded));
  65. queue::pop_front(_loaded);
  66. }
  67. }
  68. void ResourceLoader::register_fallback(StringId64 type, StringId64 name)
  69. {
  70. hash_map::set(_fallback, type, name);
  71. }
  72. s32 ResourceLoader::run()
  73. {
  74. while (!_exit)
  75. {
  76. _mutex.lock();
  77. if (queue::empty(_requests))
  78. {
  79. _mutex.unlock();
  80. os::sleep(16);
  81. continue;
  82. }
  83. ResourceRequest rr = queue::front(_requests);
  84. _mutex.unlock();
  85. StringId64 mix;
  86. mix._id = rr.type._id ^ rr.name._id;
  87. TempAllocator128 ta;
  88. DynamicString res_path(ta);
  89. mix.to_string(res_path);
  90. DynamicString path(ta);
  91. path::join(path, CROWN_DATA_DIRECTORY, res_path.c_str());
  92. File* file = _data_filesystem.open(path.c_str(), FileOpenMode::READ);
  93. if (!file->is_open())
  94. {
  95. logw(RESOURCE_LOADER, "Can't load resource #ID(%s). Falling back...", res_path.c_str());
  96. StringId64 fallback_name;
  97. fallback_name = hash_map::get(_fallback, rr.type, fallback_name);
  98. CE_ENSURE(fallback_name._id != 0);
  99. mix._id = rr.type._id ^ fallback_name._id;
  100. mix.to_string(res_path);
  101. path::join(path, CROWN_DATA_DIRECTORY, res_path.c_str());
  102. _data_filesystem.close(*file);
  103. file = _data_filesystem.open(path.c_str(), FileOpenMode::READ);
  104. }
  105. CE_ASSERT(file->is_open(), "Can't load resource #ID(%s)", res_path.c_str());
  106. if (rr.load_function)
  107. {
  108. rr.data = rr.load_function(*file, *rr.allocator);
  109. }
  110. else
  111. {
  112. const u32 size = file->size();
  113. rr.data = rr.allocator->allocate(size);
  114. file->read(rr.data, size);
  115. CE_ASSERT(*(u32*)rr.data == rr.version, "Wrong version");
  116. }
  117. _data_filesystem.close(*file);
  118. add_loaded(rr);
  119. _mutex.lock();
  120. queue::pop_front(_requests);
  121. _mutex.unlock();
  122. }
  123. return 0;
  124. }
  125. } // namespace crown