blob: c8e7ce4702e10cc2fbee138146a3296af14db7c1 [file] [log] [blame]
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstring>
#include <vector>
#include "iree/hal/cts/cts_test_base.h"
#include "iree/hal/testing/driver_registry.h"
#include "iree/testing/gtest.h"
#include "iree/testing/status_matchers.h"
// TODO(scotttodd): split into several tests, for example:
// command_buffer_recording_test (recording/lifetime)
// command_buffer_dispatch_test
// command_buffer_fill_test (filling buffers)
// command_buffer_e2e_test (barriers, dispatches)
namespace iree {
namespace hal {
namespace cts {
using ::testing::ContainerEq;
class CommandBufferTest : public CtsTestBase {
public:
CommandBufferTest() {
// TODO(#4680): command buffer recording so that this can run on sync HAL.
SkipUnavailableDriver("dylib-sync");
}
protected:
static constexpr iree_device_size_t kBufferSize = 4096;
};
TEST_P(CommandBufferTest, Create) {
iree_hal_command_buffer_t* command_buffer;
IREE_ASSERT_OK(iree_hal_command_buffer_create(
device_, IREE_HAL_COMMAND_BUFFER_MODE_ONE_SHOT,
IREE_HAL_COMMAND_CATEGORY_DISPATCH, IREE_HAL_QUEUE_AFFINITY_ANY,
&command_buffer));
EXPECT_TRUE((iree_hal_command_buffer_allowed_categories(command_buffer) &
IREE_HAL_COMMAND_CATEGORY_DISPATCH) ==
IREE_HAL_COMMAND_CATEGORY_DISPATCH);
iree_hal_command_buffer_release(command_buffer);
}
TEST_P(CommandBufferTest, BeginEnd) {
iree_hal_command_buffer_t* command_buffer;
IREE_ASSERT_OK(iree_hal_command_buffer_create(
device_, IREE_HAL_COMMAND_BUFFER_MODE_ONE_SHOT,
IREE_HAL_COMMAND_CATEGORY_DISPATCH, IREE_HAL_QUEUE_AFFINITY_ANY,
&command_buffer));
IREE_ASSERT_OK(iree_hal_command_buffer_begin(command_buffer));
IREE_ASSERT_OK(iree_hal_command_buffer_end(command_buffer));
iree_hal_command_buffer_release(command_buffer);
}
TEST_P(CommandBufferTest, SubmitEmpty) {
iree_hal_command_buffer_t* command_buffer;
IREE_ASSERT_OK(iree_hal_command_buffer_create(
device_, IREE_HAL_COMMAND_BUFFER_MODE_ONE_SHOT,
IREE_HAL_COMMAND_CATEGORY_DISPATCH, IREE_HAL_QUEUE_AFFINITY_ANY,
&command_buffer));
IREE_ASSERT_OK(iree_hal_command_buffer_begin(command_buffer));
IREE_ASSERT_OK(iree_hal_command_buffer_end(command_buffer));
IREE_ASSERT_OK(SubmitCommandBufferAndWait(IREE_HAL_COMMAND_CATEGORY_DISPATCH,
command_buffer));
iree_hal_command_buffer_release(command_buffer);
}
TEST_P(CommandBufferTest, FillBufferWithRepeatedBytes) {
iree_hal_command_buffer_t* command_buffer;
IREE_ASSERT_OK(iree_hal_command_buffer_create(
device_, IREE_HAL_COMMAND_BUFFER_MODE_ONE_SHOT,
IREE_HAL_COMMAND_CATEGORY_TRANSFER, IREE_HAL_QUEUE_AFFINITY_ANY,
&command_buffer));
iree_hal_buffer_t* device_buffer;
IREE_ASSERT_OK(iree_hal_allocator_allocate_buffer(
device_allocator_,
IREE_HAL_MEMORY_TYPE_DEVICE_LOCAL | IREE_HAL_MEMORY_TYPE_HOST_VISIBLE,
IREE_HAL_BUFFER_USAGE_ALL, kBufferSize, &device_buffer));
std::vector<uint8_t> reference_buffer(kBufferSize);
IREE_ASSERT_OK(iree_hal_command_buffer_begin(command_buffer));
// Fill the device buffer with segments of different values so that we can
// test both fill and offset/size.
uint8_t val1 = 0x07;
IREE_ASSERT_OK(iree_hal_command_buffer_fill_buffer(
command_buffer, device_buffer,
/*target_offset=*/0, /*length=*/kBufferSize / 4, /*pattern=*/&val1,
/*pattern_length=*/sizeof(val1)));
std::memset(reference_buffer.data(), val1, kBufferSize / 4);
uint8_t val2 = 0xbe;
IREE_ASSERT_OK(
iree_hal_command_buffer_fill_buffer(command_buffer, device_buffer,
/*target_offset=*/kBufferSize / 4,
/*length=*/kBufferSize / 4,
/*pattern=*/&val2,
/*pattern_length=*/sizeof(val2)));
std::memset(reference_buffer.data() + kBufferSize / 4, val2, kBufferSize / 4);
uint8_t val3 = 0x54;
IREE_ASSERT_OK(
iree_hal_command_buffer_fill_buffer(command_buffer, device_buffer,
/*target_offset=*/kBufferSize / 2,
/*length=*/kBufferSize / 2,
/*pattern=*/&val3,
/*pattern_length=*/sizeof(val3)));
std::memset(reference_buffer.data() + kBufferSize / 2, val3, kBufferSize / 2);
IREE_ASSERT_OK(iree_hal_command_buffer_end(command_buffer));
IREE_ASSERT_OK(SubmitCommandBufferAndWait(IREE_HAL_COMMAND_CATEGORY_TRANSFER,
command_buffer));
// Read the device buffer and compare.
std::vector<uint8_t> actual_data(kBufferSize);
IREE_ASSERT_OK(iree_hal_buffer_read_data(device_buffer, /*source_offset=*/0,
/*target_buffer=*/actual_data.data(),
/*data_length=*/kBufferSize));
EXPECT_THAT(actual_data, ContainerEq(reference_buffer));
// Must release the command buffer before resources used by it.
iree_hal_command_buffer_release(command_buffer);
iree_hal_buffer_release(device_buffer);
}
TEST_P(CommandBufferTest, CopyWholeBuffer) {
iree_hal_command_buffer_t* command_buffer;
IREE_ASSERT_OK(iree_hal_command_buffer_create(
device_, IREE_HAL_COMMAND_BUFFER_MODE_ONE_SHOT,
IREE_HAL_COMMAND_CATEGORY_TRANSFER, IREE_HAL_QUEUE_AFFINITY_ANY,
&command_buffer));
// Create and fill a host buffer.
iree_hal_buffer_t* host_buffer;
IREE_ASSERT_OK(iree_hal_allocator_allocate_buffer(
device_allocator_,
IREE_HAL_MEMORY_TYPE_HOST_VISIBLE | IREE_HAL_MEMORY_TYPE_HOST_CACHED |
IREE_HAL_MEMORY_TYPE_DEVICE_VISIBLE,
IREE_HAL_BUFFER_USAGE_ALL, kBufferSize, &host_buffer));
uint8_t i8_val = 0x54;
IREE_ASSERT_OK(iree_hal_buffer_fill(host_buffer, /*byte_offset=*/0,
/*byte_length=*/kBufferSize, &i8_val,
/*pattern_length=*/sizeof(i8_val)));
std::vector<uint8_t> reference_buffer(kBufferSize);
std::memset(reference_buffer.data(), i8_val, kBufferSize);
// Create a device buffer.
iree_hal_buffer_t* device_buffer;
IREE_ASSERT_OK(iree_hal_allocator_allocate_buffer(
device_allocator_,
IREE_HAL_MEMORY_TYPE_DEVICE_LOCAL | IREE_HAL_MEMORY_TYPE_HOST_VISIBLE,
IREE_HAL_BUFFER_USAGE_ALL, kBufferSize, &device_buffer));
// Copy the host buffer to the device buffer.
IREE_ASSERT_OK(iree_hal_command_buffer_begin(command_buffer));
IREE_ASSERT_OK(iree_hal_command_buffer_copy_buffer(
command_buffer, /*source_buffer=*/host_buffer, /*source_offset=*/0,
/*target_buffer=*/device_buffer, /*target_offset=*/0,
/*length=*/kBufferSize));
IREE_ASSERT_OK(iree_hal_command_buffer_end(command_buffer));
IREE_ASSERT_OK(SubmitCommandBufferAndWait(IREE_HAL_COMMAND_CATEGORY_TRANSFER,
command_buffer));
// Read the device buffer and compare.
std::vector<uint8_t> actual_data(kBufferSize);
IREE_ASSERT_OK(iree_hal_buffer_read_data(device_buffer, /*source_offset=*/0,
/*target_buffer=*/actual_data.data(),
/*data_length=*/kBufferSize));
EXPECT_THAT(actual_data, ContainerEq(reference_buffer));
// Must release the command buffer before resources used by it.
iree_hal_command_buffer_release(command_buffer);
iree_hal_buffer_release(device_buffer);
iree_hal_buffer_release(host_buffer);
}
TEST_P(CommandBufferTest, CopySubBuffer) {
iree_hal_command_buffer_t* command_buffer;
IREE_ASSERT_OK(iree_hal_command_buffer_create(
device_, IREE_HAL_COMMAND_BUFFER_MODE_ONE_SHOT,
IREE_HAL_COMMAND_CATEGORY_TRANSFER, IREE_HAL_QUEUE_AFFINITY_ANY,
&command_buffer));
iree_hal_buffer_t* device_buffer;
IREE_ASSERT_OK(iree_hal_allocator_allocate_buffer(
device_allocator_,
IREE_HAL_MEMORY_TYPE_DEVICE_LOCAL | IREE_HAL_MEMORY_TYPE_HOST_VISIBLE,
IREE_HAL_BUFFER_USAGE_ALL, kBufferSize, &device_buffer));
// Create another host buffer with a smaller size.
iree_hal_buffer_t* host_buffer;
IREE_ASSERT_OK(iree_hal_allocator_allocate_buffer(
device_allocator_,
IREE_HAL_MEMORY_TYPE_HOST_VISIBLE | IREE_HAL_MEMORY_TYPE_HOST_CACHED |
IREE_HAL_MEMORY_TYPE_DEVICE_VISIBLE,
IREE_HAL_BUFFER_USAGE_ALL, kBufferSize / 2, &host_buffer));
// Fill the host buffer.
uint8_t i8_val = 0x88;
IREE_ASSERT_OK(iree_hal_buffer_fill(host_buffer, /*byte_offset=*/0,
/*byte_length=*/kBufferSize / 2, &i8_val,
/*pattern_length=*/sizeof(i8_val)));
std::vector<uint8_t> reference_buffer(kBufferSize);
std::memset(reference_buffer.data() + 8, i8_val, kBufferSize / 2 - 4);
// Copy the host buffer to the device buffer.
IREE_ASSERT_OK(iree_hal_command_buffer_begin(command_buffer));
IREE_ASSERT_OK(iree_hal_command_buffer_copy_buffer(
command_buffer, /*source_buffer=*/host_buffer, /*source_offset=*/4,
/*target_buffer=*/device_buffer, /*target_offset=*/8,
/*length=*/kBufferSize / 2 - 4));
IREE_ASSERT_OK(iree_hal_command_buffer_end(command_buffer));
IREE_ASSERT_OK(SubmitCommandBufferAndWait(IREE_HAL_COMMAND_CATEGORY_TRANSFER,
command_buffer));
// Read the device buffer and compare.
std::vector<uint8_t> actual_data(kBufferSize);
IREE_ASSERT_OK(iree_hal_buffer_read_data(device_buffer, /*source_offset=*/0,
/*target_buffer=*/actual_data.data(),
/*data_length=*/kBufferSize));
EXPECT_THAT(actual_data, ContainerEq(reference_buffer));
// Must release the command buffer before resources used by it.
iree_hal_command_buffer_release(command_buffer);
iree_hal_buffer_release(device_buffer);
iree_hal_buffer_release(host_buffer);
}
INSTANTIATE_TEST_SUITE_P(
AllDrivers, CommandBufferTest,
::testing::ValuesIn(testing::EnumerateAvailableDrivers()),
GenerateTestName());
} // namespace cts
} // namespace hal
} // namespace iree