blob: 4bddc7ac529359547b0257711d22ec599cc5934c [file] [log] [blame]
/* Copyright (c) 2015-2021 The Khronos Group Inc.
* Copyright (c) 2015-2021 Valve Corporation
* Copyright (c) 2015-2021 LunarG, Inc.
* Copyright (C) 2015-2021 Google Inc.
* Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
*
* 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
*
* http://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.
*
* Author: Courtney Goeltzenleuchter <courtneygo@google.com>
* Author: Tobin Ehlis <tobine@google.com>
* Author: Chris Forbes <chrisf@ijw.co.nz>
* Author: Mark Lobodzinski <mark@lunarg.com>
* Author: Dave Houlton <daveh@lunarg.com>
* Author: John Zulauf <jzulauf@lunarg.com>
* Author: Tobias Hector <tobias.hector@amd.com>
* Author: Jeremy Gebben <jeremyg@lunarg.com>
*/
#include "device_memory_state.h"
#include "image_state.h"
static VkExternalMemoryHandleTypeFlags GetExportHandleType(const VkMemoryAllocateInfo *p_alloc_info) {
auto export_info = LvlFindInChain<VkExportMemoryAllocateInfo>(p_alloc_info->pNext);
return export_info ? export_info->handleTypes : 0;
}
static VkExternalMemoryHandleTypeFlags GetImportHandleType(const VkMemoryAllocateInfo *p_alloc_info) {
#ifdef VK_USE_PLATFORM_WIN32_KHR
auto win32_import = LvlFindInChain<VkImportMemoryWin32HandleInfoKHR>(p_alloc_info->pNext);
if (win32_import) {
return win32_import->handleType;
}
#endif
auto fd_import = LvlFindInChain<VkImportMemoryFdInfoKHR>(p_alloc_info->pNext);
if (fd_import) {
return fd_import->handleType;
}
auto host_pointer_import = LvlFindInChain<VkImportMemoryHostPointerInfoEXT>(p_alloc_info->pNext);
if (host_pointer_import) {
return host_pointer_import->handleType;
}
#ifdef VK_USE_PLATFORM_ANDROID_KHR
// AHB Import doesn't have handle in the pNext struct
// It should be assumed that all imported AHB can only have the same, single handleType
auto ahb_import = LvlFindInChain<VkImportAndroidHardwareBufferInfoANDROID>(p_alloc_info->pNext);
if ((ahb_import) && (ahb_import->buffer != nullptr)) {
return VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
}
#endif // VK_USE_PLATFORM_ANDROID_KHR
return 0;
}
static bool IsMultiInstance(const VkMemoryAllocateInfo *p_alloc_info, const VkMemoryHeap &memory_heap, uint32_t physical_device_count) {
auto alloc_flags = LvlFindInChain<VkMemoryAllocateFlagsInfo>(p_alloc_info->pNext);
if (alloc_flags && (alloc_flags->flags & VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT)) {
auto dev_mask = alloc_flags->deviceMask;
return ((dev_mask != 0) && (dev_mask & (dev_mask - 1))) != 0;
} else if (memory_heap.flags & VK_MEMORY_HEAP_MULTI_INSTANCE_BIT) {
return physical_device_count > 1;
}
return false;
}
DEVICE_MEMORY_STATE::DEVICE_MEMORY_STATE(VkDeviceMemory mem, const VkMemoryAllocateInfo *p_alloc_info,
uint64_t fake_address,
const VkMemoryType &memory_type, const VkMemoryHeap &memory_heap,
layer_data::optional<DedicatedBinding> &&dedicated_binding,
uint32_t physical_device_count)
: BASE_NODE(mem, kVulkanObjectTypeDeviceMemory),
alloc_info(p_alloc_info),
export_handle_type_flags(GetExportHandleType(p_alloc_info)),
import_handle_type_flags(GetImportHandleType(p_alloc_info)),
unprotected((memory_type.propertyFlags & VK_MEMORY_PROPERTY_PROTECTED_BIT) == 0),
multi_instance(IsMultiInstance(p_alloc_info, memory_heap, physical_device_count)),
dedicated(std::move(dedicated_binding)),
mapped_range{},
p_driver_data(nullptr),
fake_base_address(fake_address) {}
void BINDABLE::Destroy() {
for (auto &item: bound_memory_) {
if (item.second.mem_state) {
item.second.mem_state->RemoveParent(this);
}
}
bound_memory_.clear();
BASE_NODE::Destroy();
}
// SetMemBinding is used to establish immutable, non-sparse binding between a single image/buffer object and memory object.
// Corresponding valid usage checks are in ValidateSetMemBinding().
void BINDABLE::SetMemBinding(std::shared_ptr<DEVICE_MEMORY_STATE> &mem, VkDeviceSize memory_offset) {
if (!mem) {
return;
}
assert(!sparse);
if (bound_memory_.size() > 0) {
bound_memory_.clear();
}
MEM_BINDING binding = {
mem,
memory_offset,
};
binding.mem_state->AddParent(this);
bound_memory_.insert({mem->mem(), binding});
}
// For NULL mem case, clear any previous binding Else...
// Make sure given object is in its object map
// IF a previous binding existed, update binding
// Add reference from objectInfo to memoryInfo
// Add reference off of object's binding info
// Return VK_TRUE if addition is successful, VK_FALSE otherwise
void BINDABLE::SetSparseMemBinding(std::shared_ptr<DEVICE_MEMORY_STATE> &mem, const VkDeviceSize mem_offset,
const VkDeviceSize mem_size) {
if (!mem) {
return;
}
assert(sparse);
MEM_BINDING sparse_binding = {mem, mem_offset, mem_size};
sparse_binding.mem_state->AddParent(this);
// Need to set mem binding for this object
bound_memory_.insert({mem->mem(), sparse_binding});
}
VkDeviceSize BINDABLE::GetFakeBaseAddress() const {
assert(!sparse); // not implemented yet
const auto *binding = Binding();
return binding ? binding->offset + binding->mem_state->fake_base_address : 0;
}