Deprecate SharedMemoryRegion memory(), replace it with data() and spans
The accessor returns an unbounded void* which is dangerous to use. Callers should instead use GetMemoryAsSpan() or GetMemoryAs(). To ease this we introduce `uint8_t* data()` which allows SharedMemoryMappings to convert implicitly or explicitly to base::span<uint8_t>. We enable unsafe-buffer-usage warning in the shared memory unit tests, which mostly required changing tests to use span apis instead of working with the unbounded pointer accessor. The span apis return the same pointer but with a length attached. Other code is changed to span(mapping), GetMemoryAsSpan() or GetMemoryAs(). These require the types being pulled out of shared memory are trivially copyable. However a couple classes used in this way in devices were _not_ trivially copyable. This can cause UB. These classes wanted to be trivially copyable but could not be because of the out-of-line ctor requirements of the chromium clang plugin. So we template these and use a type alias to avoid rewriting 1000 LOC with useless template arguments. This works around the clang plugin for now. R=lukasza@chromium.org Bug: 40284755, 355003174 Change-Id: Id7fd4c9bcf0b86b8109134c18740453bb24aa5de Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5734584 Reviewed-by: James Cook <jamescook@chromium.org> Reviewed-by: Łukasz Anforowicz <lukasza@chromium.org> Reviewed-by: Khushal Sagar <khushalsagar@chromium.org> Reviewed-by: Daniel Cheng <dcheng@chromium.org> Reviewed-by: Alex Moshchuk <alexmos@chromium.org> Reviewed-by: Avi Drissman <avi@chromium.org> Owners-Override: Daniel Cheng <dcheng@chromium.org> Commit-Queue: danakj <danakj@chromium.org> Reviewed-by: Reilly Grant <reillyg@chromium.org> Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com> Reviewed-by: Jonathan Ross <jonross@chromium.org> Cr-Commit-Position: refs/heads/main@{#1333755}
This commit is contained in:
ash/webui/camera_app_ui
base
android
library_loader
memory
discardable_shared_memory.ccplatform_shared_memory_region_unittest.ccread_only_shared_memory_region.ccshared_memory_mapping.hshared_memory_region_unittest.cc
trace_event
cc
chrome/browser
ash
app_list
search
local_image_search
extensions
file_manager
devtools
enterprise
content
browser
android
devtools
font_access
font_unique_name_lookup
renderer_host
renderer
device
gamepad
public
vr
mojo
core
public
cpp
services
audio
device
generic_sensor
platform_sensor.hplatform_sensor_and_provider_unittest.ccplatform_sensor_and_provider_unittest_linux.ccplatform_sensor_and_provider_unittest_win.ccplatform_sensor_provider.ccsensor_provider_impl.cc
public
test
echo
tracing
third_party/blink
common
font_unique_name_lookup
renderer
modules
font_access
gamepad
gamepad_dispatcher.hgamepad_listener.hgamepad_shared_memory_reader.ccgamepad_shared_memory_reader.hnavigator_gamepad.h
xr
platform
ui/ozone
common
platform
wayland
@ -411,7 +411,7 @@ void CameraAppHelperImpl::ScanDocumentCorners(
|
||||
std::move(callback).Run({});
|
||||
return;
|
||||
}
|
||||
memcpy(memory.mapping.memory(), jpeg_data.data(), jpeg_data.size());
|
||||
base::span(memory.mapping).copy_from(jpeg_data);
|
||||
|
||||
// Since |this| owns |document_scanner_service|, and the callback will be
|
||||
// posted to other sequence with weak pointer of |document_scanner_service|.
|
||||
@ -441,7 +441,7 @@ void CameraAppHelperImpl::ConvertToDocument(
|
||||
std::move(callback).Run({});
|
||||
return;
|
||||
}
|
||||
memcpy(memory.mapping.memory(), jpeg_data.data(), jpeg_data.size());
|
||||
base::span(memory.mapping).copy_from(jpeg_data);
|
||||
|
||||
// Since |this| owns |document_scanner_service|, and the callback will be
|
||||
// posted to other sequence with weak pointer of |document_scanner_service|.
|
||||
|
@ -29,18 +29,22 @@ TEST(NativeLibraryPrefetcherTest, DISABLED_TestPercentageOfResidentCode) {
|
||||
ASSERT_TRUE(shared_region.IsValid());
|
||||
auto mapping = shared_region.Map();
|
||||
ASSERT_TRUE(mapping.IsValid());
|
||||
void* address = mapping.memory();
|
||||
size_t start = reinterpret_cast<size_t>(address);
|
||||
size_t end = start + length;
|
||||
// SAFETY: There's no public way to get a span of the full mapped memory size.
|
||||
// The `mapped_size()` is larger then `size()` but is the actual size of the
|
||||
// shared memory backing.
|
||||
span<uint8_t> memory =
|
||||
UNSAFE_BUFFERS(base::span(mapping.data(), mapping.mapped_size()));
|
||||
auto start = reinterpret_cast<uintptr_t>(&*memory.begin());
|
||||
auto end = reinterpret_cast<uintptr_t>(&*memory.end());
|
||||
|
||||
// Remove everything.
|
||||
ASSERT_EQ(0, madvise(address, length, MADV_DONTNEED));
|
||||
ASSERT_EQ(0, madvise(memory.data(), memory.size(), MADV_DONTNEED));
|
||||
EXPECT_EQ(0, NativeLibraryPrefetcher::PercentageOfResidentCode(start, end));
|
||||
|
||||
// Get everything back.
|
||||
ASSERT_EQ(0, mlock(address, length));
|
||||
ASSERT_EQ(0, mlock(memory.data(), memory.size()));
|
||||
EXPECT_EQ(100, NativeLibraryPrefetcher::PercentageOfResidentCode(start, end));
|
||||
munlock(address, length);
|
||||
munlock(memory.data(), memory.size());
|
||||
}
|
||||
#endif // !defined(ADDRESS_SANITIZER)
|
||||
|
||||
|
@ -115,7 +115,7 @@ struct SharedState {
|
||||
SharedState* SharedStateFromSharedMemory(
|
||||
const WritableSharedMemoryMapping& shared_memory) {
|
||||
DCHECK(shared_memory.IsValid());
|
||||
return static_cast<SharedState*>(shared_memory.memory());
|
||||
return shared_memory.GetMemoryAs<SharedState>();
|
||||
}
|
||||
|
||||
// Round up |size| to a multiple of page size.
|
||||
|
@ -308,11 +308,17 @@ TEST_F(PlatformSharedMemoryRegionTest, MappingProtectionSetCorrectly) {
|
||||
ASSERT_TRUE(region.ConvertToReadOnly());
|
||||
WritableSharedMemoryMapping ro_mapping = MapForTesting(®ion);
|
||||
ASSERT_TRUE(ro_mapping.IsValid());
|
||||
CheckReadOnlyMapProtection(ro_mapping.memory());
|
||||
CheckReadOnlyMapProtection(ro_mapping.data());
|
||||
|
||||
EXPECT_FALSE(TryToRestoreWritablePermissions(ro_mapping.memory(),
|
||||
ro_mapping.mapped_size()));
|
||||
CheckReadOnlyMapProtection(ro_mapping.memory());
|
||||
// SAFETY: There's no public way to get a span of the full mapped memory size.
|
||||
// The `mapped_size()` is larger then `size()` but is the actual size of the
|
||||
// shared memory backing.
|
||||
auto full_map_mem =
|
||||
UNSAFE_BUFFERS(span(ro_mapping.data(), ro_mapping.mapped_size()));
|
||||
EXPECT_FALSE(TryToRestoreWritablePermissions(full_map_mem.data(),
|
||||
full_map_mem.size()));
|
||||
|
||||
CheckReadOnlyMapProtection(ro_mapping.data());
|
||||
}
|
||||
|
||||
// Tests that platform handle permissions are checked correctly.
|
||||
|
@ -32,7 +32,7 @@ MappedReadOnlyRegion ReadOnlySharedMemoryRegion::Create(
|
||||
WritableSharedMemoryMapping mapping(result.value(), size, handle.GetGUID(),
|
||||
mapper);
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
handle.ConvertToReadOnly(mapping.memory());
|
||||
handle.ConvertToReadOnly(mapping.data());
|
||||
#else
|
||||
handle.ConvertToReadOnly();
|
||||
#endif // BUILDFLAG(IS_MAC)
|
||||
|
@ -74,6 +74,7 @@ class BASE_EXPORT SharedMemoryMapping {
|
||||
size_t size,
|
||||
const UnguessableToken& guid,
|
||||
SharedMemoryMapper* mapper);
|
||||
|
||||
// Returns a span over the full mapped memory.
|
||||
span<uint8_t> mapped_memory() const { return mapped_span_; }
|
||||
|
||||
@ -107,7 +108,17 @@ class BASE_EXPORT ReadOnlySharedMemoryMapping : public SharedMemoryMapping {
|
||||
|
||||
// Returns the base address of the read-only mapping. Returns nullptr for
|
||||
// invalid instances.
|
||||
const void* memory() const { return mapped_memory().data(); }
|
||||
//
|
||||
// Use `span(mapping)` to make a span of `uint8_t`, `GetMemoryAs<T>()` to
|
||||
// access the memory as a single `T` or `GetMemoryAsSpan<T>()` to access it as
|
||||
// an array of `T`.
|
||||
const uint8_t* data() const { return mapped_memory().data(); }
|
||||
|
||||
// TODO(crbug.com/355451178): Deprecated. Use `span(mapping)` to make a span
|
||||
// of `uint8_t`, `GetMemoryAs<T>()` to access the memory as a single `T` or
|
||||
// `GetMemoryAsSpan<T>()` to access it as an array of `T`, or `data()` for an
|
||||
// unbounded pointer.
|
||||
const void* memory() const { return data(); }
|
||||
|
||||
// Returns a pointer to a page-aligned const T if the mapping is valid and
|
||||
// large enough to contain a T, or nullptr otherwise.
|
||||
@ -187,7 +198,17 @@ class BASE_EXPORT WritableSharedMemoryMapping : public SharedMemoryMapping {
|
||||
|
||||
// Returns the base address of the writable mapping. Returns nullptr for
|
||||
// invalid instances.
|
||||
void* memory() const { return mapped_memory().data(); }
|
||||
//
|
||||
// Use `span(mapping)` to make a span of `uint8_t`, `GetMemoryAs<T>()` to
|
||||
// access the memory as a single `T` or `GetMemoryAsSpan<T>()` to access it as
|
||||
// an array of `T`.
|
||||
uint8_t* data() const { return mapped_memory().data(); }
|
||||
|
||||
// TODO(crbug.com/355451178): Deprecated. Use `span(mapping)` to make a span
|
||||
// of `uint8_t`, `GetMemoryAs<T>()` to access the memory as a single `T`, or
|
||||
// `GetMemoryAsSpan<T>()` to access it as an array of `T` or `data()` for an
|
||||
// unbounded pointer.
|
||||
void* memory() const { return data(); }
|
||||
|
||||
// Returns a pointer to a page-aligned T if the mapping is valid and large
|
||||
// enough to contain a T, or nullptr otherwise.
|
||||
|
@ -2,13 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifdef UNSAFE_BUFFERS_BUILD
|
||||
// TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
|
||||
#pragma allow_unsafe_buffers
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include "base/containers/span.h"
|
||||
#include "base/memory/platform_shared_memory_region.h"
|
||||
#include "base/memory/read_only_shared_memory_region.h"
|
||||
#include "base/memory/unsafe_shared_memory_region.h"
|
||||
@ -22,14 +19,12 @@ namespace base {
|
||||
|
||||
const size_t kRegionSize = 1024;
|
||||
|
||||
bool IsMemoryFilledWithByte(const void* memory, size_t size, char byte) {
|
||||
const char* start_ptr = static_cast<const char*>(memory);
|
||||
const char* end_ptr = start_ptr + size;
|
||||
for (const char* ptr = start_ptr; ptr < end_ptr; ++ptr) {
|
||||
if (*ptr != byte)
|
||||
bool IsMemoryFilledWithByte(span<const uint8_t> memory, uint8_t byte) {
|
||||
for (uint8_t c : memory) {
|
||||
if (c != byte) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -41,8 +36,10 @@ class SharedMemoryRegionTest : public ::testing::Test {
|
||||
CreateMappedRegion<SharedMemoryRegionType>(kRegionSize);
|
||||
ASSERT_TRUE(region_.IsValid());
|
||||
ASSERT_TRUE(rw_mapping_.IsValid());
|
||||
memset(rw_mapping_.memory(), 'G', kRegionSize);
|
||||
EXPECT_TRUE(IsMemoryFilledWithByte(rw_mapping_.memory(), kRegionSize, 'G'));
|
||||
span<uint8_t> mapped = base::span(rw_mapping_);
|
||||
EXPECT_EQ(mapped.size(), kRegionSize);
|
||||
std::ranges::fill(mapped, uint8_t{'G'});
|
||||
EXPECT_TRUE(IsMemoryFilledWithByte(mapped, 'G'));
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -72,14 +69,12 @@ TYPED_TEST(SharedMemoryRegionTest, MoveRegion) {
|
||||
// Check that moved region maps correctly.
|
||||
typename TypeParam::MappingType mapping = moved_region.Map();
|
||||
ASSERT_TRUE(mapping.IsValid());
|
||||
EXPECT_NE(this->rw_mapping_.memory(), mapping.memory());
|
||||
EXPECT_EQ(memcmp(this->rw_mapping_.memory(), mapping.memory(), kRegionSize),
|
||||
0);
|
||||
EXPECT_NE(this->rw_mapping_.data(), mapping.data());
|
||||
EXPECT_EQ(base::span(this->rw_mapping_), base::span(mapping));
|
||||
|
||||
// Verify that the second mapping reflects changes in the first.
|
||||
memset(this->rw_mapping_.memory(), '#', kRegionSize);
|
||||
EXPECT_EQ(memcmp(this->rw_mapping_.memory(), mapping.memory(), kRegionSize),
|
||||
0);
|
||||
std::ranges::fill(base::span(this->rw_mapping_), '#');
|
||||
EXPECT_EQ(base::span(this->rw_mapping_), base::span(mapping));
|
||||
}
|
||||
|
||||
TYPED_TEST(SharedMemoryRegionTest, MappingValidAfterClose) {
|
||||
@ -87,28 +82,25 @@ TYPED_TEST(SharedMemoryRegionTest, MappingValidAfterClose) {
|
||||
this->region_ = TypeParam();
|
||||
EXPECT_FALSE(this->region_.IsValid());
|
||||
ASSERT_TRUE(this->rw_mapping_.IsValid());
|
||||
EXPECT_TRUE(
|
||||
IsMemoryFilledWithByte(this->rw_mapping_.memory(), kRegionSize, 'G'));
|
||||
EXPECT_TRUE(IsMemoryFilledWithByte(base::span(this->rw_mapping_), 'G'));
|
||||
}
|
||||
|
||||
TYPED_TEST(SharedMemoryRegionTest, MapTwice) {
|
||||
// The second mapping is either writable or read-only.
|
||||
typename TypeParam::MappingType mapping = this->region_.Map();
|
||||
ASSERT_TRUE(mapping.IsValid());
|
||||
EXPECT_NE(this->rw_mapping_.memory(), mapping.memory());
|
||||
EXPECT_EQ(memcmp(this->rw_mapping_.memory(), mapping.memory(), kRegionSize),
|
||||
0);
|
||||
EXPECT_NE(this->rw_mapping_.data(), mapping.data());
|
||||
EXPECT_EQ(base::span(this->rw_mapping_), base::span(mapping));
|
||||
|
||||
// Verify that the second mapping reflects changes in the first.
|
||||
memset(this->rw_mapping_.memory(), '#', kRegionSize);
|
||||
EXPECT_EQ(memcmp(this->rw_mapping_.memory(), mapping.memory(), kRegionSize),
|
||||
0);
|
||||
std::ranges::fill(base::span(this->rw_mapping_), '#');
|
||||
EXPECT_EQ(base::span(this->rw_mapping_), base::span(mapping));
|
||||
|
||||
// Close the region and unmap the first memory segment, verify the second
|
||||
// still has the right data.
|
||||
this->region_ = TypeParam();
|
||||
this->rw_mapping_ = WritableSharedMemoryMapping();
|
||||
EXPECT_TRUE(IsMemoryFilledWithByte(mapping.memory(), kRegionSize, '#'));
|
||||
EXPECT_TRUE(IsMemoryFilledWithByte(base::span(mapping), '#'));
|
||||
}
|
||||
|
||||
TYPED_TEST(SharedMemoryRegionTest, MapUnmapMap) {
|
||||
@ -116,7 +108,7 @@ TYPED_TEST(SharedMemoryRegionTest, MapUnmapMap) {
|
||||
|
||||
typename TypeParam::MappingType mapping = this->region_.Map();
|
||||
ASSERT_TRUE(mapping.IsValid());
|
||||
EXPECT_TRUE(IsMemoryFilledWithByte(mapping.memory(), kRegionSize, 'G'));
|
||||
EXPECT_TRUE(IsMemoryFilledWithByte(base::span(mapping), 'G'));
|
||||
}
|
||||
|
||||
TYPED_TEST(SharedMemoryRegionTest, SerializeAndDeserialize) {
|
||||
@ -128,12 +120,11 @@ TYPED_TEST(SharedMemoryRegionTest, SerializeAndDeserialize) {
|
||||
EXPECT_FALSE(this->region_.IsValid());
|
||||
typename TypeParam::MappingType mapping = region.Map();
|
||||
ASSERT_TRUE(mapping.IsValid());
|
||||
EXPECT_TRUE(IsMemoryFilledWithByte(mapping.memory(), kRegionSize, 'G'));
|
||||
EXPECT_TRUE(IsMemoryFilledWithByte(base::span(mapping), 'G'));
|
||||
|
||||
// Verify that the second mapping reflects changes in the first.
|
||||
memset(this->rw_mapping_.memory(), '#', kRegionSize);
|
||||
EXPECT_EQ(memcmp(this->rw_mapping_.memory(), mapping.memory(), kRegionSize),
|
||||
0);
|
||||
std::ranges::fill(base::span(this->rw_mapping_), '#');
|
||||
EXPECT_EQ(base::span(this->rw_mapping_), base::span(mapping));
|
||||
}
|
||||
|
||||
// Map() will return addresses which are aligned to the platform page size, this
|
||||
@ -141,7 +132,7 @@ TYPED_TEST(SharedMemoryRegionTest, SerializeAndDeserialize) {
|
||||
// minimum alignment that callers can count on, test for it here.
|
||||
TYPED_TEST(SharedMemoryRegionTest, MapMinimumAlignment) {
|
||||
EXPECT_EQ(0U,
|
||||
reinterpret_cast<uintptr_t>(this->rw_mapping_.memory()) &
|
||||
reinterpret_cast<uintptr_t>(this->rw_mapping_.data()) &
|
||||
(subtle::PlatformSharedMemoryRegion::kMapMinimumAlignment - 1));
|
||||
}
|
||||
|
||||
@ -165,10 +156,10 @@ TYPED_TEST(SharedMemoryRegionTest, MapAt) {
|
||||
auto [region, rw_mapping] = CreateMappedRegion<TypeParam>(kDataSize);
|
||||
ASSERT_TRUE(region.IsValid());
|
||||
ASSERT_TRUE(rw_mapping.IsValid());
|
||||
uint32_t* ptr = static_cast<uint32_t*>(rw_mapping.memory());
|
||||
auto map = rw_mapping.template GetMemoryAsSpan<uint32_t>();
|
||||
|
||||
for (size_t i = 0; i < kCount; ++i)
|
||||
ptr[i] = i;
|
||||
map[i] = i;
|
||||
|
||||
rw_mapping = WritableSharedMemoryMapping();
|
||||
|
||||
@ -179,9 +170,9 @@ TYPED_TEST(SharedMemoryRegionTest, MapAt) {
|
||||
ASSERT_TRUE(mapping.IsValid());
|
||||
|
||||
size_t int_offset = bytes_offset / sizeof(uint32_t);
|
||||
const uint32_t* ptr2 = static_cast<const uint32_t*>(mapping.memory());
|
||||
auto map2 = mapping.template GetMemoryAsSpan<uint32_t>();
|
||||
for (size_t i = int_offset; i < kCount; ++i) {
|
||||
EXPECT_EQ(ptr2[i - int_offset], i);
|
||||
EXPECT_EQ(map2[i - int_offset], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -211,9 +202,9 @@ TYPED_TEST(DuplicatableSharedMemoryRegionTest, Duplicate) {
|
||||
EXPECT_EQ(this->region_.GetGUID(), dup_region.GetGUID());
|
||||
typename TypeParam::MappingType mapping = dup_region.Map();
|
||||
ASSERT_TRUE(mapping.IsValid());
|
||||
EXPECT_NE(this->rw_mapping_.memory(), mapping.memory());
|
||||
EXPECT_NE(this->rw_mapping_.data(), mapping.data());
|
||||
EXPECT_EQ(this->rw_mapping_.guid(), mapping.guid());
|
||||
EXPECT_TRUE(IsMemoryFilledWithByte(mapping.memory(), kRegionSize, 'G'));
|
||||
EXPECT_TRUE(IsMemoryFilledWithByte(base::span(mapping), 'G'));
|
||||
}
|
||||
|
||||
class ReadOnlySharedMemoryRegionTest : public ::testing::Test {
|
||||
@ -260,8 +251,15 @@ TEST_F(ReadOnlySharedMemoryRegionTest,
|
||||
ASSERT_TRUE(region.IsValid());
|
||||
ReadOnlySharedMemoryMapping mapping = region.Map();
|
||||
ASSERT_TRUE(mapping.IsValid());
|
||||
void* memory_ptr = const_cast<void*>(mapping.memory());
|
||||
EXPECT_DEATH_IF_SUPPORTED(memset(memory_ptr, 'G', kRegionSize), "");
|
||||
base::span<const uint8_t> mem(mapping);
|
||||
base::span<uint8_t> mut_mem =
|
||||
// SAFETY: The data() and size() from `mem` produce a valid span as they
|
||||
// come from another span of the same type (modulo const). Const-casting
|
||||
// is not Undefined Behaviour here as it's not pointing to a const object.
|
||||
// We're testing that we crash if writing to a ReadOnly shared memory
|
||||
// backing.
|
||||
UNSAFE_BUFFERS(base::span(const_cast<uint8_t*>(mem.data()), mem.size()));
|
||||
EXPECT_DEATH_IF_SUPPORTED(std::ranges::fill(mut_mem, 'G'), "");
|
||||
}
|
||||
|
||||
TEST_F(ReadOnlySharedMemoryRegionTest,
|
||||
@ -270,8 +268,15 @@ TEST_F(ReadOnlySharedMemoryRegionTest,
|
||||
ASSERT_TRUE(region.IsValid());
|
||||
ReadOnlySharedMemoryMapping mapping = region.Map();
|
||||
ASSERT_TRUE(mapping.IsValid());
|
||||
void* memory_ptr = const_cast<void*>(mapping.memory());
|
||||
EXPECT_DEATH_IF_SUPPORTED(memset(memory_ptr, 'G', kRegionSize), "");
|
||||
base::span<const uint8_t> mem(mapping);
|
||||
base::span<uint8_t> mut_mem =
|
||||
// SAFETY: The data() and size() from `mem` produce a valid span as they
|
||||
// come from another span of the same type (modulo const). Const-casting
|
||||
// is not Undefined Behaviour here as it's not pointing to a const object.
|
||||
// We're testing that we crash if writing to a ReadOnly shared memory
|
||||
// backing.
|
||||
UNSAFE_BUFFERS(base::span(const_cast<uint8_t*>(mem.data()), mem.size()));
|
||||
EXPECT_DEATH_IF_SUPPORTED(std::ranges::fill(mut_mem, 'G'), "");
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
@ -59,6 +59,18 @@ void Unmap(void* addr, size_t size) {
|
||||
#endif
|
||||
}
|
||||
|
||||
std::optional<size_t> CountResidentBytesInSharedMemory(
|
||||
const WritableSharedMemoryMapping& mapping) {
|
||||
// SAFETY: We need the actual mapped memory size here. There's no public
|
||||
// method to get this as a span, so we need to construct it unsafely. The
|
||||
// mapped_size() is larger than `mem.size()` but represents the actual memory
|
||||
// segment size in the SharedMemoryMapping.
|
||||
auto mapped =
|
||||
UNSAFE_BUFFERS(base::span(mapping.data(), mapping.mapped_size()));
|
||||
return ProcessMemoryDump::CountResidentBytesInSharedMemory(mapped.data(),
|
||||
mapped.size());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(ProcessMemoryDumpTest, MoveConstructor) {
|
||||
@ -524,10 +536,9 @@ TEST(ProcessMemoryDumpTest, MAYBE_CountResidentBytesInSharedMemory) {
|
||||
const size_t kDirtyMemorySize = 5 * page_size;
|
||||
auto region = base::WritableSharedMemoryRegion::Create(kDirtyMemorySize);
|
||||
base::WritableSharedMemoryMapping mapping = region.Map();
|
||||
memset(mapping.memory(), 0, kDirtyMemorySize);
|
||||
std::optional<size_t> res1 =
|
||||
ProcessMemoryDump::CountResidentBytesInSharedMemory(
|
||||
mapping.memory(), mapping.mapped_size());
|
||||
base::span<uint8_t> mapping_mem(mapping);
|
||||
std::ranges::fill(mapping_mem, 0u);
|
||||
std::optional<size_t> res1 = CountResidentBytesInSharedMemory(mapping);
|
||||
ASSERT_TRUE(res1.has_value());
|
||||
ASSERT_EQ(res1.value(), kDirtyMemorySize);
|
||||
}
|
||||
@ -539,10 +550,9 @@ TEST(ProcessMemoryDumpTest, MAYBE_CountResidentBytesInSharedMemory) {
|
||||
base::WritableSharedMemoryRegion::Create(kDirtyMemorySize + page_size);
|
||||
base::WritableSharedMemoryMapping mapping =
|
||||
region.MapAt(page_size / 2, kDirtyMemorySize);
|
||||
memset(mapping.memory(), 0, kDirtyMemorySize);
|
||||
std::optional<size_t> res1 =
|
||||
ProcessMemoryDump::CountResidentBytesInSharedMemory(
|
||||
mapping.memory(), mapping.mapped_size());
|
||||
base::span<uint8_t> mapping_mem(mapping);
|
||||
std::ranges::fill(mapping_mem, 0u);
|
||||
std::optional<size_t> res1 = CountResidentBytesInSharedMemory(mapping);
|
||||
ASSERT_TRUE(res1.has_value());
|
||||
ASSERT_EQ(res1.value(), kDirtyMemorySize + page_size);
|
||||
}
|
||||
@ -553,10 +563,9 @@ TEST(ProcessMemoryDumpTest, MAYBE_CountResidentBytesInSharedMemory) {
|
||||
auto region =
|
||||
base::WritableSharedMemoryRegion::Create(kVeryLargeMemorySize);
|
||||
base::WritableSharedMemoryMapping mapping = region.Map();
|
||||
memset(mapping.memory(), 0, kVeryLargeMemorySize);
|
||||
std::optional<size_t> res2 =
|
||||
ProcessMemoryDump::CountResidentBytesInSharedMemory(
|
||||
mapping.memory(), mapping.mapped_size());
|
||||
base::span<uint8_t> mapping_mem(mapping);
|
||||
std::ranges::fill(mapping_mem, 0u);
|
||||
std::optional<size_t> res2 = CountResidentBytesInSharedMemory(mapping);
|
||||
ASSERT_TRUE(res2.has_value());
|
||||
ASSERT_EQ(res2.value(), kVeryLargeMemorySize);
|
||||
}
|
||||
@ -566,10 +575,9 @@ TEST(ProcessMemoryDumpTest, MAYBE_CountResidentBytesInSharedMemory) {
|
||||
const size_t kTouchedMemorySize = 7 * 1024 * 1024;
|
||||
auto region = base::WritableSharedMemoryRegion::Create(kTouchedMemorySize);
|
||||
base::WritableSharedMemoryMapping mapping = region.Map();
|
||||
memset(mapping.memory(), 0, kTouchedMemorySize);
|
||||
std::optional<size_t> res3 =
|
||||
ProcessMemoryDump::CountResidentBytesInSharedMemory(
|
||||
mapping.memory(), mapping.mapped_size());
|
||||
base::span<uint8_t> mapping_mem(mapping);
|
||||
std::ranges::fill(mapping_mem, 0u);
|
||||
std::optional<size_t> res3 = CountResidentBytesInSharedMemory(mapping);
|
||||
ASSERT_TRUE(res3.has_value());
|
||||
ASSERT_EQ(res3.value(), kTouchedMemorySize);
|
||||
}
|
||||
|
@ -456,11 +456,14 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
|
||||
|
||||
SkImageInfo info = SkImageInfo::MakeN32Premul(
|
||||
pool_resource.size().width(), pool_resource.size().height());
|
||||
SkSurfaceProps props = skia::LegacyDisplayGlobals::GetSkSurfaceProps();
|
||||
const size_t row_bytes = info.minRowBytes();
|
||||
auto* backing =
|
||||
static_cast<HudSoftwareBacking*>(pool_resource.software_backing());
|
||||
SkSurfaceProps props = skia::LegacyDisplayGlobals::GetSkSurfaceProps();
|
||||
sk_sp<SkSurface> surface = SkSurfaces::WrapPixels(
|
||||
info, backing->shared_mapping.memory(), info.minRowBytes(), &props);
|
||||
base::span<uint8_t> mem(backing->shared_mapping);
|
||||
CHECK_GE(mem.size(), info.computeByteSize(row_bytes));
|
||||
sk_sp<SkSurface> surface =
|
||||
SkSurfaces::WrapPixels(info, mem.data(), row_bytes, &props);
|
||||
|
||||
SkiaPaintCanvas canvas(surface->getCanvas());
|
||||
DrawHudContents(&canvas);
|
||||
|
@ -33,7 +33,11 @@ class CC_EXPORT CrossThreadSharedBitmap
|
||||
const base::ReadOnlySharedMemoryRegion& shared_region() const {
|
||||
return region_;
|
||||
}
|
||||
void* memory() const { return mapping_.memory(); }
|
||||
void* memory() const {
|
||||
// TODO(crbug.com/355003196): This returns an unsafe unbounded pointer. The
|
||||
// return type here should be changed to a span, then return span(mapping_).
|
||||
return mapping_.data();
|
||||
}
|
||||
const gfx::Size& size() const { return size_; }
|
||||
viz::SharedImageFormat format() const { return format_; }
|
||||
|
||||
|
@ -255,7 +255,10 @@ viz::ResourceId PixelTest::AllocateAndFillSoftwareResource(
|
||||
AllocateSharedBitmapMemory(shared_bitmap_id, size);
|
||||
|
||||
SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height());
|
||||
source.readPixels(info, mapping.memory(), info.minRowBytes(), 0, 0);
|
||||
const size_t row_bytes = info.minRowBytes();
|
||||
base::span<uint8_t> mem(mapping);
|
||||
CHECK_GE(mem.size(), info.computeByteSize(row_bytes));
|
||||
source.readPixels(info, mem.data(), row_bytes, 0, 0);
|
||||
|
||||
return child_resource_provider_->ImportResource(
|
||||
viz::TransferableResource::MakeSoftwareSharedBitmap(
|
||||
|
@ -136,7 +136,7 @@ void ImageContentAnnotator::AnnotateEncodedImage(
|
||||
if (!mapped_region.IsValid()) {
|
||||
return;
|
||||
}
|
||||
memcpy(mapped_region.mapping.memory(), data.data(), data.length());
|
||||
base::span(mapped_region.mapping).copy_from(data.bytes());
|
||||
|
||||
EnsureAnnotatorIsConnected();
|
||||
image_content_annotator_->AnnotateEncodedImage(
|
||||
|
@ -245,7 +245,7 @@ void ImageLoaderPrivateGetPdfThumbnailFunction::FetchThumbnail(
|
||||
Respond(Error("Failed allocate memory for PDF file"));
|
||||
return;
|
||||
}
|
||||
memcpy(pdf_region.mapping.memory(), content.data(), content.size());
|
||||
base::as_writable_chars(base::span(pdf_region.mapping)).copy_from(content);
|
||||
DCHECK(!pdf_thumbnailer_.is_bound());
|
||||
GetPdfService()->BindPdfThumbnailer(
|
||||
pdf_thumbnailer_.BindNewPipeAndPassReceiver());
|
||||
|
@ -314,16 +314,15 @@ void DevToolsEyeDropper::OnFrameCaptured(
|
||||
DLOG(ERROR) << "Shared memory mapping failed.";
|
||||
return;
|
||||
}
|
||||
if (mapping.size() <
|
||||
|
||||
base::span<const uint8_t> pixels(mapping);
|
||||
|
||||
if (pixels.size() <
|
||||
media::VideoFrame::AllocationSize(info->pixel_format, info->coded_size)) {
|
||||
DLOG(ERROR) << "Shared memory size was less than expected.";
|
||||
return;
|
||||
}
|
||||
|
||||
// The SkBitmap's pixels will be marked as immutable, but the installPixels()
|
||||
// API requires a non-const pointer. So, cast away the const.
|
||||
void* const pixels = const_cast<void*>(mapping.memory());
|
||||
|
||||
// Call installPixels() with a |releaseProc| that: 1) notifies the capturer
|
||||
// that this consumer has finished with the frame, and 2) releases the shared
|
||||
// memory mapping.
|
||||
@ -335,13 +334,23 @@ void DevToolsEyeDropper::OnFrameCaptured(
|
||||
mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
|
||||
releaser;
|
||||
};
|
||||
frame_.installPixels(
|
||||
SkImageInfo::MakeN32(content_rect.width(), content_rect.height(),
|
||||
kPremul_SkAlphaType,
|
||||
info->color_space.ToSkColorSpace()),
|
||||
pixels,
|
||||
|
||||
auto image_info = SkImageInfo::MakeN32(
|
||||
content_rect.width(), content_rect.height(), kPremul_SkAlphaType,
|
||||
info->color_space.ToSkColorSpace());
|
||||
const size_t row_bytes =
|
||||
media::VideoFrame::RowBytes(media::VideoFrame::Plane::kARGB,
|
||||
info->pixel_format, info->coded_size.width()),
|
||||
info->pixel_format, info->coded_size.width());
|
||||
// installPixels() takes an unsafe unbounded pointer, ensure it's pointing to
|
||||
// enough memory.
|
||||
CHECK_GE(pixels.size(), image_info.computeByteSize(row_bytes));
|
||||
|
||||
frame_.installPixels(
|
||||
image_info,
|
||||
// The SkBitmap's pixels will be marked as immutable, but the
|
||||
// installPixels() API requires a non-const pointer. So, cast away the
|
||||
// const.
|
||||
const_cast<uint8_t*>(pixels.data()), row_bytes,
|
||||
[](void* addr, void* context) {
|
||||
delete static_cast<FramePinner*>(context);
|
||||
},
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
@ -1810,7 +1811,7 @@ IN_PROC_BROWSER_TEST_P(ContentAnalysisDelegateBlockingSettingBrowserTest,
|
||||
constexpr int64_t kLargeSize = 51 * 1024 * 1024;
|
||||
base::MappedReadOnlyRegion page =
|
||||
base::ReadOnlySharedMemoryRegion::Create(kLargeSize);
|
||||
memset(page.mapping.memory(), 'a', kLargeSize);
|
||||
std::ranges::fill(base::span(page.mapping), 'a');
|
||||
data.page = std::move(page.region);
|
||||
|
||||
ASSERT_TRUE(ContentAnalysisDelegate::IsEnabled(browser()->profile(),
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
@ -107,7 +108,7 @@ std::string small_text() {
|
||||
base::ReadOnlySharedMemoryRegion create_page(size_t size) {
|
||||
base::MappedReadOnlyRegion page =
|
||||
base::ReadOnlySharedMemoryRegion::Create(size);
|
||||
memset(page.mapping.memory(), 'a', size);
|
||||
std::ranges::fill(base::span(page.mapping), 'a');
|
||||
return std::move(page.region);
|
||||
}
|
||||
|
||||
|
@ -437,7 +437,9 @@ bool SynchronousCompositorHost::DemandDrawSw(SkCanvas* canvas,
|
||||
UpdateFrameMetaData(metadata_version, std::move(*metadata), std::nullopt);
|
||||
|
||||
SkBitmap bitmap;
|
||||
SkPixmap pixmap(info, software_draw_shm_->shared_memory.memory(), stride);
|
||||
base::span<uint8_t> mem(software_draw_shm_->shared_memory);
|
||||
CHECK_GE(mem.size(), info.computeByteSize(stride));
|
||||
SkPixmap pixmap(info, mem.data(), stride);
|
||||
|
||||
bool pixels_released = false;
|
||||
{
|
||||
|
@ -160,7 +160,8 @@ void DevToolsVideoConsumer::OnFrameCaptured(
|
||||
DLOG(ERROR) << "Shared memory mapping failed.";
|
||||
return;
|
||||
}
|
||||
if (mapping.size() <
|
||||
base::span<const uint8_t> mapping_memory(mapping);
|
||||
if (mapping_memory.size() <
|
||||
media::VideoFrame::AllocationSize(info->pixel_format, info->coded_size)) {
|
||||
DLOG(ERROR) << "Shared memory size was less than expected.";
|
||||
return;
|
||||
@ -177,8 +178,7 @@ void DevToolsVideoConsumer::OnFrameCaptured(
|
||||
// portion of the frame that contains content is used.
|
||||
scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapExternalData(
|
||||
info->pixel_format, info->coded_size, content_rect, content_rect.size(),
|
||||
static_cast<const uint8_t*>(mapping.memory()), mapping.size(),
|
||||
info->timestamp);
|
||||
mapping_memory.data(), mapping_memory.size(), info->timestamp);
|
||||
if (!frame) {
|
||||
DLOG(ERROR) << "Unable to create VideoFrame wrapper around the shmem.";
|
||||
return;
|
||||
|
@ -103,8 +103,8 @@ void FontEnumerationCache::BuildEnumerationCache(
|
||||
}
|
||||
|
||||
DCHECK_GE(font_data_region.mapping.size(), table.ByteSizeLong());
|
||||
if (!table.SerializeToArray(font_data_region.mapping.memory(),
|
||||
font_data_region.mapping.size())) {
|
||||
base::span<uint8_t> font_mem(font_data_region.mapping);
|
||||
if (!table.SerializeToArray(font_mem.data(), font_mem.size())) {
|
||||
data_.status = blink::mojom::FontEnumerationStatus::kUnexpectedError;
|
||||
return;
|
||||
}
|
||||
|
@ -289,17 +289,19 @@ bool FontUniqueNameLookup::IsValid() {
|
||||
|
||||
bool FontUniqueNameLookup::UpdateTableIfNeeded() {
|
||||
TRACE_EVENT0("fonts", "FontUniqueNameLookup::UpdateTableIfNeeded");
|
||||
blink::FontUniqueNameTable font_table;
|
||||
bool update_needed =
|
||||
!proto_storage_.IsValid() || !proto_storage_.mapping.size() ||
|
||||
!font_table.ParseFromArray(proto_storage_.mapping.memory(),
|
||||
proto_storage_.mapping.size()) ||
|
||||
font_table.stored_for_platform_version_identifier() !=
|
||||
GetAndroidBuildFingerprint();
|
||||
if (proto_storage_.IsValid() && proto_storage_.mapping.size()) {
|
||||
blink::FontUniqueNameTable font_table;
|
||||
base::span<const uint8_t> mem(proto_storage_.mapping);
|
||||
if (font_table.ParseFromArray(mem.data(), mem.size())) {
|
||||
if (font_table.stored_for_platform_version_identifier() ==
|
||||
GetAndroidBuildFingerprint()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (update_needed)
|
||||
UpdateTable();
|
||||
return update_needed;
|
||||
UpdateTable();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FontUniqueNameLookup::UpdateTable() {
|
||||
@ -324,8 +326,8 @@ bool FontUniqueNameLookup::UpdateTable() {
|
||||
if (!proto_storage_.IsValid() || !proto_storage_.mapping.size())
|
||||
return false;
|
||||
|
||||
if (!font_table.SerializeToArray(proto_storage_.mapping.memory(),
|
||||
proto_storage_.mapping.size())) {
|
||||
base::span<uint8_t> mem(proto_storage_.mapping);
|
||||
if (!font_table.SerializeToArray(mem.data(), mem.size())) {
|
||||
proto_storage_ = base::MappedReadOnlyRegion();
|
||||
return false;
|
||||
}
|
||||
|
@ -1728,13 +1728,10 @@ void RenderProcessHostImpl::InitializeSharedMemoryRegionsOnceChannelIsUp() {
|
||||
sizeof(std::atomic<base::TimeTicks>));
|
||||
CHECK(last_foreground_time_region_.IsValid());
|
||||
|
||||
// Placement new to initialize the std::atomic in place.
|
||||
new (last_foreground_time_region_.mapping.memory())
|
||||
std::atomic<base::TimeTicks>;
|
||||
// Then initialized to the appropriate value. `std::memory_order_relaxed` is
|
||||
// sufficient as reads on the renderer side will happen-after this per the
|
||||
// ordering relationship implicitly established between this operation and
|
||||
// the renderer via TransferSharedLastForegroundTime().
|
||||
// `std::memory_order_relaxed` is sufficient as reads on the renderer side
|
||||
// will happen-after this per the ordering relationship implicitly
|
||||
// established between this operation and the renderer via
|
||||
// TransferSharedLastForegroundTime().
|
||||
last_foreground_time_region_.mapping
|
||||
.GetMemoryAs<std::atomic<base::TimeTicks>>()
|
||||
->store(priority_.is_background() ? base::TimeTicks()
|
||||
|
@ -70,7 +70,7 @@ void* PPB_Buffer_Impl::Map() {
|
||||
DCHECK(!shared_mapping_.IsValid());
|
||||
shared_mapping_ = shared_memory_.Map();
|
||||
}
|
||||
return shared_mapping_.memory();
|
||||
return shared_mapping_.data();
|
||||
}
|
||||
|
||||
void PPB_Buffer_Impl::Unmap() {
|
||||
|
@ -234,7 +234,9 @@ void* ImageDataSimpleBackend::Map() {
|
||||
if (!shm_mapping_.IsValid())
|
||||
return nullptr;
|
||||
|
||||
skia_bitmap_.setPixels(shm_mapping_.memory());
|
||||
base::span<uint8_t> mem(shm_mapping_);
|
||||
CHECK_GE(mem.size(), skia_bitmap_.computeByteSize());
|
||||
skia_bitmap_.setPixels(mem.data());
|
||||
// Our platform bitmaps are set to opaque by default, which we don't want.
|
||||
skia_bitmap_.setAlphaType(kPremul_SkAlphaType);
|
||||
skia_canvas_ = std::make_unique<SkCanvas>(
|
||||
|
@ -4,35 +4,9 @@
|
||||
|
||||
#include "device/gamepad/public/cpp/gamepad.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace device {
|
||||
|
||||
const float GamepadButton::kDefaultButtonPressedThreshold;
|
||||
const double GamepadHapticActuator::kMaxEffectDurationMillis;
|
||||
const size_t Gamepad::kIdLengthCap;
|
||||
const size_t Gamepad::kAxesLengthCap;
|
||||
const size_t Gamepad::kButtonsLengthCap;
|
||||
const size_t Gamepad::kTouchEventsLengthCap;
|
||||
|
||||
Gamepad::Gamepad()
|
||||
: connected(false),
|
||||
timestamp(0),
|
||||
axes_length(0),
|
||||
buttons_length(0),
|
||||
touch_events_length(0),
|
||||
mapping(GamepadMapping::kNone),
|
||||
display_id(0) {
|
||||
id[0] = 0;
|
||||
}
|
||||
|
||||
Gamepad::Gamepad(const Gamepad& other) = default;
|
||||
|
||||
Gamepad& Gamepad::operator=(const Gamepad& other) = default;
|
||||
|
||||
void Gamepad::SetID(const std::u16string& src) {
|
||||
memset(id, 0, sizeof(id));
|
||||
src.copy(id, kIdLengthCap - 1);
|
||||
}
|
||||
|
||||
} // namespace device
|
||||
|
@ -6,10 +6,11 @@
|
||||
#define DEVICE_GAMEPAD_PUBLIC_CPP_GAMEPAD_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "base/component_export.h"
|
||||
|
||||
@ -28,10 +29,10 @@ class GamepadButton {
|
||||
this->touched == other.touched && this->value == other.value;
|
||||
}
|
||||
// Whether the button is actually reported by the gamepad at all.
|
||||
bool used{false};
|
||||
bool pressed{false};
|
||||
bool touched{false};
|
||||
double value{0.0};
|
||||
bool used = false;
|
||||
bool pressed = false;
|
||||
bool touched = false;
|
||||
double value = 0.0;
|
||||
};
|
||||
|
||||
enum class GamepadHapticActuatorType {
|
||||
@ -64,44 +65,36 @@ class GamepadHapticActuator {
|
||||
public:
|
||||
static constexpr double kMaxEffectDurationMillis = 5000.0;
|
||||
|
||||
GamepadHapticActuator() : not_null(false) {}
|
||||
|
||||
bool not_null;
|
||||
bool not_null = false;
|
||||
GamepadHapticActuatorType type;
|
||||
};
|
||||
|
||||
class GamepadEffectParameters {
|
||||
public:
|
||||
double duration;
|
||||
double start_delay;
|
||||
double strong_magnitude;
|
||||
double weak_magnitude;
|
||||
double duration = 0.0;
|
||||
double start_delay = 0.0;
|
||||
double strong_magnitude = 0.0;
|
||||
double weak_magnitude = 0.0;
|
||||
};
|
||||
|
||||
class GamepadVector {
|
||||
public:
|
||||
GamepadVector() : not_null(false) {}
|
||||
|
||||
bool not_null;
|
||||
float x, y, z;
|
||||
bool not_null = false;
|
||||
float x = 0.f, y = 0.f, z = 0.f;
|
||||
};
|
||||
|
||||
class GamepadQuaternion {
|
||||
public:
|
||||
GamepadQuaternion() : not_null(false) {}
|
||||
|
||||
bool not_null;
|
||||
float x, y, z, w;
|
||||
bool not_null = false;
|
||||
float x = 0.f, y = 0.f, z = 0.f, w = 0.f;
|
||||
};
|
||||
|
||||
class GamepadPose {
|
||||
public:
|
||||
GamepadPose() : not_null(false) {}
|
||||
bool not_null = false;
|
||||
|
||||
bool not_null;
|
||||
|
||||
bool has_orientation;
|
||||
bool has_position;
|
||||
bool has_orientation = false;
|
||||
bool has_position = false;
|
||||
|
||||
GamepadQuaternion orientation;
|
||||
GamepadVector position;
|
||||
@ -115,77 +108,84 @@ enum class GamepadMapping { kNone = 0, kStandard = 1, kXrStandard = 2 };
|
||||
|
||||
enum class GamepadHand { kNone = 0, kLeft = 1, kRight = 2 };
|
||||
|
||||
// This structure is intentionally POD and fixed size so that it can be shared
|
||||
// This structure is intentionally trivially copyable so that it can be shared
|
||||
// memory between hardware polling threads and the rest of the browser. See
|
||||
// also gamepads.h.
|
||||
class COMPONENT_EXPORT(GAMEPAD_PUBLIC) Gamepad {
|
||||
//
|
||||
// TODO(crbug.com/355003174): It's a template to avoid the clang plugin that
|
||||
// prevents inline ctors, as we need the class to be trivially copyable for use
|
||||
// in shared memory.
|
||||
template <class T>
|
||||
class GamepadImpl {
|
||||
public:
|
||||
static constexpr size_t kIdLengthCap = 128;
|
||||
static constexpr size_t kAxesLengthCap = 16;
|
||||
static constexpr size_t kButtonsLengthCap = 32;
|
||||
static constexpr size_t kTouchEventsLengthCap = 8;
|
||||
|
||||
Gamepad();
|
||||
Gamepad(const Gamepad& other);
|
||||
Gamepad& operator=(const Gamepad& other);
|
||||
|
||||
// If src is too long, then the contents of id will be truncated to
|
||||
// kIdLengthCap-1. id will be null-terminated and any extra space in the
|
||||
// buffer will be zeroed out.
|
||||
void SetID(const std::u16string& src);
|
||||
void SetID(const std::u16string& src) {
|
||||
std::ranges::fill(id, 0);
|
||||
src.copy(id, kIdLengthCap - 1);
|
||||
}
|
||||
|
||||
// Is there a gamepad connected at this index?
|
||||
bool connected;
|
||||
bool connected = false;
|
||||
|
||||
// Device identifier (based on manufacturer, model, etc.).
|
||||
char16_t id[kIdLengthCap];
|
||||
char16_t id[kIdLengthCap] = {};
|
||||
|
||||
// Time value representing the last time the data for this gamepad was
|
||||
// updated. Measured as TimeTicks::Now().since_origin().InMicroseconds().
|
||||
int64_t timestamp;
|
||||
int64_t timestamp = 0;
|
||||
|
||||
// Number of valid entries in the axes array.
|
||||
unsigned axes_length;
|
||||
unsigned axes_length = 0;
|
||||
|
||||
// Bitfield indicating which entries of the axes array are actually used. If
|
||||
// the axes index is actually used for this gamepad then the corresponding bit
|
||||
// will be 1.
|
||||
uint32_t axes_used;
|
||||
static_assert(Gamepad::kAxesLengthCap <=
|
||||
std::numeric_limits<uint32_t>::digits,
|
||||
uint32_t axes_used = 0;
|
||||
static_assert(kAxesLengthCap <= std::numeric_limits<uint32_t>::digits,
|
||||
"axes_used is not large enough");
|
||||
|
||||
// Normalized values representing axes, in the range [-1..1].
|
||||
double axes[kAxesLengthCap];
|
||||
double axes[kAxesLengthCap] = {};
|
||||
|
||||
// Number of valid entries in the buttons array.
|
||||
unsigned buttons_length;
|
||||
unsigned buttons_length = 0;
|
||||
|
||||
// Button states
|
||||
GamepadButton buttons[kButtonsLengthCap];
|
||||
GamepadButton buttons[kButtonsLengthCap] = {};
|
||||
|
||||
// Number of valid entries in the touch_events array.
|
||||
uint32_t touch_events_length;
|
||||
uint32_t touch_events_length = 0;
|
||||
|
||||
// Touch events states
|
||||
bool supports_touch_events_ = false;
|
||||
|
||||
GamepadTouch touch_events[kTouchEventsLengthCap];
|
||||
GamepadTouch touch_events[kTouchEventsLengthCap] = {};
|
||||
|
||||
GamepadHapticActuator vibration_actuator;
|
||||
|
||||
// Mapping type
|
||||
GamepadMapping mapping;
|
||||
GamepadMapping mapping = GamepadMapping::kNone;
|
||||
|
||||
GamepadPose pose;
|
||||
|
||||
GamepadHand hand;
|
||||
|
||||
unsigned display_id;
|
||||
unsigned display_id = 0;
|
||||
|
||||
bool is_xr = false;
|
||||
};
|
||||
|
||||
using Gamepad = GamepadImpl<void>;
|
||||
|
||||
static_assert(std::is_trivially_copyable_v<Gamepad>);
|
||||
|
||||
} // namespace device
|
||||
|
||||
#endif // DEVICE_GAMEPAD_PUBLIC_CPP_GAMEPAD_H_
|
||||
|
@ -10,7 +10,11 @@
|
||||
|
||||
namespace device {
|
||||
|
||||
typedef SharedMemorySeqLockBuffer<Gamepads> GamepadHardwareBuffer;
|
||||
using GamepadHardwareBuffer = SharedMemorySeqLockBuffer<Gamepads>;
|
||||
|
||||
// GamepadHardwareBuffer is used in shared memory, so it must be trivially
|
||||
// copyable.
|
||||
static_assert(std::is_trivially_copyable_v<GamepadHardwareBuffer>);
|
||||
|
||||
} // namespace device
|
||||
|
||||
|
@ -92,7 +92,7 @@ class VROrientationDeviceProviderTest : public testing::Test {
|
||||
init_params->memory = mapped_region_.region.Duplicate();
|
||||
|
||||
init_params->buffer_offset =
|
||||
SensorReadingSharedBuffer::GetOffset(kOrientationSensorType);
|
||||
GetSensorReadingSharedBufferOffset(kOrientationSensorType);
|
||||
|
||||
return init_params;
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ class VROrientationDeviceTest : public testing::Test {
|
||||
}
|
||||
|
||||
uint64_t GetBufferOffset() {
|
||||
return SensorReadingSharedBuffer::GetOffset(kOrientationSensorType);
|
||||
return GetSensorReadingSharedBufferOffset(kOrientationSensorType);
|
||||
}
|
||||
|
||||
void InitializeDevice(mojom::SensorInitParamsPtr params) {
|
||||
@ -204,17 +204,19 @@ class VROrientationDeviceTest : public testing::Test {
|
||||
}
|
||||
|
||||
void WriteToBuffer(gfx::Quaternion q) {
|
||||
SensorReadingSharedBuffer* buffer =
|
||||
reinterpret_cast<SensorReadingSharedBuffer*>(
|
||||
static_cast<char*>(mapped_region_.mapping.memory()) +
|
||||
GetBufferOffset());
|
||||
size_t offset = GetBufferOffset();
|
||||
CHECK(offset % sizeof(SensorReadingSharedBuffer) == 0u);
|
||||
auto buffers =
|
||||
mapped_region_.mapping.GetMemoryAsSpan<SensorReadingSharedBuffer>();
|
||||
SensorReadingSharedBuffer& buffer =
|
||||
buffers[offset / sizeof(SensorReadingSharedBuffer)];
|
||||
|
||||
auto& seqlock = buffer->seqlock.value();
|
||||
auto& seqlock = buffer.seqlock.value();
|
||||
seqlock.WriteBegin();
|
||||
buffer->reading.orientation_quat.x = q.x();
|
||||
buffer->reading.orientation_quat.y = q.y();
|
||||
buffer->reading.orientation_quat.z = q.z();
|
||||
buffer->reading.orientation_quat.w = q.w();
|
||||
buffer.reading.orientation_quat.x = q.x();
|
||||
buffer.reading.orientation_quat.y = q.y();
|
||||
buffer.reading.orientation_quat.z = q.z();
|
||||
buffer.reading.orientation_quat.w = q.w();
|
||||
seqlock.WriteEnd();
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,9 @@ std::unique_ptr<base::SharedMemoryMapping> MapRegion(
|
||||
if (!m.IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
*memory = const_cast<void*>(m.memory());
|
||||
// TODO(crbug.com/355607629): This function should give back a span instead of
|
||||
// an unbounded pointer.
|
||||
*memory = const_cast<uint8_t*>(m.data());
|
||||
return std::make_unique<typename RegionType::MappingType>(std::move(m));
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ TEST_F(PlatformWrapperTest, MAYBE_WrapPlatformSharedMemoryRegion) {
|
||||
auto region = base::UnsafeSharedMemoryRegion::Create(kMessage.size());
|
||||
base::WritableSharedMemoryMapping buffer = region.Map();
|
||||
CHECK(buffer.IsValid());
|
||||
memcpy(buffer.memory(), kMessage.data(), kMessage.size());
|
||||
base::as_writable_chars(base::span(buffer)).copy_from(kMessage);
|
||||
|
||||
RunTestClient("ReadPlatformSharedBuffer", [&](MojoHandle h) {
|
||||
// Wrap the shared memory handle and send it to the child along with the
|
||||
@ -229,9 +229,7 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformSharedBuffer,
|
||||
ASSERT_TRUE(region.IsValid());
|
||||
|
||||
base::WritableSharedMemoryMapping mapping = region.Map();
|
||||
ASSERT_TRUE(mapping.memory());
|
||||
EXPECT_TRUE(std::equal(message.begin(), message.end(),
|
||||
static_cast<const char*>(mapping.memory())));
|
||||
EXPECT_EQ(base::as_byte_span(message), base::span(mapping));
|
||||
|
||||
// Verify that the received buffer's internal GUID was preserved in transit.
|
||||
EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE));
|
||||
|
@ -13,14 +13,16 @@
|
||||
TEST(SharedMemoryMojomTest, ReadOnly) {
|
||||
auto region = base::ReadOnlySharedMemoryRegion::Create(64);
|
||||
const std::string kTestData = "Hello, world!";
|
||||
memcpy(region.mapping.memory(), kTestData.data(), kTestData.size());
|
||||
base::as_writable_chars(base::span(region.mapping))
|
||||
.copy_prefix_from(kTestData);
|
||||
|
||||
base::ReadOnlySharedMemoryRegion read_only_out;
|
||||
ASSERT_TRUE(mojo::test::SerializeAndDeserialize<
|
||||
mojo_base::mojom::ReadOnlySharedMemoryRegion>(region.region,
|
||||
read_only_out));
|
||||
base::ReadOnlySharedMemoryMapping mapping = read_only_out.Map();
|
||||
EXPECT_EQ(0, memcmp(mapping.memory(), kTestData.data(), kTestData.size()));
|
||||
EXPECT_EQ(base::as_chars(base::span(region.mapping)).first(kTestData.size()),
|
||||
kTestData);
|
||||
}
|
||||
|
||||
#if BUILDFLAG(USE_BLINK)
|
||||
@ -28,7 +30,7 @@ TEST(SharedMemoryMojomTest, Writable) {
|
||||
auto region = base::WritableSharedMemoryRegion::Create(64);
|
||||
auto mapping = region.Map();
|
||||
const std::string kTestData = "Hello, world!";
|
||||
memcpy(mapping.memory(), kTestData.data(), kTestData.size());
|
||||
base::as_writable_chars(base::span(mapping)).copy_prefix_from(kTestData);
|
||||
|
||||
base::WritableSharedMemoryRegion writable_out;
|
||||
ASSERT_TRUE(
|
||||
@ -36,7 +38,8 @@ TEST(SharedMemoryMojomTest, Writable) {
|
||||
mojo_base::mojom::WritableSharedMemoryRegion>(region, writable_out));
|
||||
|
||||
mapping = writable_out.Map();
|
||||
EXPECT_EQ(0, memcmp(mapping.memory(), kTestData.data(), kTestData.size()));
|
||||
EXPECT_EQ(base::as_chars(base::span(mapping)).first(kTestData.size()),
|
||||
kTestData);
|
||||
}
|
||||
#endif // BUILDFLAG(USE_BLINK)
|
||||
|
||||
@ -44,12 +47,13 @@ TEST(SharedMemoryMojomTest, Unsafe) {
|
||||
auto region = base::UnsafeSharedMemoryRegion::Create(64);
|
||||
auto mapping = region.Map();
|
||||
const std::string kTestData = "Hello, world!";
|
||||
memcpy(mapping.memory(), kTestData.data(), kTestData.size());
|
||||
base::as_writable_chars(base::span(mapping)).copy_prefix_from(kTestData);
|
||||
|
||||
base::UnsafeSharedMemoryRegion unsafe_out;
|
||||
ASSERT_TRUE(mojo::test::SerializeAndDeserialize<
|
||||
mojo_base::mojom::UnsafeSharedMemoryRegion>(region, unsafe_out));
|
||||
|
||||
mapping = unsafe_out.Map();
|
||||
EXPECT_EQ(0, memcmp(mapping.memory(), kTestData.data(), kTestData.size()));
|
||||
EXPECT_EQ(base::as_chars(base::span(mapping)).first(kTestData.size()),
|
||||
kTestData);
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ SharedMemoryVersionController::SharedMemoryVersionController()
|
||||
base::ReadOnlySharedMemoryRegion::Create(sizeof(SharedVersionType))) {
|
||||
// Create a shared memory region and immediately populate it.
|
||||
CHECK(mapped_region_.IsValid());
|
||||
new (mapped_region_.mapping.memory()) SharedVersionType;
|
||||
|
||||
// Clients may use `kInvalidVersion` as special value to indicate the version
|
||||
// in the absence of shared memory communication. Make sure the version starts
|
||||
|
@ -158,7 +158,7 @@ class PlatformHandleTest : public testing::Test,
|
||||
PlatformHandle SetUpSharedMemory() {
|
||||
auto region = base::UnsafeSharedMemoryRegion::Create(kTestData.size());
|
||||
auto mapping = region.Map();
|
||||
memcpy(mapping.memory(), kTestData.data(), kTestData.size());
|
||||
base::as_writable_chars(base::span(mapping)).copy_from(kTestData);
|
||||
auto generic_region =
|
||||
base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
|
||||
std::move(region));
|
||||
@ -184,8 +184,7 @@ class PlatformHandleTest : public testing::Test,
|
||||
auto region =
|
||||
base::UnsafeSharedMemoryRegion::Deserialize(std::move(generic_region));
|
||||
auto mapping = region.Map();
|
||||
std::string contents(static_cast<char*>(mapping.memory()),
|
||||
kTestData.size());
|
||||
std::string contents(base::as_string_view(mapping));
|
||||
|
||||
// Let |handle| retain ownership.
|
||||
generic_region = base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
|
||||
|
@ -99,8 +99,8 @@ SyncReader::SyncReader(
|
||||
shared_memory_mapping_ = shared_memory_region_.Map();
|
||||
if (shared_memory_region_.IsValid() && shared_memory_mapping_.IsValid() &&
|
||||
base::CancelableSyncSocket::CreatePair(&socket_, foreign_socket)) {
|
||||
auto* const buffer = reinterpret_cast<media::AudioOutputBuffer*>(
|
||||
shared_memory_mapping_.memory());
|
||||
auto* const buffer =
|
||||
shared_memory_mapping_.GetMemoryAs<media::AudioOutputBuffer>();
|
||||
output_bus_ = media::AudioBus::WrapMemory(params, buffer->audio);
|
||||
output_bus_->Zero();
|
||||
output_bus_->set_is_bitstream_format(params.IsBitstreamFormat());
|
||||
@ -140,8 +140,8 @@ void SyncReader::RequestMoreData(base::TimeDelta delay,
|
||||
// We don't send arguments over the socket since sending more than 4
|
||||
// bytes might lead to being descheduled. The reading side will zero
|
||||
// them when consumed.
|
||||
auto* const buffer = reinterpret_cast<media::AudioOutputBuffer*>(
|
||||
shared_memory_mapping_.memory());
|
||||
auto* const buffer =
|
||||
shared_memory_mapping_.GetMemoryAs<media::AudioOutputBuffer>();
|
||||
// Increase the number of skipped frames stored in shared memory.
|
||||
buffer->params.delay_us = delay.InMicroseconds();
|
||||
buffer->params.delay_timestamp_us =
|
||||
@ -215,8 +215,8 @@ bool SyncReader::Read(media::AudioBus* dest, bool is_mixing) {
|
||||
|
||||
if (output_bus_->is_bitstream_format()) {
|
||||
// For bitstream formats, we need the real data size and PCM frame count.
|
||||
auto* const buffer = reinterpret_cast<media::AudioOutputBuffer*>(
|
||||
shared_memory_mapping_.memory());
|
||||
auto* const buffer =
|
||||
shared_memory_mapping_.GetMemoryAs<media::AudioOutputBuffer>();
|
||||
uint32_t data_size = buffer->params.bitstream_data_size;
|
||||
uint32_t bitstream_frames = buffer->params.bitstream_frames;
|
||||
// |bitstream_frames| is cast to int below, so it must fit.
|
||||
|
@ -78,8 +78,7 @@ TEST_P(SyncReaderBitstreamTest, BitstreamBufferOverflow_DoesNotWriteOOB) {
|
||||
const base::WritableSharedMemoryMapping shmem =
|
||||
reader.TakeSharedMemoryRegion().Map();
|
||||
ASSERT_TRUE(shmem.IsValid());
|
||||
auto* const buffer =
|
||||
reinterpret_cast<media::AudioOutputBuffer*>(shmem.memory());
|
||||
auto* const buffer = shmem.GetMemoryAs<media::AudioOutputBuffer>();
|
||||
ASSERT_TRUE(buffer);
|
||||
reader.RequestMoreData(base::TimeDelta(), base::TimeTicks(), {});
|
||||
|
||||
@ -158,7 +157,7 @@ class SyncReaderTest : public ::testing::Test {
|
||||
reader_->set_max_wait_timeout_for_test(base::Milliseconds(999));
|
||||
shmem_ = reader_->TakeSharedMemoryRegion().Map();
|
||||
CHECK(shmem_.IsValid());
|
||||
buffer_ = reinterpret_cast<media::AudioOutputBuffer*>(shmem_.memory());
|
||||
buffer_ = shmem_.GetMemoryAs<media::AudioOutputBuffer>();
|
||||
CHECK(buffer_);
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,9 @@ namespace device {
|
||||
|
||||
class PlatformSensorProvider;
|
||||
class PlatformSensorConfiguration;
|
||||
struct SensorReadingSharedBuffer;
|
||||
template <class T>
|
||||
struct SensorReadingSharedBufferImpl;
|
||||
using SensorReadingSharedBuffer = SensorReadingSharedBufferImpl<void>;
|
||||
|
||||
// Base class for the sensors provided by the platform. Concrete instances of
|
||||
// this class are created by platform specific PlatformSensorProvider.
|
||||
|
@ -147,11 +147,10 @@ TEST_F(PlatformSensorAndProviderTest, SharedBufferDefaultValue) {
|
||||
base::ReadOnlySharedMemoryRegion region =
|
||||
provider_->CloneSharedMemoryRegion();
|
||||
base::ReadOnlySharedMemoryMapping mapping = region.MapAt(
|
||||
SensorReadingSharedBuffer::GetOffset(mojom::SensorType::AMBIENT_LIGHT),
|
||||
GetSensorReadingSharedBufferOffset(mojom::SensorType::AMBIENT_LIGHT),
|
||||
sizeof(SensorReadingSharedBuffer));
|
||||
|
||||
const SensorReadingSharedBuffer* buffer =
|
||||
static_cast<const SensorReadingSharedBuffer*>(mapping.memory());
|
||||
const auto* buffer = mapping.GetMemoryAs<SensorReadingSharedBuffer>();
|
||||
EXPECT_THAT(buffer->reading.als.value, 0);
|
||||
}
|
||||
|
||||
|
@ -531,7 +531,7 @@ TEST_F(PlatformSensorAndProviderLinuxTest, CheckAmbientLightReadings) {
|
||||
base::ReadOnlySharedMemoryRegion region =
|
||||
provider_->CloneSharedMemoryRegion();
|
||||
base::ReadOnlySharedMemoryMapping mapping = region.MapAt(
|
||||
SensorReadingSharedBuffer::GetOffset(mojom::SensorType::AMBIENT_LIGHT),
|
||||
GetSensorReadingSharedBufferOffset(mojom::SensorType::AMBIENT_LIGHT),
|
||||
sizeof(SensorReadingSharedBuffer));
|
||||
|
||||
double sensor_value[kSensorValuesSize] = {50};
|
||||
@ -552,7 +552,7 @@ TEST_F(PlatformSensorAndProviderLinuxTest, CheckAmbientLightReadings) {
|
||||
WaitOnSensorReadingChangedEvent(client.get(), sensor->GetType());
|
||||
|
||||
const SensorReadingSharedBuffer* buffer =
|
||||
static_cast<const SensorReadingSharedBuffer*>(mapping.memory());
|
||||
mapping.GetMemoryAs<SensorReadingSharedBuffer>();
|
||||
EXPECT_THAT(buffer->reading.als.value, 50);
|
||||
|
||||
EXPECT_TRUE(sensor->StopListening(client.get(), configuration));
|
||||
@ -564,7 +564,7 @@ TEST_F(PlatformSensorAndProviderLinuxTest,
|
||||
base::ReadOnlySharedMemoryRegion region =
|
||||
provider_->CloneSharedMemoryRegion();
|
||||
base::ReadOnlySharedMemoryMapping mapping = region.MapAt(
|
||||
SensorReadingSharedBuffer::GetOffset(SensorType::ACCELEROMETER),
|
||||
GetSensorReadingSharedBufferOffset(SensorType::ACCELEROMETER),
|
||||
sizeof(SensorReadingSharedBuffer));
|
||||
|
||||
// As long as WaitOnSensorReadingChangedEvent() waits until client gets a
|
||||
@ -594,7 +594,7 @@ TEST_F(PlatformSensorAndProviderLinuxTest,
|
||||
WaitOnSensorReadingChangedEvent(client.get(), sensor->GetType());
|
||||
|
||||
const SensorReadingSharedBuffer* buffer =
|
||||
static_cast<const SensorReadingSharedBuffer*>(mapping.memory());
|
||||
mapping.GetMemoryAs<SensorReadingSharedBuffer>();
|
||||
double scaling = kAccelerometerScalingValue;
|
||||
EXPECT_THAT(buffer->reading.accel.x,
|
||||
RoundAccelerometerValue(
|
||||
@ -624,7 +624,7 @@ TEST_F(PlatformSensorAndProviderLinuxTest, CheckLinearAcceleration) {
|
||||
base::ReadOnlySharedMemoryRegion region =
|
||||
provider_->CloneSharedMemoryRegion();
|
||||
base::ReadOnlySharedMemoryMapping mapping = region.MapAt(
|
||||
SensorReadingSharedBuffer::GetOffset(SensorType::LINEAR_ACCELERATION),
|
||||
GetSensorReadingSharedBufferOffset(SensorType::LINEAR_ACCELERATION),
|
||||
sizeof(SensorReadingSharedBuffer));
|
||||
double sensor_values[kSensorValuesSize] = {0, 0, -base::kMeanGravityDouble};
|
||||
InitializeSupportedSensor(SensorType::ACCELEROMETER,
|
||||
@ -648,7 +648,7 @@ TEST_F(PlatformSensorAndProviderLinuxTest, CheckLinearAcceleration) {
|
||||
WaitOnSensorReadingChangedEvent(client.get(), sensor->GetType());
|
||||
|
||||
const SensorReadingSharedBuffer* buffer =
|
||||
static_cast<const SensorReadingSharedBuffer*>(mapping.memory());
|
||||
mapping.GetMemoryAs<SensorReadingSharedBuffer>();
|
||||
EXPECT_THAT(buffer->reading.accel.x, 0.0);
|
||||
EXPECT_THAT(buffer->reading.accel.y, 0.0);
|
||||
EXPECT_THAT(static_cast<int>(buffer->reading.accel.z),
|
||||
@ -662,7 +662,7 @@ TEST_F(PlatformSensorAndProviderLinuxTest, CheckGyroscopeReadingConversion) {
|
||||
base::ReadOnlySharedMemoryRegion region =
|
||||
provider_->CloneSharedMemoryRegion();
|
||||
base::ReadOnlySharedMemoryMapping mapping =
|
||||
region.MapAt(SensorReadingSharedBuffer::GetOffset(SensorType::GYROSCOPE),
|
||||
region.MapAt(GetSensorReadingSharedBufferOffset(SensorType::GYROSCOPE),
|
||||
sizeof(SensorReadingSharedBuffer));
|
||||
|
||||
// As long as WaitOnSensorReadingChangedEvent() waits until client gets a
|
||||
@ -691,7 +691,7 @@ TEST_F(PlatformSensorAndProviderLinuxTest, CheckGyroscopeReadingConversion) {
|
||||
WaitOnSensorReadingChangedEvent(client.get(), sensor->GetType());
|
||||
|
||||
const SensorReadingSharedBuffer* buffer =
|
||||
static_cast<const SensorReadingSharedBuffer*>(mapping.memory());
|
||||
mapping.GetMemoryAs<SensorReadingSharedBuffer>();
|
||||
double scaling = kGyroscopeScalingValue;
|
||||
EXPECT_THAT(buffer->reading.gyro.x,
|
||||
RoundGyroscopeValue(scaling *
|
||||
@ -710,9 +710,9 @@ TEST_F(PlatformSensorAndProviderLinuxTest, CheckGyroscopeReadingConversion) {
|
||||
TEST_F(PlatformSensorAndProviderLinuxTest, CheckMagnetometerReadingConversion) {
|
||||
base::ReadOnlySharedMemoryRegion region =
|
||||
provider_->CloneSharedMemoryRegion();
|
||||
base::ReadOnlySharedMemoryMapping mapping = region.MapAt(
|
||||
SensorReadingSharedBuffer::GetOffset(SensorType::MAGNETOMETER),
|
||||
sizeof(SensorReadingSharedBuffer));
|
||||
base::ReadOnlySharedMemoryMapping mapping =
|
||||
region.MapAt(GetSensorReadingSharedBufferOffset(SensorType::MAGNETOMETER),
|
||||
sizeof(SensorReadingSharedBuffer));
|
||||
|
||||
// As long as WaitOnSensorReadingChangedEvent() waits until client gets a
|
||||
// a notification about readings changed, the frequency file must not be
|
||||
@ -741,7 +741,7 @@ TEST_F(PlatformSensorAndProviderLinuxTest, CheckMagnetometerReadingConversion) {
|
||||
WaitOnSensorReadingChangedEvent(client.get(), sensor->GetType());
|
||||
|
||||
const SensorReadingSharedBuffer* buffer =
|
||||
static_cast<const SensorReadingSharedBuffer*>(mapping.memory());
|
||||
mapping.GetMemoryAs<SensorReadingSharedBuffer>();
|
||||
double scaling = kMagnetometerScalingValue * kMicroteslaInGauss;
|
||||
EXPECT_THAT(buffer->reading.magn.x,
|
||||
RoundMagnetometerValue(
|
||||
@ -764,7 +764,7 @@ TEST_F(PlatformSensorAndProviderLinuxTest,
|
||||
base::ReadOnlySharedMemoryRegion region =
|
||||
provider_->CloneSharedMemoryRegion();
|
||||
base::ReadOnlySharedMemoryMapping mapping = region.MapAt(
|
||||
SensorReadingSharedBuffer::GetOffset(SensorType::AMBIENT_LIGHT),
|
||||
GetSensorReadingSharedBufferOffset(SensorType::AMBIENT_LIGHT),
|
||||
sizeof(SensorReadingSharedBuffer));
|
||||
|
||||
double sensor_value[kSensorValuesSize] = {50};
|
||||
@ -790,7 +790,7 @@ TEST_F(PlatformSensorAndProviderLinuxTest,
|
||||
WaitOnSensorReadingChangedEvent(client.get(), sensor->GetType());
|
||||
|
||||
const SensorReadingSharedBuffer* buffer =
|
||||
static_cast<const SensorReadingSharedBuffer*>(mapping.memory());
|
||||
mapping.GetMemoryAs<SensorReadingSharedBuffer>();
|
||||
EXPECT_THAT(buffer->reading.als.value, 50);
|
||||
|
||||
EXPECT_TRUE(sensor->StopListening(client.get(), configuration));
|
||||
|
@ -545,7 +545,7 @@ TEST_F(PlatformSensorAndProviderTestWin, CheckAccelerometerReadingConversion) {
|
||||
base::ReadOnlySharedMemoryRegion region =
|
||||
provider_->CloneSharedMemoryRegion();
|
||||
base::ReadOnlySharedMemoryMapping mapping = region.MapAt(
|
||||
SensorReadingSharedBuffer::GetOffset(SensorType::ACCELEROMETER),
|
||||
GetSensorReadingSharedBufferOffset(SensorType::ACCELEROMETER),
|
||||
sizeof(SensorReadingSharedBuffer));
|
||||
|
||||
SetSupportedSensor(SENSOR_TYPE_ACCELEROMETER_3D);
|
||||
@ -587,7 +587,7 @@ TEST_F(PlatformSensorAndProviderTestWin, CheckGyroscopeReadingConversion) {
|
||||
base::ReadOnlySharedMemoryRegion region =
|
||||
provider_->CloneSharedMemoryRegion();
|
||||
base::ReadOnlySharedMemoryMapping mapping =
|
||||
region.MapAt(SensorReadingSharedBuffer::GetOffset(SensorType::GYROSCOPE),
|
||||
region.MapAt(GetSensorReadingSharedBufferOffset(SensorType::GYROSCOPE),
|
||||
sizeof(SensorReadingSharedBuffer));
|
||||
|
||||
SetSupportedSensor(SENSOR_TYPE_GYROMETER_3D);
|
||||
@ -629,9 +629,9 @@ TEST_F(PlatformSensorAndProviderTestWin, CheckGyroscopeReadingConversion) {
|
||||
TEST_F(PlatformSensorAndProviderTestWin, CheckMagnetometerReadingConversion) {
|
||||
base::ReadOnlySharedMemoryRegion region =
|
||||
provider_->CloneSharedMemoryRegion();
|
||||
base::ReadOnlySharedMemoryMapping mapping = region.MapAt(
|
||||
SensorReadingSharedBuffer::GetOffset(SensorType::MAGNETOMETER),
|
||||
sizeof(SensorReadingSharedBuffer));
|
||||
base::ReadOnlySharedMemoryMapping mapping =
|
||||
region.MapAt(GetSensorReadingSharedBufferOffset(SensorType::MAGNETOMETER),
|
||||
sizeof(SensorReadingSharedBuffer));
|
||||
|
||||
SetSupportedSensor(SENSOR_TYPE_COMPASS_3D);
|
||||
auto sensor = CreateSensor(SensorType::MAGNETOMETER);
|
||||
@ -672,7 +672,7 @@ TEST_F(PlatformSensorAndProviderTestWin,
|
||||
base::ReadOnlySharedMemoryRegion region =
|
||||
provider_->CloneSharedMemoryRegion();
|
||||
base::ReadOnlySharedMemoryMapping mapping =
|
||||
region.MapAt(SensorReadingSharedBuffer::GetOffset(
|
||||
region.MapAt(GetSensorReadingSharedBufferOffset(
|
||||
SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES),
|
||||
sizeof(SensorReadingSharedBuffer));
|
||||
|
||||
@ -715,7 +715,7 @@ TEST_F(PlatformSensorAndProviderTestWin,
|
||||
base::ReadOnlySharedMemoryRegion region =
|
||||
provider_->CloneSharedMemoryRegion();
|
||||
base::ReadOnlySharedMemoryMapping mapping =
|
||||
region.MapAt(SensorReadingSharedBuffer::GetOffset(
|
||||
region.MapAt(GetSensorReadingSharedBufferOffset(
|
||||
SensorType::ABSOLUTE_ORIENTATION_QUATERNION),
|
||||
sizeof(SensorReadingSharedBuffer));
|
||||
|
||||
|
@ -207,14 +207,19 @@ PlatformSensorProvider::GetPendingRequestTypes() {
|
||||
SensorReadingSharedBuffer*
|
||||
PlatformSensorProvider::GetSensorReadingSharedBufferForType(
|
||||
mojom::SensorType type) {
|
||||
auto* ptr = static_cast<char*>(mapped_region_.mapping.memory());
|
||||
if (!ptr) {
|
||||
base::span<SensorReadingSharedBuffer> buffers =
|
||||
mapped_region_.mapping.GetMemoryAsSpan<SensorReadingSharedBuffer>();
|
||||
if (buffers.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ptr += SensorReadingSharedBuffer::GetOffset(type);
|
||||
memset(ptr, 0, kReadingBufferSize);
|
||||
return reinterpret_cast<SensorReadingSharedBuffer*>(ptr);
|
||||
size_t offset = GetSensorReadingSharedBufferOffset(type);
|
||||
CHECK(offset % sizeof(SensorReadingSharedBuffer) == 0u);
|
||||
|
||||
SensorReadingSharedBuffer& buffer =
|
||||
buffers[offset / sizeof(SensorReadingSharedBuffer)];
|
||||
std::ranges::fill(base::byte_span_from_ref(buffer), 0u);
|
||||
return &buffer;
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
|
@ -142,7 +142,7 @@ void SensorProviderImpl::SensorCreated(
|
||||
|
||||
init_params->memory = std::move(cloned_region);
|
||||
init_params->buffer_offset =
|
||||
SensorReadingSharedBuffer::GetOffset(sensor->GetType());
|
||||
GetSensorReadingSharedBufferOffset(sensor->GetType());
|
||||
init_params->mode = sensor->GetReportingMode();
|
||||
|
||||
double maximum_frequency = sensor->GetMaximumSupportedFrequency();
|
||||
|
@ -6,11 +6,7 @@
|
||||
|
||||
namespace device {
|
||||
|
||||
SensorReadingSharedBuffer::SensorReadingSharedBuffer() = default;
|
||||
SensorReadingSharedBuffer::~SensorReadingSharedBuffer() = default;
|
||||
|
||||
// static
|
||||
uint64_t SensorReadingSharedBuffer::GetOffset(mojom::SensorType type) {
|
||||
uint64_t GetSensorReadingSharedBufferOffset(mojom::SensorType type) {
|
||||
return static_cast<uint64_t>(type) * sizeof(SensorReadingSharedBuffer);
|
||||
}
|
||||
|
||||
|
@ -13,16 +13,25 @@ namespace device {
|
||||
|
||||
// This structure represents sensor reading buffer: sensor reading and seqlock
|
||||
// for synchronization.
|
||||
struct SensorReadingSharedBuffer {
|
||||
SensorReadingSharedBuffer();
|
||||
~SensorReadingSharedBuffer();
|
||||
//
|
||||
// TODO(crbug.com/355003174): It's a template to avoid the clang plugin that
|
||||
// prevents inline ctors, as we need the class to be trivially copyable for use
|
||||
// in shared memory.
|
||||
template <class T = void>
|
||||
struct SensorReadingSharedBufferImpl {
|
||||
SensorReadingField<OneWriterSeqLock> seqlock;
|
||||
SensorReading reading;
|
||||
|
||||
// Gets the shared reading buffer offset for the given sensor type.
|
||||
static uint64_t GetOffset(mojom::SensorType type);
|
||||
};
|
||||
|
||||
using SensorReadingSharedBuffer = SensorReadingSharedBufferImpl<void>;
|
||||
|
||||
// Gets the shared reading buffer offset for the given sensor type.
|
||||
uint64_t GetSensorReadingSharedBufferOffset(mojom::SensorType type);
|
||||
|
||||
// SensorReadingSharedBuffer is used in shared memory, so it must be trivially
|
||||
// copyable.
|
||||
static_assert(std::is_trivially_copyable_v<SensorReadingSharedBuffer>);
|
||||
|
||||
} // namespace device
|
||||
|
||||
#endif // SERVICES_DEVICE_PUBLIC_CPP_GENERIC_SENSOR_SENSOR_READING_SHARED_BUFFER_H_
|
||||
|
@ -44,14 +44,8 @@ SensorReadingSharedBufferReader::Create(base::ReadOnlySharedMemoryRegion region,
|
||||
|
||||
bool SensorReadingSharedBufferReader::GetReading(SensorReading* result) {
|
||||
DCHECK(mapping_.IsValid());
|
||||
|
||||
// TODO(someone): This *should* use GetMemoryAs, but SensorReadingSharedBuffer
|
||||
// is not considered trivially copyable. Maybe there's a better trait to
|
||||
// use...
|
||||
const auto* buffer =
|
||||
static_cast<const device::SensorReadingSharedBuffer*>(mapping_.memory());
|
||||
|
||||
return GetReading(buffer, result);
|
||||
return GetReading(mapping_.GetMemoryAs<device::SensorReadingSharedBuffer>(),
|
||||
result);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -13,7 +13,9 @@
|
||||
namespace device {
|
||||
|
||||
union SensorReading;
|
||||
struct SensorReadingSharedBuffer;
|
||||
template <class T>
|
||||
struct SensorReadingSharedBufferImpl;
|
||||
using SensorReadingSharedBuffer = SensorReadingSharedBufferImpl<void>;
|
||||
|
||||
class SensorReadingSharedBufferReader {
|
||||
public:
|
||||
|
@ -80,7 +80,7 @@ mojo::PendingReceiver<mojom::SensorClient> FakeSensor::GetClient() {
|
||||
}
|
||||
|
||||
uint64_t FakeSensor::GetBufferOffset() {
|
||||
return SensorReadingSharedBuffer::GetOffset(sensor_type_);
|
||||
return GetSensorReadingSharedBufferOffset(sensor_type_);
|
||||
}
|
||||
|
||||
void FakeSensor::SetReading(SensorReading reading) {
|
||||
@ -333,13 +333,19 @@ bool FakeSensorProvider::CreateSharedBufferIfNeeded() {
|
||||
SensorReadingSharedBuffer*
|
||||
FakeSensorProvider::GetSensorReadingSharedBufferForType(
|
||||
mojom::SensorType type) {
|
||||
auto* ptr = static_cast<char*>(mapped_region_.mapping.memory());
|
||||
if (!ptr)
|
||||
base::span<SensorReadingSharedBuffer> buffers =
|
||||
mapped_region_.mapping.GetMemoryAsSpan<SensorReadingSharedBuffer>();
|
||||
if (buffers.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ptr += SensorReadingSharedBuffer::GetOffset(type);
|
||||
memset(ptr, 0, kReadingBufferSize);
|
||||
return reinterpret_cast<SensorReadingSharedBuffer*>(ptr);
|
||||
size_t offset = GetSensorReadingSharedBufferOffset(type);
|
||||
CHECK(offset % sizeof(SensorReadingSharedBuffer) == 0u);
|
||||
|
||||
SensorReadingSharedBuffer& buffer =
|
||||
buffers[offset / sizeof(SensorReadingSharedBuffer)];
|
||||
std::ranges::fill(base::byte_span_from_ref(buffer), 0u);
|
||||
return &buffer;
|
||||
}
|
||||
|
||||
} // namespace device
|
||||
|
@ -16,7 +16,9 @@
|
||||
|
||||
namespace device {
|
||||
|
||||
struct SensorReadingSharedBuffer;
|
||||
template <class T>
|
||||
struct SensorReadingSharedBufferImpl;
|
||||
using SensorReadingSharedBuffer = SensorReadingSharedBufferImpl<void>;
|
||||
|
||||
class FakeSensor : public mojom::Sensor {
|
||||
public:
|
||||
|
@ -37,7 +37,7 @@ void EchoService::EchoStringToSharedMemory(
|
||||
const std::string& input,
|
||||
base::UnsafeSharedMemoryRegion region) {
|
||||
base::WritableSharedMemoryMapping mapping = region.Map();
|
||||
memcpy(mapping.memory(), input.data(), input.size());
|
||||
base::span(mapping).copy_prefix_from(base::as_byte_span(input));
|
||||
}
|
||||
|
||||
void EchoService::Quit() {
|
||||
|
@ -136,15 +136,14 @@ base::ReadOnlySharedMemoryRegion CreateTracingConfigSharedMemory() {
|
||||
return base::ReadOnlySharedMemoryRegion();
|
||||
}
|
||||
|
||||
auto serialized_config = trace_config.SerializeAsArray();
|
||||
std::vector<uint8_t> serialized_config = trace_config.SerializeAsArray();
|
||||
|
||||
base::MappedReadOnlyRegion shm =
|
||||
base::ReadOnlySharedMemoryRegion::Create(serialized_config.size());
|
||||
if (!shm.IsValid()) {
|
||||
return base::ReadOnlySharedMemoryRegion();
|
||||
}
|
||||
memcpy(shm.mapping.memory(), serialized_config.data(),
|
||||
serialized_config.size());
|
||||
base::span(shm.mapping).copy_from(serialized_config);
|
||||
return std::move(shm.region);
|
||||
}
|
||||
|
||||
|
@ -264,7 +264,9 @@ bool TraceStartupConfig::EnableFromConfigHandle() {
|
||||
<< "Invald memory region passed on command line.";
|
||||
|
||||
base::ReadOnlySharedMemoryMapping mapping = shmem_region->Map();
|
||||
if (!perfetto_config_.ParseFromArray(mapping.memory(), mapping.size())) {
|
||||
base::span<const uint8_t> mapping_mem(mapping);
|
||||
if (!perfetto_config_.ParseFromArray(mapping_mem.data(),
|
||||
mapping_mem.size())) {
|
||||
DLOG(WARNING) << "Could not parse --" << switches::kTraceConfigHandle;
|
||||
return false;
|
||||
}
|
||||
|
@ -3,16 +3,19 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "third_party/blink/public/common/font_unique_name_lookup/font_table_matcher.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "third_party/blink/public/common/font_unique_name_lookup/icu_fold_case_util.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/containers/span.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "third_party/blink/public/common/font_unique_name_lookup/icu_fold_case_util.h"
|
||||
|
||||
namespace blink {
|
||||
|
||||
FontTableMatcher::FontTableMatcher(
|
||||
const base::ReadOnlySharedMemoryMapping& mapping) {
|
||||
font_table_.ParseFromArray(mapping.memory(), mapping.size());
|
||||
base::span<const uint8_t> mem(mapping);
|
||||
font_table_.ParseFromArray(mem.data(), mem.size());
|
||||
}
|
||||
|
||||
// static
|
||||
@ -24,8 +27,8 @@ FontTableMatcher::MemoryMappingFromFontUniqueNameTable(
|
||||
base::MappedReadOnlyRegion mapped_region =
|
||||
base::ReadOnlySharedMemoryRegion::Create(serialization_size);
|
||||
CHECK(mapped_region.IsValid());
|
||||
font_unique_name_table.SerializeToArray(mapped_region.mapping.memory(),
|
||||
mapped_region.mapping.mapped_size());
|
||||
base::span<uint8_t> mem(mapped_region.mapping);
|
||||
font_unique_name_table.SerializeToArray(mem.data(), mem.size());
|
||||
return mapped_region.region.Map();
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ bool LoadFromFile(base::FilePath file_path,
|
||||
return false;
|
||||
}
|
||||
|
||||
name_table_region->mapping.GetMemoryAsSpan<uint8_t>().copy_from(proto);
|
||||
base::span(name_table_region->mapping).copy_from(proto);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -90,11 +90,9 @@ bool PersistToFile(const base::MappedReadOnlyRegion& name_table_region,
|
||||
}
|
||||
|
||||
base::Pickle pickle;
|
||||
uint32_t checksum = base::PersistentHash(
|
||||
name_table_region.mapping.GetMemoryAsSpan<const uint8_t>());
|
||||
uint32_t checksum = base::PersistentHash(name_table_region.mapping);
|
||||
pickle.WriteUInt32(checksum);
|
||||
pickle.WriteData(static_cast<char*>(name_table_region.mapping.memory()),
|
||||
name_table_region.mapping.size());
|
||||
pickle.WriteData(name_table_region.mapping);
|
||||
DCHECK(pickle.size());
|
||||
{
|
||||
base::ScopedBlockingCall scoped_blocking_call(
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/feature_list.h"
|
||||
#include "base/numerics/safe_conversions.h"
|
||||
#include "third_party/blink/public/common/features.h"
|
||||
#include "third_party/blink/public/common/font_access/font_enumeration_table.pb.h"
|
||||
#include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom-blink.h"
|
||||
@ -150,7 +151,9 @@ void FontAccess::DidGetEnumerationResponse(
|
||||
}
|
||||
|
||||
HeapVector<Member<FontMetadata>> entries;
|
||||
table.ParseFromArray(mapping.memory(), static_cast<int>(mapping.size()));
|
||||
base::span<const uint8_t> mapped_mem(mapping);
|
||||
table.ParseFromArray(mapped_mem.data(),
|
||||
base::checked_cast<int>(mapped_mem.size()));
|
||||
for (const auto& element : table.fonts()) {
|
||||
// If the optional postscript name filter is set in QueryOptions,
|
||||
// only allow items that match.
|
||||
|
@ -14,7 +14,9 @@
|
||||
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
|
||||
|
||||
namespace device {
|
||||
class Gamepad;
|
||||
template <class T>
|
||||
class GamepadImpl;
|
||||
using Gamepad = GamepadImpl<void>;
|
||||
class Gamepads;
|
||||
} // namespace device
|
||||
|
||||
|
@ -6,7 +6,9 @@
|
||||
#define THIRD_PARTY_BLINK_RENDERER_MODULES_GAMEPAD_GAMEPAD_LISTENER_H_
|
||||
|
||||
namespace device {
|
||||
class Gamepad;
|
||||
template <class T>
|
||||
class GamepadImpl;
|
||||
using Gamepad = GamepadImpl<void>;
|
||||
}
|
||||
|
||||
namespace blink {
|
||||
|
@ -61,10 +61,9 @@ void GamepadSharedMemoryReader::Start(blink::GamepadListener* listener) {
|
||||
|
||||
renderer_shared_buffer_mapping_ = renderer_shared_buffer_region_.Map();
|
||||
CHECK(renderer_shared_buffer_mapping_.IsValid());
|
||||
const void* memory = renderer_shared_buffer_mapping_.memory();
|
||||
CHECK(memory);
|
||||
gamepad_hardware_buffer_ =
|
||||
static_cast<const device::GamepadHardwareBuffer*>(memory);
|
||||
gamepad_hardware_buffer_ = renderer_shared_buffer_mapping_
|
||||
.GetMemoryAs<device::GamepadHardwareBuffer>();
|
||||
CHECK(gamepad_hardware_buffer_);
|
||||
}
|
||||
|
||||
void GamepadSharedMemoryReader::Stop() {
|
||||
|
@ -18,7 +18,9 @@ class ReadOnlySharedMemoryRegion;
|
||||
}
|
||||
|
||||
namespace device {
|
||||
class Gamepad;
|
||||
template <class T>
|
||||
class GamepadImpl;
|
||||
using Gamepad = GamepadImpl<void>;
|
||||
class Gamepads;
|
||||
} // namespace device
|
||||
|
||||
|
@ -41,7 +41,9 @@
|
||||
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
|
||||
|
||||
namespace device {
|
||||
class Gamepad;
|
||||
template <class T>
|
||||
class GamepadImpl;
|
||||
using Gamepad = GamepadImpl<void>;
|
||||
}
|
||||
|
||||
namespace blink {
|
||||
|
@ -19,7 +19,9 @@
|
||||
#include "ui/gfx/geometry/transform.h"
|
||||
|
||||
namespace device {
|
||||
class Gamepad;
|
||||
template <class T>
|
||||
class GamepadImpl;
|
||||
using Gamepad = GamepadImpl<void>;
|
||||
}
|
||||
|
||||
namespace blink {
|
||||
|
@ -326,8 +326,9 @@ scoped_refptr<StaticBitmapImage> CanvasResourceSharedBitmap::Bitmap() {
|
||||
// the SkImage is destroyed.
|
||||
SkImageInfo image_info = SkImageInfo::Make(
|
||||
SkISize::Make(Size().width(), Size().height()), GetSkColorInfo());
|
||||
SkPixmap pixmap(image_info, shared_mapping_.memory(),
|
||||
image_info.minRowBytes());
|
||||
base::span<uint8_t> bytes(shared_mapping_);
|
||||
CHECK_GE(bytes.size(), image_info.computeByteSize(image_info.minRowBytes()));
|
||||
SkPixmap pixmap(image_info, bytes.data(), image_info.minRowBytes());
|
||||
AddRef();
|
||||
sk_sp<SkImage> sk_image = SkImages::RasterFromPixmap(
|
||||
pixmap,
|
||||
@ -390,8 +391,10 @@ void CanvasResourceSharedBitmap::NotifyResourceLost() {
|
||||
void CanvasResourceSharedBitmap::TakeSkImage(sk_sp<SkImage> image) {
|
||||
SkImageInfo image_info = SkImageInfo::Make(
|
||||
SkISize::Make(Size().width(), Size().height()), GetSkColorInfo());
|
||||
base::span<uint8_t> bytes(shared_mapping_);
|
||||
CHECK_GE(bytes.size(), image_info.computeByteSize(image_info.minRowBytes()));
|
||||
bool read_pixels_successful = image->readPixels(
|
||||
image_info, shared_mapping_.memory(), image_info.minRowBytes(), 0, 0);
|
||||
image_info, bytes.data(), image_info.minRowBytes(), 0, 0);
|
||||
DCHECK(read_pixels_successful);
|
||||
}
|
||||
|
||||
|
@ -163,8 +163,8 @@ void SynchronousCompositorProxy::ZeroSharedMemory() {
|
||||
if (software_draw_shm_->zeroed)
|
||||
return;
|
||||
|
||||
memset(software_draw_shm_->shared_memory.memory(), 0,
|
||||
software_draw_shm_->buffer_size);
|
||||
base::span<uint8_t> mem(software_draw_shm_->shared_memory);
|
||||
std::ranges::fill(mem.first(software_draw_shm_->buffer_size), 0u);
|
||||
software_draw_shm_->zeroed = true;
|
||||
}
|
||||
|
||||
@ -203,9 +203,10 @@ void SynchronousCompositorProxy::DoDemandDrawSw(
|
||||
size_t buffer_size = info.computeByteSize(stride);
|
||||
DCHECK_EQ(software_draw_shm_->buffer_size, buffer_size);
|
||||
|
||||
base::span<uint8_t> mem(software_draw_shm_->shared_memory);
|
||||
CHECK_GE(mem.size(), buffer_size);
|
||||
SkBitmap bitmap;
|
||||
if (!bitmap.installPixels(info, software_draw_shm_->shared_memory.memory(),
|
||||
stride)) {
|
||||
if (!bitmap.installPixels(info, mem.data(), stride)) {
|
||||
return;
|
||||
}
|
||||
SkCanvas canvas(bitmap);
|
||||
|
@ -27,7 +27,7 @@ bool GLSurfaceEglReadback::Resize(const gfx::Size& size,
|
||||
float scale_factor,
|
||||
const gfx::ColorSpace& color_space,
|
||||
bool has_alpha) {
|
||||
pixels_.reset();
|
||||
pixels_ = base::HeapArray<uint8_t>();
|
||||
|
||||
if (!PbufferGLSurfaceEGL::Resize(size, scale_factor, color_space, has_alpha))
|
||||
return false;
|
||||
@ -42,7 +42,7 @@ bool GLSurfaceEglReadback::Resize(const gfx::Size& size,
|
||||
|
||||
// Allocate a new buffer for readback.
|
||||
const size_t buffer_size = size.width() * size.height() * kBytesPerPixelBGRA;
|
||||
pixels_ = std::make_unique<uint8_t[]>(buffer_size);
|
||||
pixels_ = base::HeapArray<uint8_t>::Uninit(buffer_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -52,9 +52,9 @@ gfx::SwapResult GLSurfaceEglReadback::SwapBuffers(PresentationCallback callback,
|
||||
gfx::SwapResult swap_result = gfx::SwapResult::SWAP_FAILED;
|
||||
gfx::PresentationFeedback feedback;
|
||||
|
||||
if (pixels_) {
|
||||
ReadPixels(pixels_.get());
|
||||
if (HandlePixels(pixels_.get())) {
|
||||
if (!pixels_.empty()) {
|
||||
ReadPixels(pixels_.as_span());
|
||||
if (HandlePixels(pixels_.as_span().data())) {
|
||||
// Swap is successful, so return SWAP_ACK and provide the current time
|
||||
// with presentation feedback.
|
||||
swap_result = gfx::SwapResult::SWAP_ACK;
|
||||
@ -82,7 +82,7 @@ bool GLSurfaceEglReadback::HandlePixels(uint8_t* pixels) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLSurfaceEglReadback::ReadPixels(void* buffer) {
|
||||
void GLSurfaceEglReadback::ReadPixels(base::span<uint8_t> buffer) {
|
||||
const gfx::Size size = GetSize();
|
||||
GLint read_fbo = 0;
|
||||
GLint pixel_pack_buffer = 0;
|
||||
@ -98,8 +98,10 @@ void GLSurfaceEglReadback::ReadPixels(void* buffer) {
|
||||
if (pixel_pack_buffer)
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
|
||||
CHECK_GE(buffer.size() / base::checked_cast<size_t>(size.width()),
|
||||
base::checked_cast<size_t>(size.height()));
|
||||
glReadPixels(0, 0, size.width(), size.height(), GL_BGRA, GL_UNSIGNED_BYTE,
|
||||
buffer);
|
||||
buffer.data());
|
||||
|
||||
if (read_fbo)
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER, read_fbo);
|
||||
|
@ -5,8 +5,8 @@
|
||||
#ifndef UI_OZONE_COMMON_GL_SURFACE_EGL_READBACK_H_
|
||||
#define UI_OZONE_COMMON_GL_SURFACE_EGL_READBACK_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/containers/heap_array.h"
|
||||
#include "base/containers/span.h"
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "ui/gfx/native_widget_types.h"
|
||||
#include "ui/gl/gl_surface_egl.h"
|
||||
@ -44,14 +44,16 @@ class GLSurfaceEglReadback : public gl::PbufferGLSurfaceEGL {
|
||||
// Implementations should override this, use the pixels data and then return
|
||||
// true if succesful. Should return true on succesful swap or false on swap
|
||||
// failure.
|
||||
virtual bool HandlePixels(uint8_t* pixels);
|
||||
//
|
||||
// TODO(danakj): This method should take a span, like ReadPixels.
|
||||
UNSAFE_BUFFER_USAGE virtual bool HandlePixels(uint8_t* pixels);
|
||||
|
||||
// Reads pixels with glReadPixels from fbo to |buffer|.
|
||||
void ReadPixels(void* buffer);
|
||||
void ReadPixels(base::span<uint8_t> buffer);
|
||||
|
||||
private:
|
||||
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
|
||||
std::unique_ptr<uint8_t[]> pixels_;
|
||||
base::HeapArray<uint8_t> pixels_;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
@ -114,8 +114,7 @@ void GLSurfaceEglReadbackWayland::SwapBuffersAsync(
|
||||
auto* next_buffer = in_flight_pixel_buffers_.back().get();
|
||||
available_buffers_.erase(available_buffers_.begin());
|
||||
|
||||
CHECK(next_buffer->shm_mapping_.memory());
|
||||
ReadPixels(next_buffer->shm_mapping_.memory());
|
||||
ReadPixels(next_buffer->shm_mapping_);
|
||||
|
||||
const auto bounds = gfx::Rect(GetSize());
|
||||
constexpr bool enable_blend_for_shadow = true;
|
||||
|
Reference in New Issue
Block a user