splitter_context.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. // Copyright 2020 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "audio_core/behavior_info.h"
  5. #include "audio_core/splitter_context.h"
  6. #include "common/alignment.h"
  7. #include "common/assert.h"
  8. #include "common/logging/log.h"
  9. namespace AudioCore {
  10. ServerSplitterDestinationData::ServerSplitterDestinationData(s32 id_) : id{id_} {}
  11. ServerSplitterDestinationData::~ServerSplitterDestinationData() = default;
  12. void ServerSplitterDestinationData::Update(SplitterInfo::InDestinationParams& header) {
  13. // Log error as these are not actually failure states
  14. if (header.magic != SplitterMagic::DataHeader) {
  15. LOG_ERROR(Audio, "Splitter destination header is invalid!");
  16. return;
  17. }
  18. // Incorrect splitter id
  19. if (header.splitter_id != id) {
  20. LOG_ERROR(Audio, "Splitter destination ids do not match!");
  21. return;
  22. }
  23. mix_id = header.mix_id;
  24. // Copy our mix volumes
  25. std::copy(header.mix_volumes.begin(), header.mix_volumes.end(), current_mix_volumes.begin());
  26. if (!in_use && header.in_use) {
  27. // Update mix volumes
  28. std::copy(current_mix_volumes.begin(), current_mix_volumes.end(), last_mix_volumes.begin());
  29. needs_update = false;
  30. }
  31. in_use = header.in_use;
  32. }
  33. ServerSplitterDestinationData* ServerSplitterDestinationData::GetNextDestination() {
  34. return next;
  35. }
  36. const ServerSplitterDestinationData* ServerSplitterDestinationData::GetNextDestination() const {
  37. return next;
  38. }
  39. void ServerSplitterDestinationData::SetNextDestination(ServerSplitterDestinationData* dest) {
  40. next = dest;
  41. }
  42. bool ServerSplitterDestinationData::ValidMixId() const {
  43. return GetMixId() != AudioCommon::NO_MIX;
  44. }
  45. s32 ServerSplitterDestinationData::GetMixId() const {
  46. return mix_id;
  47. }
  48. bool ServerSplitterDestinationData::IsConfigured() const {
  49. return in_use && ValidMixId();
  50. }
  51. float ServerSplitterDestinationData::GetMixVolume(std::size_t i) const {
  52. ASSERT(i < AudioCommon::MAX_MIX_BUFFERS);
  53. return current_mix_volumes.at(i);
  54. }
  55. const std::array<float, AudioCommon::MAX_MIX_BUFFERS>&
  56. ServerSplitterDestinationData::CurrentMixVolumes() const {
  57. return current_mix_volumes;
  58. }
  59. const std::array<float, AudioCommon::MAX_MIX_BUFFERS>&
  60. ServerSplitterDestinationData::LastMixVolumes() const {
  61. return last_mix_volumes;
  62. }
  63. void ServerSplitterDestinationData::MarkDirty() {
  64. needs_update = true;
  65. }
  66. void ServerSplitterDestinationData::UpdateInternalState() {
  67. if (in_use && needs_update) {
  68. std::copy(current_mix_volumes.begin(), current_mix_volumes.end(), last_mix_volumes.begin());
  69. }
  70. needs_update = false;
  71. }
  72. ServerSplitterInfo::ServerSplitterInfo(s32 id_) : id(id_) {}
  73. ServerSplitterInfo::~ServerSplitterInfo() = default;
  74. void ServerSplitterInfo::InitializeInfos() {
  75. send_length = 0;
  76. head = nullptr;
  77. new_connection = true;
  78. }
  79. void ServerSplitterInfo::ClearNewConnectionFlag() {
  80. new_connection = false;
  81. }
  82. std::size_t ServerSplitterInfo::Update(SplitterInfo::InInfoPrams& header) {
  83. if (header.send_id != id) {
  84. return 0;
  85. }
  86. sample_rate = header.sample_rate;
  87. new_connection = true;
  88. // We need to update the size here due to the splitter bug being present and providing an
  89. // incorrect size. We're suppose to also update the header here but we just ignore and continue
  90. return (sizeof(s32_le) * (header.length - 1)) + (sizeof(s32_le) * 3);
  91. }
  92. ServerSplitterDestinationData* ServerSplitterInfo::GetHead() {
  93. return head;
  94. }
  95. const ServerSplitterDestinationData* ServerSplitterInfo::GetHead() const {
  96. return head;
  97. }
  98. ServerSplitterDestinationData* ServerSplitterInfo::GetData(std::size_t depth) {
  99. auto* current_head = head;
  100. for (std::size_t i = 0; i < depth; i++) {
  101. if (current_head == nullptr) {
  102. return nullptr;
  103. }
  104. current_head = current_head->GetNextDestination();
  105. }
  106. return current_head;
  107. }
  108. const ServerSplitterDestinationData* ServerSplitterInfo::GetData(std::size_t depth) const {
  109. auto* current_head = head;
  110. for (std::size_t i = 0; i < depth; i++) {
  111. if (current_head == nullptr) {
  112. return nullptr;
  113. }
  114. current_head = current_head->GetNextDestination();
  115. }
  116. return current_head;
  117. }
  118. bool ServerSplitterInfo::HasNewConnection() const {
  119. return new_connection;
  120. }
  121. s32 ServerSplitterInfo::GetLength() const {
  122. return send_length;
  123. }
  124. void ServerSplitterInfo::SetHead(ServerSplitterDestinationData* new_head) {
  125. head = new_head;
  126. }
  127. void ServerSplitterInfo::SetHeadDepth(s32 length) {
  128. send_length = length;
  129. }
  130. SplitterContext::SplitterContext() = default;
  131. SplitterContext::~SplitterContext() = default;
  132. void SplitterContext::Initialize(BehaviorInfo& behavior_info, std::size_t _info_count,
  133. std::size_t _data_count) {
  134. if (!behavior_info.IsSplitterSupported() || _data_count == 0 || _info_count == 0) {
  135. Setup(0, 0, false);
  136. return;
  137. }
  138. // Only initialize if we're using splitters
  139. Setup(_info_count, _data_count, behavior_info.IsSplitterBugFixed());
  140. }
  141. bool SplitterContext::Update(const std::vector<u8>& input, std::size_t& input_offset,
  142. std::size_t& bytes_read) {
  143. const auto UpdateOffsets = [&](std::size_t read) {
  144. input_offset += read;
  145. bytes_read += read;
  146. };
  147. if (info_count == 0 || data_count == 0) {
  148. bytes_read = 0;
  149. return true;
  150. }
  151. if (!AudioCommon::CanConsumeBuffer(input.size(), input_offset,
  152. sizeof(SplitterInfo::InHeader))) {
  153. LOG_ERROR(Audio, "Buffer is an invalid size!");
  154. return false;
  155. }
  156. SplitterInfo::InHeader header{};
  157. std::memcpy(&header, input.data() + input_offset, sizeof(SplitterInfo::InHeader));
  158. UpdateOffsets(sizeof(SplitterInfo::InHeader));
  159. if (header.magic != SplitterMagic::SplitterHeader) {
  160. LOG_ERROR(Audio, "Invalid header magic! Expecting {:X} but got {:X}",
  161. SplitterMagic::SplitterHeader, header.magic);
  162. return false;
  163. }
  164. // Clear all connections
  165. for (auto& info : infos) {
  166. info.ClearNewConnectionFlag();
  167. }
  168. UpdateInfo(input, input_offset, bytes_read, header.info_count);
  169. UpdateData(input, input_offset, bytes_read, header.data_count);
  170. const auto aligned_bytes_read = Common::AlignUp(bytes_read, 16);
  171. input_offset += aligned_bytes_read - bytes_read;
  172. bytes_read = aligned_bytes_read;
  173. return true;
  174. }
  175. bool SplitterContext::UsingSplitter() const {
  176. return info_count > 0 && data_count > 0;
  177. }
  178. ServerSplitterInfo& SplitterContext::GetInfo(std::size_t i) {
  179. ASSERT(i < info_count);
  180. return infos.at(i);
  181. }
  182. const ServerSplitterInfo& SplitterContext::GetInfo(std::size_t i) const {
  183. ASSERT(i < info_count);
  184. return infos.at(i);
  185. }
  186. ServerSplitterDestinationData& SplitterContext::GetData(std::size_t i) {
  187. ASSERT(i < data_count);
  188. return datas.at(i);
  189. }
  190. const ServerSplitterDestinationData& SplitterContext::GetData(std::size_t i) const {
  191. ASSERT(i < data_count);
  192. return datas.at(i);
  193. }
  194. ServerSplitterDestinationData* SplitterContext::GetDestinationData(std::size_t info,
  195. std::size_t data) {
  196. ASSERT(info < info_count);
  197. auto& cur_info = GetInfo(info);
  198. return cur_info.GetData(data);
  199. }
  200. const ServerSplitterDestinationData* SplitterContext::GetDestinationData(std::size_t info,
  201. std::size_t data) const {
  202. ASSERT(info < info_count);
  203. const auto& cur_info = GetInfo(info);
  204. return cur_info.GetData(data);
  205. }
  206. void SplitterContext::UpdateInternalState() {
  207. if (data_count == 0) {
  208. return;
  209. }
  210. for (auto& data : datas) {
  211. data.UpdateInternalState();
  212. }
  213. }
  214. std::size_t SplitterContext::GetInfoCount() const {
  215. return info_count;
  216. }
  217. std::size_t SplitterContext::GetDataCount() const {
  218. return data_count;
  219. }
  220. void SplitterContext::Setup(std::size_t info_count_, std::size_t data_count_,
  221. bool is_splitter_bug_fixed) {
  222. info_count = info_count_;
  223. data_count = data_count_;
  224. for (std::size_t i = 0; i < info_count; i++) {
  225. auto& splitter = infos.emplace_back(static_cast<s32>(i));
  226. splitter.InitializeInfos();
  227. }
  228. for (std::size_t i = 0; i < data_count; i++) {
  229. datas.emplace_back(static_cast<s32>(i));
  230. }
  231. bug_fixed = is_splitter_bug_fixed;
  232. }
  233. bool SplitterContext::UpdateInfo(const std::vector<u8>& input, std::size_t& input_offset,
  234. std::size_t& bytes_read, s32 in_splitter_count) {
  235. const auto UpdateOffsets = [&](std::size_t read) {
  236. input_offset += read;
  237. bytes_read += read;
  238. };
  239. for (s32 i = 0; i < in_splitter_count; i++) {
  240. if (!AudioCommon::CanConsumeBuffer(input.size(), input_offset,
  241. sizeof(SplitterInfo::InInfoPrams))) {
  242. LOG_ERROR(Audio, "Buffer is an invalid size!");
  243. return false;
  244. }
  245. SplitterInfo::InInfoPrams header{};
  246. std::memcpy(&header, input.data() + input_offset, sizeof(SplitterInfo::InInfoPrams));
  247. // Logged as warning as these don't actually cause a bailout for some reason
  248. if (header.magic != SplitterMagic::InfoHeader) {
  249. LOG_ERROR(Audio, "Bad splitter data header");
  250. break;
  251. }
  252. if (header.send_id < 0 || static_cast<std::size_t>(header.send_id) > info_count) {
  253. LOG_ERROR(Audio, "Bad splitter data id");
  254. break;
  255. }
  256. UpdateOffsets(sizeof(SplitterInfo::InInfoPrams));
  257. auto& info = GetInfo(header.send_id);
  258. if (!RecomposeDestination(info, header, input, input_offset)) {
  259. LOG_ERROR(Audio, "Failed to recompose destination for splitter!");
  260. return false;
  261. }
  262. const std::size_t read = info.Update(header);
  263. bytes_read += read;
  264. input_offset += read;
  265. }
  266. return true;
  267. }
  268. bool SplitterContext::UpdateData(const std::vector<u8>& input, std::size_t& input_offset,
  269. std::size_t& bytes_read, s32 in_data_count) {
  270. const auto UpdateOffsets = [&](std::size_t read) {
  271. input_offset += read;
  272. bytes_read += read;
  273. };
  274. for (s32 i = 0; i < in_data_count; i++) {
  275. if (!AudioCommon::CanConsumeBuffer(input.size(), input_offset,
  276. sizeof(SplitterInfo::InDestinationParams))) {
  277. LOG_ERROR(Audio, "Buffer is an invalid size!");
  278. return false;
  279. }
  280. SplitterInfo::InDestinationParams header{};
  281. std::memcpy(&header, input.data() + input_offset,
  282. sizeof(SplitterInfo::InDestinationParams));
  283. UpdateOffsets(sizeof(SplitterInfo::InDestinationParams));
  284. // Logged as warning as these don't actually cause a bailout for some reason
  285. if (header.magic != SplitterMagic::DataHeader) {
  286. LOG_ERROR(Audio, "Bad splitter data header");
  287. break;
  288. }
  289. if (header.splitter_id < 0 || static_cast<std::size_t>(header.splitter_id) > data_count) {
  290. LOG_ERROR(Audio, "Bad splitter data id");
  291. break;
  292. }
  293. GetData(header.splitter_id).Update(header);
  294. }
  295. return true;
  296. }
  297. bool SplitterContext::RecomposeDestination(ServerSplitterInfo& info,
  298. SplitterInfo::InInfoPrams& header,
  299. const std::vector<u8>& input,
  300. const std::size_t& input_offset) {
  301. // Clear our current destinations
  302. auto* current_head = info.GetHead();
  303. while (current_head != nullptr) {
  304. auto* next_head = current_head->GetNextDestination();
  305. current_head->SetNextDestination(nullptr);
  306. current_head = next_head;
  307. }
  308. info.SetHead(nullptr);
  309. s32 size = header.length;
  310. // If the splitter bug is present, calculate fixed size
  311. if (!bug_fixed) {
  312. if (info_count > 0) {
  313. const auto factor = data_count / info_count;
  314. size = std::min(header.length, static_cast<s32>(factor));
  315. } else {
  316. size = 0;
  317. }
  318. }
  319. if (size < 1) {
  320. LOG_ERROR(Audio, "Invalid splitter info size! size={:X}", size);
  321. return true;
  322. }
  323. auto* start_head = &GetData(header.resource_id_base);
  324. current_head = start_head;
  325. std::vector<s32_le> resource_ids(size - 1);
  326. if (!AudioCommon::CanConsumeBuffer(input.size(), input_offset,
  327. resource_ids.size() * sizeof(s32_le))) {
  328. LOG_ERROR(Audio, "Buffer is an invalid size!");
  329. return false;
  330. }
  331. std::memcpy(resource_ids.data(), input.data() + input_offset,
  332. resource_ids.size() * sizeof(s32_le));
  333. for (auto resource_id : resource_ids) {
  334. auto* head = &GetData(resource_id);
  335. current_head->SetNextDestination(head);
  336. current_head = head;
  337. }
  338. info.SetHead(start_head);
  339. info.SetHeadDepth(size);
  340. return true;
  341. }
  342. NodeStates::NodeStates() = default;
  343. NodeStates::~NodeStates() = default;
  344. void NodeStates::Initialize(std::size_t node_count_) {
  345. // Setup our work parameters
  346. node_count = node_count_;
  347. was_node_found.resize(node_count);
  348. was_node_completed.resize(node_count);
  349. index_list.resize(node_count);
  350. index_stack.Reset(node_count * node_count);
  351. }
  352. bool NodeStates::Tsort(EdgeMatrix& edge_matrix) {
  353. return DepthFirstSearch(edge_matrix);
  354. }
  355. std::size_t NodeStates::GetIndexPos() const {
  356. return index_pos;
  357. }
  358. const std::vector<s32>& NodeStates::GetIndexList() const {
  359. return index_list;
  360. }
  361. void NodeStates::PushTsortResult(s32 index) {
  362. ASSERT(index < static_cast<s32>(node_count));
  363. index_list[index_pos++] = index;
  364. }
  365. bool NodeStates::DepthFirstSearch(EdgeMatrix& edge_matrix) {
  366. ResetState();
  367. for (std::size_t i = 0; i < node_count; i++) {
  368. const auto node_id = static_cast<s32>(i);
  369. // If we don't have a state, send to our index stack for work
  370. if (GetState(i) == NodeStates::State::NoState) {
  371. index_stack.push(node_id);
  372. }
  373. // While we have work to do in our stack
  374. while (index_stack.Count() > 0) {
  375. // Get the current node
  376. const auto current_stack_index = index_stack.top();
  377. // Check if we've seen the node yet
  378. const auto index_state = GetState(current_stack_index);
  379. if (index_state == NodeStates::State::NoState) {
  380. // Mark the node as seen
  381. UpdateState(NodeStates::State::InFound, current_stack_index);
  382. } else if (index_state == NodeStates::State::InFound) {
  383. // We've seen this node before, mark it as completed
  384. UpdateState(NodeStates::State::InCompleted, current_stack_index);
  385. // Update our index list
  386. PushTsortResult(current_stack_index);
  387. // Pop the stack
  388. index_stack.pop();
  389. continue;
  390. } else if (index_state == NodeStates::State::InCompleted) {
  391. // If our node is already sorted, clear it
  392. index_stack.pop();
  393. continue;
  394. }
  395. const auto edge_node_count = edge_matrix.GetNodeCount();
  396. for (s32 j = 0; j < static_cast<s32>(edge_node_count); j++) {
  397. // Check if our node is connected to our edge matrix
  398. if (!edge_matrix.Connected(current_stack_index, j)) {
  399. continue;
  400. }
  401. // Check if our node exists
  402. const auto node_state = GetState(j);
  403. if (node_state == NodeStates::State::NoState) {
  404. // Add more work
  405. index_stack.push(j);
  406. } else if (node_state == NodeStates::State::InFound) {
  407. UNREACHABLE_MSG("Node start marked as found");
  408. ResetState();
  409. return false;
  410. }
  411. }
  412. }
  413. }
  414. return true;
  415. }
  416. void NodeStates::ResetState() {
  417. // Reset to the start of our index stack
  418. index_pos = 0;
  419. for (std::size_t i = 0; i < node_count; i++) {
  420. // Mark all nodes as not found
  421. was_node_found[i] = false;
  422. // Mark all nodes as uncompleted
  423. was_node_completed[i] = false;
  424. // Mark all indexes as invalid
  425. index_list[i] = -1;
  426. }
  427. }
  428. void NodeStates::UpdateState(NodeStates::State state, std::size_t i) {
  429. switch (state) {
  430. case NodeStates::State::NoState:
  431. was_node_found[i] = false;
  432. was_node_completed[i] = false;
  433. break;
  434. case NodeStates::State::InFound:
  435. was_node_found[i] = true;
  436. was_node_completed[i] = false;
  437. break;
  438. case NodeStates::State::InCompleted:
  439. was_node_found[i] = false;
  440. was_node_completed[i] = true;
  441. break;
  442. }
  443. }
  444. NodeStates::State NodeStates::GetState(std::size_t i) {
  445. ASSERT(i < node_count);
  446. if (was_node_found[i]) {
  447. // If our node exists in our found list
  448. return NodeStates::State::InFound;
  449. } else if (was_node_completed[i]) {
  450. // If node is in the completed list
  451. return NodeStates::State::InCompleted;
  452. } else {
  453. // If in neither
  454. return NodeStates::State::NoState;
  455. }
  456. }
  457. NodeStates::Stack::Stack() = default;
  458. NodeStates::Stack::~Stack() = default;
  459. void NodeStates::Stack::Reset(std::size_t size) {
  460. // Mark our stack as empty
  461. stack.resize(size);
  462. stack_size = size;
  463. stack_pos = 0;
  464. std::fill(stack.begin(), stack.end(), 0);
  465. }
  466. void NodeStates::Stack::push(s32 val) {
  467. ASSERT(stack_pos < stack_size);
  468. stack[stack_pos++] = val;
  469. }
  470. std::size_t NodeStates::Stack::Count() const {
  471. return stack_pos;
  472. }
  473. s32 NodeStates::Stack::top() const {
  474. ASSERT(stack_pos > 0);
  475. return stack[stack_pos - 1];
  476. }
  477. s32 NodeStates::Stack::pop() {
  478. ASSERT(stack_pos > 0);
  479. stack_pos--;
  480. return stack[stack_pos];
  481. }
  482. EdgeMatrix::EdgeMatrix() = default;
  483. EdgeMatrix::~EdgeMatrix() = default;
  484. void EdgeMatrix::Initialize(std::size_t _node_count) {
  485. node_count = _node_count;
  486. edge_matrix.resize(node_count * node_count);
  487. }
  488. bool EdgeMatrix::Connected(s32 a, s32 b) {
  489. return GetState(a, b);
  490. }
  491. void EdgeMatrix::Connect(s32 a, s32 b) {
  492. SetState(a, b, true);
  493. }
  494. void EdgeMatrix::Disconnect(s32 a, s32 b) {
  495. SetState(a, b, false);
  496. }
  497. void EdgeMatrix::RemoveEdges(s32 edge) {
  498. for (std::size_t i = 0; i < node_count; i++) {
  499. SetState(edge, static_cast<s32>(i), false);
  500. }
  501. }
  502. std::size_t EdgeMatrix::GetNodeCount() const {
  503. return node_count;
  504. }
  505. void EdgeMatrix::SetState(s32 a, s32 b, bool state) {
  506. ASSERT(InRange(a, b));
  507. edge_matrix.at(a * node_count + b) = state;
  508. }
  509. bool EdgeMatrix::GetState(s32 a, s32 b) {
  510. ASSERT(InRange(a, b));
  511. return edge_matrix.at(a * node_count + b);
  512. }
  513. bool EdgeMatrix::InRange(s32 a, s32 b) const {
  514. const std::size_t pos = a * node_count + b;
  515. return pos < (node_count * node_count);
  516. }
  517. } // namespace AudioCore