resource_loader.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /*
  2. * Copyright (c) 2012-2020 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.inl"
  7. #include "core/containers/queue.inl"
  8. #include "core/filesystem/file.h"
  9. #include "core/filesystem/filesystem.h"
  10. #include "core/filesystem/path.h"
  11. #include "core/memory/globals.h"
  12. #include "core/memory/temp_allocator.inl"
  13. #include "core/os.h"
  14. #include "core/strings/dynamic_string.inl"
  15. #include "core/strings/string_id.inl"
  16. #include "core/thread/scoped_mutex.inl"
  17. #include "device/log.h"
  18. #include "resource/resource_id.inl"
  19. #include "resource/resource_loader.h"
  20. #include "resource/types.h"
  21. LOG_SYSTEM(RESOURCE_LOADER, "resource_loader")
  22. namespace crown
  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([](void* thiz) { return ((ResourceLoader*)thiz)->run(); }, this);
  32. }
  33. ResourceLoader::~ResourceLoader()
  34. {
  35. _exit = true;
  36. _requests_condition.signal(); // Spurious wake to exit thread
  37. _thread.stop();
  38. }
  39. void ResourceLoader::add_request(const ResourceRequest& rr)
  40. {
  41. ScopedMutex sm(_mutex);
  42. queue::push_back(_requests, rr);
  43. _requests_condition.signal();
  44. }
  45. void ResourceLoader::flush()
  46. {
  47. while (num_requests()) {}
  48. }
  49. u32 ResourceLoader::num_requests()
  50. {
  51. ScopedMutex sm(_mutex);
  52. return queue::size(_requests);
  53. }
  54. void ResourceLoader::add_loaded(ResourceRequest rr)
  55. {
  56. ScopedMutex sm(_loaded_mutex);
  57. queue::push_back(_loaded, rr);
  58. }
  59. void ResourceLoader::get_loaded(Array<ResourceRequest>& loaded)
  60. {
  61. ScopedMutex sm(_loaded_mutex);
  62. const u32 num = queue::size(_loaded);
  63. array::reserve(loaded, num);
  64. for (u32 i = 0; i < num; ++i)
  65. {
  66. array::push_back(loaded, queue::front(_loaded));
  67. queue::pop_front(_loaded);
  68. }
  69. }
  70. void ResourceLoader::register_fallback(StringId64 type, StringId64 name)
  71. {
  72. hash_map::set(_fallback, type, name);
  73. }
  74. s32 ResourceLoader::run()
  75. {
  76. while (1)
  77. {
  78. _mutex.lock();
  79. while (queue::empty(_requests) && !_exit)
  80. _requests_condition.wait(_mutex);
  81. if (_exit)
  82. break;
  83. ResourceRequest rr = queue::front(_requests);
  84. _mutex.unlock();
  85. ResourceId res_id = resource_id(rr.type, rr.name);
  86. TempAllocator128 ta;
  87. DynamicString path(ta);
  88. destination_path(path, res_id);
  89. File* file = _data_filesystem.open(path.c_str(), FileOpenMode::READ);
  90. if (!file->is_open())
  91. {
  92. logw(RESOURCE_LOADER, "Can't load resource: " RESOURCE_ID_FMT ". Falling back...", res_id._id);
  93. StringId64 fallback_name;
  94. fallback_name = hash_map::get(_fallback, rr.type, fallback_name);
  95. CE_ENSURE(fallback_name._id != 0);
  96. res_id = resource_id(rr.type, fallback_name);
  97. destination_path(path, res_id);
  98. _data_filesystem.close(*file);
  99. file = _data_filesystem.open(path.c_str(), FileOpenMode::READ);
  100. }
  101. CE_ASSERT(file->is_open(), "Can't load resource: " RESOURCE_ID_FMT, res_id._id);
  102. if (rr.load_function)
  103. {
  104. rr.data = rr.load_function(*file, *rr.allocator);
  105. }
  106. else
  107. {
  108. const u32 size = file->size();
  109. rr.data = rr.allocator->allocate(size, 16);
  110. file->read(rr.data, size);
  111. CE_ASSERT(*(u32*)rr.data == RESOURCE_HEADER(rr.version), "Wrong version");
  112. }
  113. _data_filesystem.close(*file);
  114. add_loaded(rr);
  115. _mutex.lock();
  116. queue::pop_front(_requests);
  117. _mutex.unlock();
  118. }
  119. _mutex.unlock();
  120. return 0;
  121. }
  122. } // namespace crown