vmo_buffer.cc 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "media/fuchsia/common/vmo_buffer.h"
  5. #include <zircon/rights.h>
  6. #include <algorithm>
  7. #include "base/bits.h"
  8. #include "base/fuchsia/fuchsia_logging.h"
  9. #include "base/memory/page_size.h"
  10. namespace media {
  11. // static
  12. fuchsia::sysmem::BufferCollectionConstraints
  13. VmoBuffer::GetRecommendedConstraints(size_t min_buffer_count,
  14. absl::optional<size_t> min_buffer_size,
  15. bool writable) {
  16. fuchsia::sysmem::BufferCollectionConstraints buffer_constraints;
  17. buffer_constraints.usage.cpu = fuchsia::sysmem::cpuUsageRead;
  18. if (writable)
  19. buffer_constraints.usage.cpu |= fuchsia::sysmem::cpuUsageWrite;
  20. buffer_constraints.min_buffer_count = min_buffer_count;
  21. if (min_buffer_size) {
  22. buffer_constraints.has_buffer_memory_constraints = true;
  23. buffer_constraints.buffer_memory_constraints.min_size_bytes =
  24. min_buffer_size.value();
  25. buffer_constraints.buffer_memory_constraints.ram_domain_supported = true;
  26. buffer_constraints.buffer_memory_constraints.cpu_domain_supported = true;
  27. }
  28. return buffer_constraints;
  29. }
  30. // static
  31. std::vector<VmoBuffer> VmoBuffer::CreateBuffersFromSysmemCollection(
  32. fuchsia::sysmem::BufferCollectionInfo_2* info,
  33. bool writable) {
  34. std::vector<VmoBuffer> buffers;
  35. buffers.resize(info->buffer_count);
  36. fuchsia::sysmem::BufferMemorySettings& settings =
  37. info->settings.buffer_settings;
  38. for (size_t i = 0; i < info->buffer_count; ++i) {
  39. fuchsia::sysmem::VmoBuffer& buffer = info->buffers[i];
  40. if (!buffers[i].Initialize(std::move(buffer.vmo), writable,
  41. buffer.vmo_usable_start, settings.size_bytes,
  42. settings.coherency_domain)) {
  43. return {};
  44. }
  45. }
  46. return buffers;
  47. }
  48. VmoBuffer::VmoBuffer() = default;
  49. VmoBuffer::~VmoBuffer() {
  50. if (!base_address_) {
  51. return;
  52. }
  53. zx_status_t status = zx::vmar::root_self()->unmap(
  54. reinterpret_cast<uintptr_t>(base_address_), mapped_size());
  55. ZX_DCHECK(status == ZX_OK, status) << "zx_vmar_unmap";
  56. }
  57. VmoBuffer::VmoBuffer(VmoBuffer&&) = default;
  58. VmoBuffer& VmoBuffer::operator=(VmoBuffer&&) = default;
  59. bool VmoBuffer::Initialize(zx::vmo vmo,
  60. bool writable,
  61. size_t offset,
  62. size_t size,
  63. fuchsia::sysmem::CoherencyDomain coherency_domain) {
  64. DCHECK(!base_address_);
  65. DCHECK(vmo);
  66. writable_ = writable;
  67. offset_ = offset;
  68. size_ = size;
  69. coherency_domain_ = coherency_domain;
  70. zx_vm_option_t options = ZX_VM_PERM_READ;
  71. if (writable)
  72. options |= ZX_VM_PERM_WRITE;
  73. uintptr_t addr;
  74. zx_status_t status =
  75. zx::vmar::root_self()->map(options, /*vmar_offset=*/0, vmo,
  76. /*vmo_offset=*/0, mapped_size(), &addr);
  77. if (status != ZX_OK) {
  78. ZX_DLOG(ERROR, status) << "zx_vmar_map";
  79. return false;
  80. }
  81. vmo_ = std::move(vmo);
  82. base_address_ = reinterpret_cast<uint8_t*>(addr);
  83. return true;
  84. }
  85. size_t VmoBuffer::Read(size_t offset, base::span<uint8_t> data) {
  86. if (offset >= size_)
  87. return 0U;
  88. size_t bytes_to_fill = std::min(size_ - offset, data.size());
  89. FlushCache(offset, bytes_to_fill, /*invalidate=*/true);
  90. memcpy(data.data(), base_address_ + offset_ + offset, bytes_to_fill);
  91. return bytes_to_fill;
  92. }
  93. size_t VmoBuffer::Write(base::span<const uint8_t> data) {
  94. DCHECK(writable_);
  95. size_t bytes_to_fill = std::min(size_, data.size());
  96. memcpy(base_address_ + offset_, data.data(), bytes_to_fill);
  97. FlushCache(0, bytes_to_fill, /*invalidate=*/false);
  98. return bytes_to_fill;
  99. }
  100. base::span<const uint8_t> VmoBuffer::GetMemory() {
  101. FlushCache(0, size_, /*invalidate=*/true);
  102. return base::make_span(base_address_ + offset_, size_);
  103. }
  104. base::span<uint8_t> VmoBuffer::GetWritableMemory() {
  105. DCHECK(writable_);
  106. return base::make_span(base_address_ + offset_, size_);
  107. }
  108. void VmoBuffer::FlushCache(size_t flush_offset,
  109. size_t flush_size,
  110. bool invalidate) {
  111. DCHECK_LE(flush_size, size_ - flush_offset);
  112. if (coherency_domain_ != fuchsia::sysmem::CoherencyDomain::RAM)
  113. return;
  114. uint8_t* address = base_address_ + offset_ + flush_offset;
  115. uint32_t options = ZX_CACHE_FLUSH_DATA;
  116. if (invalidate)
  117. options |= ZX_CACHE_FLUSH_INVALIDATE;
  118. zx_status_t status = zx_cache_flush(address, flush_size, options);
  119. ZX_DCHECK(status == ZX_OK, status) << "zx_cache_flush";
  120. }
  121. size_t VmoBuffer::mapped_size() {
  122. return base::bits::AlignUp(offset_ + size_, base::GetPageSize());
  123. }
  124. zx::vmo VmoBuffer::Duplicate(bool writable) {
  125. zx_rights_t rights = ZX_RIGHT_DUPLICATE | ZX_RIGHT_TRANSFER | ZX_RIGHT_READ |
  126. ZX_RIGHT_MAP | ZX_RIGHT_GET_PROPERTY;
  127. if (writable)
  128. rights |= ZX_RIGHT_WRITE;
  129. zx::vmo vmo;
  130. zx_status_t status = vmo_.duplicate(rights, &vmo);
  131. ZX_CHECK(status == ZX_OK, status) << "zx_handle_duplicate";
  132. return vmo;
  133. }
  134. } // namespace media