blob: 3e63972d11ba961b89c08509f6fef1f2febaffdb [file] [log] [blame]
// Copyright 2021 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef IREE_HAL_CTS_BUFFER_MAPPING_TEST_H_
#define IREE_HAL_CTS_BUFFER_MAPPING_TEST_H_
#include <cstdint>
#include <vector>
#include "iree/base/api.h"
#include "iree/hal/api.h"
#include "iree/hal/cts/cts_test_base.h"
#include "iree/testing/gtest.h"
#include "iree/testing/status_matchers.h"
namespace iree::hal::cts {
using ::testing::ContainerEq;
namespace {
constexpr iree_device_size_t kDefaultAllocationSize = 1024;
} // namespace
// Tests for buffer mapping (IREE_HAL_BUFFER_USAGE_MAPPING) support and
// for `iree_hal_buffer_*` functions which require buffer mapping.
//
// Note that most of these tests first write into a buffer using one or more
// functions then read the (possibly partial) contents of that buffer using
// `iree_hal_buffer_map_read`. As the buffer read implementation is
// nontrivial, particularly on implementations with complex host/device splits,
// test failures may indicate issues in either the code doing the writing or the
// code doing the reading.
//
// Where applicable, tests for each function are organized in increasing order
// of complexity, such as:
// * write to full buffer
// * write with an offset and length
// * write into a subspan of a buffer
class BufferMappingTest : public CTSTestBase<> {
protected:
void AllocateUninitializedBuffer(iree_device_size_t buffer_size,
iree_hal_buffer_t** out_buffer) {
iree_hal_buffer_params_t params = {0};
params.type =
IREE_HAL_MEMORY_TYPE_DEVICE_LOCAL | IREE_HAL_MEMORY_TYPE_HOST_VISIBLE;
params.usage =
IREE_HAL_BUFFER_USAGE_TRANSFER | IREE_HAL_BUFFER_USAGE_MAPPING;
iree_hal_buffer_t* device_buffer = NULL;
IREE_CHECK_OK(iree_hal_allocator_allocate_buffer(
iree_hal_device_allocator(device_), params, buffer_size,
&device_buffer));
*out_buffer = device_buffer;
}
};
TEST_F(BufferMappingTest, AllocatorSupportsBufferMapping) {
iree_hal_buffer_params_t params = {0};
params.type = IREE_HAL_MEMORY_TYPE_HOST_VISIBLE;
params.usage = IREE_HAL_BUFFER_USAGE_MAPPING;
iree_device_size_t allocation_size = 0;
iree_hal_buffer_compatibility_t compatibility =
iree_hal_allocator_query_buffer_compatibility(device_allocator_, params,
kDefaultAllocationSize,
&params, &allocation_size);
EXPECT_TRUE(iree_all_bits_set(compatibility,
IREE_HAL_BUFFER_COMPATIBILITY_ALLOCATABLE));
iree_hal_buffer_t* buffer = NULL;
AllocateUninitializedBuffer(allocation_size, &buffer);
EXPECT_TRUE(
iree_all_bits_set(iree_hal_buffer_memory_type(buffer), params.type));
EXPECT_TRUE(
iree_all_bits_set(iree_hal_buffer_allowed_usage(buffer), params.usage));
EXPECT_GE(iree_hal_buffer_allocation_size(buffer), allocation_size);
iree_hal_buffer_release(buffer);
}
TEST_F(BufferMappingTest, ZeroWholeBuffer) {
iree_hal_buffer_t* buffer = NULL;
AllocateUninitializedBuffer(kDefaultAllocationSize, &buffer);
// Zero the entire buffer.
IREE_ASSERT_OK(iree_hal_buffer_map_zero(buffer, /*byte_offset=*/0,
IREE_HAL_WHOLE_BUFFER));
// Check that the contents match what we expect.
std::vector<uint8_t> actual_data(kDefaultAllocationSize);
IREE_ASSERT_OK(iree_hal_buffer_map_read(
buffer, /*source_offset=*/0, actual_data.data(), actual_data.size()));
std::vector<uint8_t> reference_buffer(kDefaultAllocationSize);
std::memset(reference_buffer.data(), 0, kDefaultAllocationSize);
EXPECT_THAT(actual_data, ContainerEq(reference_buffer));
iree_hal_buffer_release(buffer);
}
TEST_F(BufferMappingTest, ZeroWithOffset) {
iree_device_size_t buffer_size = 16;
iree_hal_buffer_t* buffer = NULL;
AllocateUninitializedBuffer(buffer_size, &buffer);
// Fill the entire buffer then zero only a segment of it.
uint8_t fill_value = 0xFF;
IREE_ASSERT_OK(iree_hal_buffer_map_fill(buffer, /*byte_offset=*/0,
IREE_HAL_WHOLE_BUFFER, &fill_value,
sizeof(fill_value)));
IREE_ASSERT_OK(
iree_hal_buffer_map_zero(buffer, /*byte_offset=*/4, /*byte_length=*/8));
// Check that the contents match what we expect.
std::vector<uint8_t> actual_data(buffer_size);
IREE_ASSERT_OK(iree_hal_buffer_map_read(
buffer, /*source_offset=*/0, actual_data.data(), actual_data.size()));
std::vector<uint8_t> reference_buffer{0xFF, 0xFF, 0xFF, 0xFF, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0xFF, 0xFF, 0xFF, 0xFF};
EXPECT_THAT(actual_data, ContainerEq(reference_buffer));
iree_hal_buffer_release(buffer);
}
TEST_F(BufferMappingTest, ZeroSubspan) {
iree_device_size_t buffer_size = 16;
iree_hal_buffer_t* buffer = NULL;
AllocateUninitializedBuffer(buffer_size, &buffer);
// Fill the entire buffer.
uint8_t fill_value = 0xFF;
IREE_ASSERT_OK(iree_hal_buffer_map_fill(buffer, /*byte_offset=*/0,
IREE_HAL_WHOLE_BUFFER, &fill_value,
sizeof(fill_value)));
// Create a subspan.
iree_device_size_t subspan_length = 8;
iree_hal_buffer_t* buffer_subspan = NULL;
IREE_ASSERT_OK(
iree_hal_buffer_subspan(buffer, /*byte_offset=*/4, subspan_length,
iree_allocator_system(), &buffer_subspan));
// Zero part of the subspan.
IREE_ASSERT_OK(iree_hal_buffer_map_zero(buffer_subspan, /*byte_offset=*/4,
/*byte_length=*/4));
// Check that the contents match what we expect.
std::vector<uint8_t> actual_data(buffer_size);
IREE_ASSERT_OK(iree_hal_buffer_map_read(
buffer, /*source_offset=*/0, actual_data.data(), actual_data.size()));
std::vector<uint8_t> reference_buffer{0xFF, 0xFF, 0xFF, 0xFF, //
0xFF, 0xFF, 0xFF, 0xFF, //
0x00, 0x00, 0x00, 0x00, //
0xFF, 0xFF, 0xFF, 0xFF};
EXPECT_THAT(actual_data, ContainerEq(reference_buffer));
// Also check the subspan.
std::vector<uint8_t> actual_data_subspan(subspan_length);
IREE_ASSERT_OK(iree_hal_buffer_map_read(buffer_subspan, /*source_offset=*/0,
actual_data_subspan.data(),
actual_data_subspan.size()));
std::vector<uint8_t> reference_buffer_subspan{0xFF, 0xFF, 0xFF, 0xFF, //
0x00, 0x00, 0x00, 0x00};
EXPECT_THAT(actual_data_subspan, ContainerEq(reference_buffer_subspan));
iree_hal_buffer_release(buffer_subspan);
iree_hal_buffer_release(buffer);
}
TEST_F(BufferMappingTest, FillEmpty) {
iree_hal_buffer_t* buffer = NULL;
AllocateUninitializedBuffer(kDefaultAllocationSize, &buffer);
// Zero the whole buffer then "fill" 0 bytes with a different pattern.
IREE_ASSERT_OK(iree_hal_buffer_map_zero(buffer, 0, IREE_HAL_WHOLE_BUFFER));
uint8_t fill_value = 0xFF;
IREE_ASSERT_OK(
iree_hal_buffer_map_fill(buffer, /*byte_offset=*/0,
/*byte_length=*/0, // <---- empty!
/*pattern=*/&fill_value,
/*pattern_length=*/sizeof(fill_value)));
// Check that the buffer is still all zeroes.
std::vector<uint8_t> actual_data(kDefaultAllocationSize);
IREE_ASSERT_OK(iree_hal_buffer_map_read(
buffer, /*source_offset=*/0, actual_data.data(), actual_data.size()));
std::vector<uint8_t> reference_buffer(kDefaultAllocationSize);
std::memset(reference_buffer.data(), 0, kDefaultAllocationSize);
EXPECT_THAT(actual_data, ContainerEq(reference_buffer));
iree_hal_buffer_release(buffer);
}
TEST_F(BufferMappingTest, FillWholeBuffer) {
iree_hal_buffer_t* buffer = NULL;
AllocateUninitializedBuffer(kDefaultAllocationSize, &buffer);
uint8_t fill_value = 0xFF;
IREE_ASSERT_OK(
iree_hal_buffer_map_fill(buffer, /*byte_offset=*/0,
/*byte_length=*/IREE_HAL_WHOLE_BUFFER,
/*pattern=*/&fill_value,
/*pattern_length=*/sizeof(fill_value)));
// Check that the buffer is filled with the pattern.
std::vector<uint8_t> actual_data(kDefaultAllocationSize);
IREE_ASSERT_OK(iree_hal_buffer_map_read(
buffer, /*source_offset=*/0, actual_data.data(), actual_data.size()));
std::vector<uint8_t> reference_buffer(kDefaultAllocationSize);
std::memset(reference_buffer.data(), fill_value, kDefaultAllocationSize);
EXPECT_THAT(actual_data, ContainerEq(reference_buffer));
iree_hal_buffer_release(buffer);
}
TEST_F(BufferMappingTest, FillWithOffset) {
iree_device_size_t buffer_size = 16;
iree_hal_buffer_t* buffer = NULL;
AllocateUninitializedBuffer(buffer_size, &buffer);
// Zero the entire buffer then fill only a segment of it.
IREE_ASSERT_OK(iree_hal_buffer_map_zero(buffer, 0, IREE_HAL_WHOLE_BUFFER));
uint8_t fill_value = 0xFF;
IREE_ASSERT_OK(
iree_hal_buffer_map_fill(buffer, /*byte_offset=*/4,
/*byte_length=*/8,
/*pattern=*/&fill_value,
/*pattern_length=*/sizeof(fill_value)));
// Check that only the segment of the buffer is filled with the pattern.
std::vector<uint8_t> actual_data(buffer_size);
IREE_ASSERT_OK(iree_hal_buffer_map_read(
buffer, /*source_offset=*/0, actual_data.data(), actual_data.size()));
std::vector<uint8_t> reference_offset_buffer{0x00, 0x00, 0x00, 0x00, //
0xFF, 0xFF, 0xFF, 0xFF, //
0xFF, 0xFF, 0xFF, 0xFF, //
0x00, 0x00, 0x00, 0x00};
EXPECT_THAT(actual_data, ContainerEq(reference_offset_buffer));
iree_hal_buffer_release(buffer);
}
TEST_F(BufferMappingTest, FillSubspan) {
iree_device_size_t buffer_size = 16;
iree_hal_buffer_t* buffer = NULL;
AllocateUninitializedBuffer(buffer_size, &buffer);
// Zero the entire buffer.
IREE_ASSERT_OK(iree_hal_buffer_map_zero(buffer, 0, IREE_HAL_WHOLE_BUFFER));
// Create a subspan.
iree_device_size_t subspan_length = 8;
iree_hal_buffer_t* buffer_subspan = NULL;
IREE_ASSERT_OK(
iree_hal_buffer_subspan(buffer, /*byte_offset=*/4, subspan_length,
iree_allocator_system(), &buffer_subspan));
// Fill part of the subspan.
uint8_t fill_value = 0xFF;
IREE_ASSERT_OK(
iree_hal_buffer_map_fill(buffer_subspan, /*byte_offset=*/4,
/*byte_length=*/4,
/*pattern=*/&fill_value,
/*pattern_length=*/sizeof(fill_value)));
// Check that the contents match what we expect.
std::vector<uint8_t> actual_data(buffer_size);
IREE_ASSERT_OK(iree_hal_buffer_map_read(
buffer, /*source_offset=*/0, actual_data.data(), actual_data.size()));
std::vector<uint8_t> reference_buffer{0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0xFF, 0xFF, 0xFF, 0xFF, //
0x00, 0x00, 0x00, 0x00};
EXPECT_THAT(actual_data, ContainerEq(reference_buffer));
// Also check the subspan.
std::vector<uint8_t> actual_data_subspan(subspan_length);
IREE_ASSERT_OK(iree_hal_buffer_map_read(buffer_subspan, /*source_offset=*/0,
actual_data_subspan.data(),
actual_data_subspan.size()));
std::vector<uint8_t> reference_buffer_subspan{0x00, 0x00, 0x00, 0x00, //
0xFF, 0xFF, 0xFF, 0xFF};
EXPECT_THAT(actual_data_subspan, ContainerEq(reference_buffer_subspan));
iree_hal_buffer_release(buffer_subspan);
iree_hal_buffer_release(buffer);
}
TEST_F(BufferMappingTest, ReadData) {
iree_device_size_t buffer_size = 16;
iree_hal_buffer_t* buffer = NULL;
AllocateUninitializedBuffer(buffer_size, &buffer);
// Zero the first half, fill the second half.
IREE_ASSERT_OK(
iree_hal_buffer_map_zero(buffer, /*byte_offset=*/0, /*byte_length=*/8));
uint8_t fill_value = 0xFF;
IREE_ASSERT_OK(
iree_hal_buffer_map_fill(buffer, /*byte_offset=*/8,
/*byte_length=*/8,
/*pattern=*/&fill_value,
/*pattern_length=*/sizeof(fill_value)));
// Read the entire buffer.
std::vector<uint8_t> actual_data(buffer_size);
IREE_ASSERT_OK(iree_hal_buffer_map_read(
buffer, /*source_offset=*/0, actual_data.data(), actual_data.size()));
std::vector<uint8_t> reference_buffer{0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0xFF, 0xFF, 0xFF, 0xFF, //
0xFF, 0xFF, 0xFF, 0xFF};
EXPECT_THAT(actual_data, ContainerEq(reference_buffer));
// Read only a segment of the buffer.
std::vector<uint8_t> actual_data_offset(8);
IREE_ASSERT_OK(iree_hal_buffer_map_read(buffer, /*source_offset=*/4,
actual_data_offset.data(),
actual_data_offset.size()));
std::vector<uint8_t> reference_buffer_offset{0x00, 0x00, 0x00, 0x00, //
0xFF, 0xFF, 0xFF, 0xFF};
EXPECT_THAT(actual_data_offset, ContainerEq(reference_buffer_offset));
iree_hal_buffer_release(buffer);
}
TEST_F(BufferMappingTest, ReadDataSubspan) {
iree_device_size_t buffer_size = 16;
iree_hal_buffer_t* buffer = NULL;
AllocateUninitializedBuffer(buffer_size, &buffer);
// Fill a few segments with distinct values.
uint8_t value = 0xAA;
IREE_ASSERT_OK(iree_hal_buffer_map_fill(buffer, 0, 4, &value, sizeof(value)));
value = 0xBB;
IREE_ASSERT_OK(iree_hal_buffer_map_fill(buffer, 4, 4, &value, sizeof(value)));
value = 0xCC;
IREE_ASSERT_OK(iree_hal_buffer_map_fill(buffer, 8, 4, &value, sizeof(value)));
value = 0xDD;
IREE_ASSERT_OK(
iree_hal_buffer_map_fill(buffer, 12, 4, &value, sizeof(value)));
// Create a subspan.
iree_device_size_t subspan_length = 8;
iree_hal_buffer_t* buffer_subspan = NULL;
IREE_ASSERT_OK(
iree_hal_buffer_subspan(buffer, /*byte_offset=*/4, subspan_length,
iree_allocator_system(), &buffer_subspan));
// Read the entire buffer subspan.
std::vector<uint8_t> actual_data(subspan_length);
IREE_ASSERT_OK(iree_hal_buffer_map_read(buffer_subspan, /*source_offset=*/0,
actual_data.data(),
actual_data.size()));
std::vector<uint8_t> reference_buffer{0xBB, 0xBB, 0xBB, 0xBB, //
0xCC, 0xCC, 0xCC, 0xCC};
EXPECT_THAT(actual_data, ContainerEq(reference_buffer));
// Read only a segment of the buffer.
std::vector<uint8_t> actual_data_offset(4);
IREE_ASSERT_OK(iree_hal_buffer_map_read(buffer_subspan, /*source_offset=*/4,
actual_data_offset.data(),
actual_data_offset.size()));
std::vector<uint8_t> reference_buffer_offset{0xCC, 0xCC, 0xCC, 0xCC};
EXPECT_THAT(actual_data_offset, ContainerEq(reference_buffer_offset));
iree_hal_buffer_release(buffer_subspan);
iree_hal_buffer_release(buffer);
}
TEST_F(BufferMappingTest, WriteDataWholeBuffer) {
iree_device_size_t buffer_size = 16;
iree_hal_buffer_t* buffer = NULL;
AllocateUninitializedBuffer(buffer_size, &buffer);
// Write over the whole buffer.
uint8_t fill_value = 0xFF;
std::vector<uint8_t> reference_buffer(buffer_size);
std::memset(reference_buffer.data(), fill_value, buffer_size);
IREE_ASSERT_OK(iree_hal_buffer_map_write(buffer, /*target_offset=*/0,
reference_buffer.data(),
reference_buffer.size()));
// Check that entire buffer was written to.
std::vector<uint8_t> actual_data(buffer_size);
IREE_ASSERT_OK(iree_hal_buffer_map_read(
buffer, /*source_offset=*/0, actual_data.data(), actual_data.size()));
EXPECT_THAT(actual_data, ContainerEq(reference_buffer));
iree_hal_buffer_release(buffer);
}
TEST_F(BufferMappingTest, WriteDataWithOffset) {
iree_device_size_t buffer_size = 16;
iree_hal_buffer_t* buffer = NULL;
AllocateUninitializedBuffer(buffer_size, &buffer);
// Zero the entire buffer.
IREE_ASSERT_OK(iree_hal_buffer_map_zero(buffer, 0, IREE_HAL_WHOLE_BUFFER));
// Write over part of the buffer.
std::vector<uint8_t> fill_buffer{0x11, 0x22, 0x33, 0x44, //
0x55, 0x66, 0x77, 0x88};
IREE_ASSERT_OK(iree_hal_buffer_map_write(
buffer, /*target_offset=*/4, fill_buffer.data(), fill_buffer.size()));
// Check that the contents match what we expect.
std::vector<uint8_t> actual_data(buffer_size);
IREE_ASSERT_OK(iree_hal_buffer_map_read(
buffer, /*source_offset=*/0, actual_data.data(), actual_data.size()));
std::vector<uint8_t> reference_buffer{0x00, 0x00, 0x00, 0x00, //
0x11, 0x22, 0x33, 0x44, //
0x55, 0x66, 0x77, 0x88, //
0x00, 0x00, 0x00, 0x00};
EXPECT_THAT(actual_data, ContainerEq(reference_buffer));
iree_hal_buffer_release(buffer);
}
TEST_F(BufferMappingTest, WriteDataSubspan) {
iree_device_size_t buffer_size = 16;
iree_hal_buffer_t* buffer = NULL;
AllocateUninitializedBuffer(buffer_size, &buffer);
// Zero the entire buffer.
IREE_ASSERT_OK(iree_hal_buffer_map_zero(buffer, 0, IREE_HAL_WHOLE_BUFFER));
// Create a subspan.
iree_device_size_t subspan_length = 8;
iree_hal_buffer_t* buffer_subspan = NULL;
IREE_ASSERT_OK(
iree_hal_buffer_subspan(buffer, /*byte_offset=*/4, subspan_length,
iree_allocator_system(), &buffer_subspan));
// Write over part of the subspan.
std::vector<uint8_t> fill_buffer{0x11, 0x22, 0x33, 0x44};
IREE_ASSERT_OK(iree_hal_buffer_map_write(buffer_subspan, /*target_offset=*/4,
fill_buffer.data(),
fill_buffer.size()));
// Check that the contents match what we expect.
std::vector<uint8_t> actual_data(buffer_size);
IREE_ASSERT_OK(iree_hal_buffer_map_read(
buffer, /*source_offset=*/0, actual_data.data(), actual_data.size()));
std::vector<uint8_t> reference_buffer{0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x11, 0x22, 0x33, 0x44, //
0x00, 0x00, 0x00, 0x00};
EXPECT_THAT(actual_data, ContainerEq(reference_buffer));
// Also check the subspan.
std::vector<uint8_t> actual_data_subspan(subspan_length);
IREE_ASSERT_OK(iree_hal_buffer_map_read(buffer_subspan, /*source_offset=*/0,
actual_data_subspan.data(),
actual_data_subspan.size()));
std::vector<uint8_t> reference_buffer_subspan{0x00, 0x00, 0x00, 0x00, //
0x11, 0x22, 0x33, 0x44};
EXPECT_THAT(actual_data_subspan, ContainerEq(reference_buffer_subspan));
iree_hal_buffer_release(buffer_subspan);
iree_hal_buffer_release(buffer);
}
TEST_F(BufferMappingTest, CopyData) {
iree_hal_buffer_t* buffer_a = NULL;
iree_hal_buffer_t* buffer_b = NULL;
AllocateUninitializedBuffer(kDefaultAllocationSize, &buffer_a);
AllocateUninitializedBuffer(kDefaultAllocationSize, &buffer_b);
uint8_t fill_value = 0x07;
IREE_ASSERT_OK(
iree_hal_buffer_map_fill(buffer_a, /*byte_offset=*/0,
/*byte_length=*/kDefaultAllocationSize,
/*pattern=*/&fill_value,
/*pattern_length=*/sizeof(fill_value)));
IREE_ASSERT_OK(iree_hal_buffer_map_copy(
/*source_buffer=*/buffer_a,
/*source_offset=*/0, /*target_buffer=*/buffer_b, /*target_offset=*/0,
/*data_length=*/kDefaultAllocationSize));
std::vector<uint8_t> reference_buffer(kDefaultAllocationSize);
std::memset(reference_buffer.data(), fill_value, kDefaultAllocationSize);
std::vector<uint8_t> actual_data(kDefaultAllocationSize);
IREE_ASSERT_OK(iree_hal_buffer_map_read(
buffer_b, /*source_offset=*/0, actual_data.data(), actual_data.size()));
EXPECT_THAT(actual_data, ContainerEq(reference_buffer));
iree_hal_buffer_release(buffer_a);
iree_hal_buffer_release(buffer_b);
}
// Maps a buffer range for reading from device -> host.
// This is roughly what iree_hal_buffer_map_read does internally.
TEST_F(BufferMappingTest, MapRangeRead) {
iree_device_size_t buffer_size = 16;
iree_hal_buffer_t* buffer = NULL;
AllocateUninitializedBuffer(buffer_size, &buffer);
uint8_t fill_value = 0xEF;
IREE_ASSERT_OK(iree_hal_buffer_map_fill(buffer, /*byte_offset=*/0,
IREE_HAL_WHOLE_BUFFER, &fill_value,
sizeof(fill_value)));
iree_hal_buffer_mapping_t mapping;
IREE_ASSERT_OK(iree_hal_buffer_map_range(
buffer, IREE_HAL_MAPPING_MODE_SCOPED, IREE_HAL_MEMORY_ACCESS_READ,
/*byte_offset=*/0, /*byte_length=*/buffer_size, &mapping));
EXPECT_EQ(buffer, mapping.buffer);
EXPECT_GE(mapping.contents.data_length, (iree_host_size_t)buffer_size);
std::vector<uint8_t> reference_buffer(buffer_size);
std::memset(reference_buffer.data(), fill_value, buffer_size);
std::vector<uint8_t> mapping_data(
mapping.contents.data,
mapping.contents.data + mapping.contents.data_length);
EXPECT_THAT(mapping_data, ContainerEq(reference_buffer));
iree_hal_buffer_unmap_range(&mapping);
iree_hal_buffer_release(buffer);
}
// Maps a buffer range for writing from host -> device.
// This is roughly what iree_hal_buffer_map_write does internally.
TEST_F(BufferMappingTest, MapRangeWrite) {
iree_device_size_t buffer_size = 16;
iree_hal_buffer_t* buffer = NULL;
AllocateUninitializedBuffer(buffer_size, &buffer);
iree_hal_buffer_mapping_t mapping;
IREE_ASSERT_OK(iree_hal_buffer_map_range(
buffer, IREE_HAL_MAPPING_MODE_SCOPED,
IREE_HAL_MEMORY_ACCESS_DISCARD_WRITE,
/*byte_offset=*/0, /*byte_length=*/buffer_size, &mapping));
EXPECT_EQ(buffer, mapping.buffer);
EXPECT_GE(mapping.contents.data_length, (iree_host_size_t)buffer_size);
// Write into the mapped memory, flush for device access, then read back.
uint8_t fill_value = 0x12;
std::memset(mapping.contents.data, fill_value, buffer_size);
IREE_ASSERT_OK(
iree_hal_buffer_mapping_flush_range(&mapping, /*byte_offset=*/0,
/*byte_length=*/buffer_size));
std::vector<uint8_t> actual_data(buffer_size);
IREE_ASSERT_OK(iree_hal_buffer_map_read(
buffer, /*source_offset=*/0, actual_data.data(), actual_data.size()));
std::vector<uint8_t> reference_buffer(buffer_size);
std::memset(reference_buffer.data(), fill_value, buffer_size);
EXPECT_THAT(actual_data, ContainerEq(reference_buffer));
iree_hal_buffer_unmap_range(&mapping);
iree_hal_buffer_release(buffer);
}
} // namespace iree::hal::cts
#endif // IREE_HAL_CTS_BUFFER_MAPPING_TEST_H_