Skip to content

Commit

Permalink
tests: Fix alignment for testICD
Browse files Browse the repository at this point in the history
  • Loading branch information
spencer-lunarg committed Jan 14, 2025
1 parent f4f4a7a commit 0ec8a94
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 89 deletions.
12 changes: 11 additions & 1 deletion tests/icd/test_icd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "test_icd.h"
#include "test_icd_helper.h"
#include <vulkan/utility/vk_format_utils.h>
#include <cstddef>
#include <vulkan/utility/vk_struct_helper.hpp>

namespace icd {
Expand Down Expand Up @@ -633,7 +634,16 @@ static VKAPI_ATTR VkResult VKAPI_CALL MapMemory(VkDevice device, VkDeviceMemory
else
size = 0x10000;
}
void* map_addr = malloc((size_t)size);

// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8776
// things like shaderGroupBaseAlignment can be as big as 64, since these values are dynamically set in the Profile JSON, we need
// to create the large alignment possible to satisfy them all
static const size_t memory_alignment = 64;
#if defined(_WIN32)
void* map_addr = _aligned_malloc((size_t)size, memory_alignment);
#else
void* map_addr = aligned_alloc(memory_alignment, (size_t)size);
#endif
mapped_memory_map[memory].push_back(map_addr);
*ppData = map_addr;
return VK_SUCCESS;
Expand Down
191 changes: 103 additions & 88 deletions tests/unit/memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,28 @@
class NegativeMemory : public VkLayerTest {};

TEST_F(NegativeMemory, MapMemory) {
TEST_DESCRIPTION("Attempt to map memory in a number of incorrect ways");
bool pass;
RETURN_IF_SKIP(Init());

VkBuffer buffer;
VkDeviceMemory mem;
VkMemoryRequirements mem_reqs;

const VkDeviceSize atom_size = m_device->Physical().limits_.nonCoherentAtomSize;

VkBufferCreateInfo buf_info = vku::InitStructHelper();
buf_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
buf_info.size = 256;
ASSERT_EQ(VK_SUCCESS, vk::CreateBuffer(device(), &buf_info, NULL, &buffer));
VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
buffer_ci.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
buffer_ci.size = 256;
vkt::Buffer buffer(*m_device, buffer_ci, vkt::no_mem);

VkMemoryRequirements mem_reqs;
vk::GetBufferMemoryRequirements(device(), buffer, &mem_reqs);
VkMemoryAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.memoryTypeIndex = 0;

// Ensure memory is big enough for both bindings
// Want to make sure entire allocation is aligned to atom size
const VkDeviceSize atom_size = m_device->Physical().limits_.nonCoherentAtomSize;
static const VkDeviceSize allocation_size = atom_size * 64;
alloc_info.allocationSize = allocation_size;
pass = m_device->Physical().SetMemoryType(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
bool pass = m_device->Physical().SetMemoryType(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
if (!pass) {
vk::DestroyBuffer(device(), buffer, NULL);
GTEST_SKIP() << "Failed to set memory type";
}
ASSERT_EQ(VK_SUCCESS, vk::AllocateMemory(device(), &alloc_info, NULL, &mem));
vkt::DeviceMemory mem(*m_device, alloc_info);

uint8_t *pData;
// Attempt to map memory size 0 is invalid
Expand Down Expand Up @@ -81,111 +74,133 @@ TEST_F(NegativeMemory, MapMemory) {
m_errorMonitor->SetDesiredError("VUID-vkUnmapMemory-memory-00689");
vk::UnmapMemory(device(), mem);
m_errorMonitor->VerifyFound();
}

TEST_F(NegativeMemory, MapMemoryFlush) {
RETURN_IF_SKIP(Init());

VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
buffer_ci.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
buffer_ci.size = 256;
vkt::Buffer buffer(*m_device, buffer_ci, vkt::no_mem);

VkMemoryRequirements mem_reqs;
vk::GetBufferMemoryRequirements(device(), buffer, &mem_reqs);
VkMemoryAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.memoryTypeIndex = 0;

// Ensure memory is big enough for both bindings
// Want to make sure entire allocation is aligned to atom
const VkDeviceSize atom_size = m_device->Physical().limits_.nonCoherentAtomSize;
static const VkDeviceSize allocation_size = atom_size * 64;
alloc_info.allocationSize = allocation_size;
bool pass = m_device->Physical().SetMemoryType(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
if (!pass) {
GTEST_SKIP() << "Failed to set memory type";
}
vkt::DeviceMemory mem(*m_device, alloc_info);

uint8_t *pData;
// Now map memory and cause errors due to flushing invalid ranges
ASSERT_EQ(VK_SUCCESS, vk::MapMemory(device(), mem, 4 * atom_size, VK_WHOLE_SIZE, 0, (void **)&pData));
VkMappedMemoryRange mmr = vku::InitStructHelper();
mmr.memory = mem;
mmr.offset = atom_size; // Error b/c offset less than offset of mapped mem
VkMappedMemoryRange mem_range = vku::InitStructHelper();
mem_range.memory = mem;
mem_range.offset = atom_size; // Error b/c offset less than offset of mapped mem
m_errorMonitor->SetDesiredError("VUID-VkMappedMemoryRange-size-00685");
vk::FlushMappedMemoryRanges(device(), 1, &mmr);
vk::FlushMappedMemoryRanges(device(), 1, &mem_range);
m_errorMonitor->VerifyFound();

// Now flush range that oversteps mapped range
vk::UnmapMemory(device(), mem);
ASSERT_EQ(VK_SUCCESS, vk::MapMemory(device(), mem, 0, 4 * atom_size, 0, (void **)&pData));
mmr.offset = atom_size;
mmr.size = 4 * atom_size; // Flushing bounds exceed mapped bounds
mem_range.offset = atom_size;
mem_range.size = 4 * atom_size; // Flushing bounds exceed mapped bounds
m_errorMonitor->SetDesiredError("VUID-VkMappedMemoryRange-size-00685");
vk::FlushMappedMemoryRanges(device(), 1, &mmr);
vk::FlushMappedMemoryRanges(device(), 1, &mem_range);
m_errorMonitor->VerifyFound();

// Now flush range with VK_WHOLE_SIZE that oversteps offset
vk::UnmapMemory(device(), mem);
ASSERT_EQ(VK_SUCCESS, vk::MapMemory(device(), mem, 2 * atom_size, 4 * atom_size, 0, (void **)&pData));
mmr.offset = atom_size;
mmr.size = VK_WHOLE_SIZE;
mem_range.offset = atom_size;
mem_range.size = VK_WHOLE_SIZE;
m_errorMonitor->SetDesiredError("VUID-VkMappedMemoryRange-size-00686");
vk::FlushMappedMemoryRanges(device(), 1, &mmr);
m_errorMonitor->VerifyFound();

// Some platforms have an atomsize of 1 which makes the test meaningless
if (atom_size > 3) {
// Now with an offset NOT a multiple of the device limit
vk::UnmapMemory(device(), mem);
ASSERT_EQ(VK_SUCCESS, vk::MapMemory(device(), mem, 0, 4 * atom_size, 0, (void **)&pData));
mmr.offset = 3; // Not a multiple of atom_size
mmr.size = VK_WHOLE_SIZE;
m_errorMonitor->SetDesiredError("VUID-VkMappedMemoryRange-offset-00687");
vk::FlushMappedMemoryRanges(device(), 1, &mmr);
m_errorMonitor->VerifyFound();

// Now with a size NOT a multiple of the device limit
vk::UnmapMemory(device(), mem);
ASSERT_EQ(VK_SUCCESS, vk::MapMemory(device(), mem, 0, 4 * atom_size, 0, (void **)&pData));
mmr.offset = atom_size;
mmr.size = 2 * atom_size + 1; // Not a multiple of atom_size
m_errorMonitor->SetDesiredError("VUID-VkMappedMemoryRange-size-01390");
vk::FlushMappedMemoryRanges(device(), 1, &mmr);
m_errorMonitor->VerifyFound();

// Now with VK_WHOLE_SIZE and a mapping that does not end at a multiple of atom_size nor at the end of the memory.
vk::UnmapMemory(device(), mem);
ASSERT_EQ(VK_SUCCESS, vk::MapMemory(device(), mem, 0, 4 * atom_size + 1, 0, (void **)&pData));
mmr.offset = atom_size;
mmr.size = VK_WHOLE_SIZE;
m_errorMonitor->SetDesiredError("VUID-VkMappedMemoryRange-size-01389");
vk::FlushMappedMemoryRanges(device(), 1, &mmr);
m_errorMonitor->VerifyFound();
}
vk::FlushMappedMemoryRanges(device(), 1, &mem_range);
m_errorMonitor->VerifyFound();

// Try flushing and invalidating host memory not mapped
vk::UnmapMemory(device(), mem);
mmr.offset = 0;
mmr.size = VK_WHOLE_SIZE;
mem_range.offset = 0;
mem_range.size = VK_WHOLE_SIZE;
m_errorMonitor->SetDesiredError("VUID-VkMappedMemoryRange-memory-00684");
vk::FlushMappedMemoryRanges(device(), 1, &mmr);
vk::FlushMappedMemoryRanges(device(), 1, &mem_range);
m_errorMonitor->VerifyFound();

m_errorMonitor->SetDesiredError("VUID-VkMappedMemoryRange-memory-00684");
vk::InvalidateMappedMemoryRanges(device(), 1, &mmr);
vk::InvalidateMappedMemoryRanges(device(), 1, &mem_range);
m_errorMonitor->VerifyFound();
}

vk::DestroyBuffer(device(), buffer, NULL);
vk::FreeMemory(device(), mem, NULL);

// device memory not atom size aligned
alloc_info.allocationSize = (atom_size * 4) + 1;
ASSERT_EQ(VK_SUCCESS, vk::CreateBuffer(device(), &buf_info, NULL, &buffer));
pass = m_device->Physical().SetMemoryType(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
if (!pass) {
vk::DestroyBuffer(device(), buffer, NULL);
GTEST_SKIP() << "Failed to set memory type";
TEST_F(NegativeMemory, MapMemoryCoherentAtomSize) {
RETURN_IF_SKIP(Init());
if (IsPlatformMockICD()) {
GTEST_SKIP() << "Test not supported by MockICD, MapMemory will fail ASAN";
}
ASSERT_EQ(VK_SUCCESS, vk::AllocateMemory(device(), &alloc_info, NULL, &mem));
ASSERT_EQ(VK_SUCCESS, vk::MapMemory(device(), mem, 0, VK_WHOLE_SIZE, 0, (void **)&pData));
// Some platforms have an atomsize of 1 which makes the test meaningless
if (atom_size > 1) {
// Offset is atom size, but total memory range is not atom size
mmr.memory = mem;
mmr.offset = atom_size;
mmr.size = VK_WHOLE_SIZE;
vk::FlushMappedMemoryRanges(device(), 1, &mmr);

const VkDeviceSize atom_size = m_device->Physical().limits_.nonCoherentAtomSize;
if (atom_size < 4) {
GTEST_SKIP() << "nonCoherentAtomSize is too small";
}

pass = m_device->Physical().SetMemoryType(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
vk::UnmapMemory(device(), mem);
VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
buffer_ci.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
buffer_ci.size = 256;
vkt::Buffer buffer(*m_device, buffer_ci, vkt::no_mem);

VkMemoryRequirements mem_reqs;
vk::GetBufferMemoryRequirements(device(), buffer, &mem_reqs);
VkMemoryAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.memoryTypeIndex = 0;

// Ensure memory is big enough for both bindings
// Want to make sure entire allocation is aligned to atom
static const VkDeviceSize allocation_size = atom_size * 64;
alloc_info.allocationSize = allocation_size;
bool pass = m_device->Physical().SetMemoryType(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
if (!pass) {
vk::FreeMemory(device(), mem, NULL);
vk::DestroyBuffer(device(), buffer, NULL);
GTEST_SKIP() << "Failed to set memory type";
}
// TODO : If we can get HOST_VISIBLE w/o HOST_COHERENT we can test cases of
// kVUID_Core_MemTrack_InvalidMap in validateAndCopyNoncoherentMemoryToDriver()
vkt::DeviceMemory mem(*m_device, alloc_info);

uint8_t *pData;

// Now with an offset NOT a multiple of the device limit
ASSERT_EQ(VK_SUCCESS, vk::MapMemory(device(), mem, 0, 4 * atom_size, 0, (void **)&pData));
VkMappedMemoryRange mem_range = vku::InitStructHelper();
mem_range.memory = mem;
mem_range.offset = 3; // Not a multiple of atom_size
mem_range.size = VK_WHOLE_SIZE;
m_errorMonitor->SetDesiredError("VUID-VkMappedMemoryRange-offset-00687");
vk::FlushMappedMemoryRanges(device(), 1, &mem_range);
m_errorMonitor->VerifyFound();

// Now with a size NOT a multiple of the device limit
vk::UnmapMemory(device(), mem);
ASSERT_EQ(VK_SUCCESS, vk::MapMemory(device(), mem, 0, 4 * atom_size, 0, (void **)&pData));
mem_range.offset = atom_size;
mem_range.size = 2 * atom_size + 1; // Not a multiple of atom_size
m_errorMonitor->SetDesiredError("VUID-VkMappedMemoryRange-size-01390");
vk::FlushMappedMemoryRanges(device(), 1, &mem_range);
m_errorMonitor->VerifyFound();

vk::DestroyBuffer(device(), buffer, NULL);
vk::FreeMemory(device(), mem, NULL);
// Now with VK_WHOLE_SIZE and a mapping that does not end at a multiple of atom_size nor at the end of the memory.
vk::UnmapMemory(device(), mem);
ASSERT_EQ(VK_SUCCESS, vk::MapMemory(device(), mem, 0, 4 * atom_size + 1, 0, (void **)&pData));
mem_range.offset = atom_size;
mem_range.size = VK_WHOLE_SIZE;
m_errorMonitor->SetDesiredError("VUID-VkMappedMemoryRange-size-01389");
vk::FlushMappedMemoryRanges(device(), 1, &mem_range);
m_errorMonitor->VerifyFound();
}

TEST_F(NegativeMemory, MapMemory2) {
Expand Down
40 changes: 40 additions & 0 deletions tests/unit/memory_positive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -621,3 +621,43 @@ TEST_F(PositiveMemory, BindMemoryStatusImage) {

ASSERT_NE(result, VK_RESULT_MAX_ENUM);
}

TEST_F(PositiveMemory, MapMemoryCoherentAtomSize) {
RETURN_IF_SKIP(Init());
if (IsPlatformMockICD()) {
GTEST_SKIP() << "Test not supported by MockICD, MapMemory will fail ASAN";
}

const VkDeviceSize atom_size = m_device->Physical().limits_.nonCoherentAtomSize;
if (atom_size == 1) {
// Some platforms have an atomsize of 1 which makes the test meaningless
GTEST_SKIP() << "nonCoherentAtomSize is 1";
}

VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
buffer_ci.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
buffer_ci.size = 256;
vkt::Buffer buffer(*m_device, buffer_ci, vkt::no_mem);

VkMemoryRequirements mem_reqs;
vk::GetBufferMemoryRequirements(device(), buffer, &mem_reqs);
VkMemoryAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.memoryTypeIndex = 0;

alloc_info.allocationSize = (atom_size * 4) + 1;
bool pass = m_device->Physical().SetMemoryType(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
if (!pass) {
GTEST_SKIP() << "Failed to set memory type";
}
vkt::DeviceMemory mem(*m_device, alloc_info);

uint8_t *pData;
ASSERT_EQ(VK_SUCCESS, vk::MapMemory(device(), mem, 0, VK_WHOLE_SIZE, 0, (void **)&pData));
// Offset is atom size, but total memory range is not atom size
VkMappedMemoryRange mem_range = vku::InitStructHelper();
mem_range.memory = mem;
mem_range.offset = atom_size;
mem_range.size = VK_WHOLE_SIZE;
vk::FlushMappedMemoryRanges(device(), 1, &mem_range);
vk::UnmapMemory(device(), mem);
}

0 comments on commit 0ec8a94

Please sign in to comment.