| /* | |
| * Copyright 2015 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "include/core/SkTypes.h" | |
| #include "include/gpu/GpuTypes.h" | |
| #include "include/gpu/vk/VulkanMemoryAllocator.h" | |
| #include "include/gpu/vk/VulkanTypes.h" | |
| #include "src/gpu/vk/VulkanMemory.h" | |
| #include <cstdint> | |
| #include <cstring> | |
| namespace skgpu { | |
| using BufferUsage = VulkanMemoryAllocator::BufferUsage; | |
| bool VulkanMemory::AllocBufferMemory(VulkanMemoryAllocator* allocator, | |
| VkBuffer buffer, | |
| skgpu::Protected isProtected, | |
| BufferUsage usage, | |
| bool shouldPersistentlyMapCpuToGpu, | |
| const std::function<CheckResult>& checkResult, | |
| VulkanAlloc* alloc) { | |
| VulkanBackendMemory memory = 0; | |
| uint32_t propFlags; | |
| if (usage == BufferUsage::kTransfersFromCpuToGpu || | |
| (usage == BufferUsage::kCpuWritesGpuReads && shouldPersistentlyMapCpuToGpu)) { | |
| // In general it is always fine (and often better) to keep buffers always mapped that we are | |
| // writing to on the cpu. | |
| propFlags = VulkanMemoryAllocator::kPersistentlyMapped_AllocationPropertyFlag; | |
| } else { | |
| propFlags = VulkanMemoryAllocator::kNone_AllocationPropertyFlag; | |
| } | |
| if (isProtected == Protected::kYes) { | |
| propFlags |= VulkanMemoryAllocator::kProtected_AllocationPropertyFlag; | |
| } | |
| VkResult result = allocator->allocateBufferMemory(buffer, usage, propFlags, &memory); | |
| if (!checkResult(result)) { | |
| return false; | |
| } | |
| allocator->getAllocInfo(memory, alloc); | |
| return true; | |
| } | |
| void VulkanMemory::FreeBufferMemory(VulkanMemoryAllocator* allocator, const VulkanAlloc& alloc) { | |
| SkASSERT(alloc.fBackendMemory); | |
| allocator->freeMemory(alloc.fBackendMemory); | |
| } | |
| bool VulkanMemory::AllocImageMemory(VulkanMemoryAllocator* allocator, | |
| VkImage image, | |
| Protected isProtected, | |
| bool forceDedicatedMemory, | |
| bool useLazyAllocation, | |
| const std::function<CheckResult>& checkResult, | |
| VulkanAlloc* alloc) { | |
| VulkanBackendMemory memory = 0; | |
| uint32_t propFlags; | |
| // If we ever find that our allocator is not aggressive enough in using dedicated image | |
| // memory we can add a size check here to force the use of dedicate memory. However for now, | |
| // we let the allocators decide. The allocator can query the GPU for each image to see if the | |
| // GPU recommends or requires the use of dedicated memory. | |
| if (forceDedicatedMemory) { | |
| propFlags = VulkanMemoryAllocator::kDedicatedAllocation_AllocationPropertyFlag; | |
| } else { | |
| propFlags = VulkanMemoryAllocator::kNone_AllocationPropertyFlag; | |
| } | |
| if (isProtected == Protected::kYes) { | |
| propFlags |= VulkanMemoryAllocator::kProtected_AllocationPropertyFlag; | |
| } | |
| if (useLazyAllocation) { | |
| propFlags |= VulkanMemoryAllocator::kLazyAllocation_AllocationPropertyFlag; | |
| // If we are doing a lazy allocation, we also want it to be a dedicated allocation so that | |
| // individual lazy allocations don't end up getting committed to real memory because they | |
| // are part of a larger memory block that is in real memory. So this flag will always | |
| // be set when the lazy allocation flag is set. | |
| propFlags |= VulkanMemoryAllocator::kDedicatedAllocation_AllocationPropertyFlag; | |
| } | |
| VkResult result = allocator->allocateImageMemory(image, propFlags, &memory); | |
| if (!checkResult(result)) { | |
| return false; | |
| } | |
| allocator->getAllocInfo(memory, alloc); | |
| return true; | |
| } | |
| void VulkanMemory::FreeImageMemory(VulkanMemoryAllocator* allocator, | |
| const VulkanAlloc& alloc) { | |
| SkASSERT(alloc.fBackendMemory); | |
| allocator->freeMemory(alloc.fBackendMemory); | |
| } | |
| void* VulkanMemory::MapAlloc(VulkanMemoryAllocator* allocator, | |
| const VulkanAlloc& alloc, | |
| const std::function<CheckResult>& checkResult) { | |
| SkASSERT(VulkanAlloc::kMappable_Flag & alloc.fFlags); | |
| SkASSERT(alloc.fBackendMemory); | |
| void* mapPtr; | |
| VkResult result = allocator->mapMemory(alloc.fBackendMemory, &mapPtr); | |
| if (!checkResult(result)) { | |
| return nullptr; | |
| } | |
| return mapPtr; | |
| } | |
| void VulkanMemory::UnmapAlloc(VulkanMemoryAllocator* allocator, | |
| const VulkanAlloc& alloc) { | |
| SkASSERT(alloc.fBackendMemory); | |
| allocator->unmapMemory(alloc.fBackendMemory); | |
| } | |
| void VulkanMemory::GetNonCoherentMappedMemoryRange(const VulkanAlloc& alloc, | |
| VkDeviceSize offset, | |
| VkDeviceSize size, | |
| VkDeviceSize alignment, | |
| VkMappedMemoryRange* range) { | |
| SkASSERT(alloc.fFlags & VulkanAlloc::kNoncoherent_Flag); | |
| offset = offset + alloc.fOffset; | |
| VkDeviceSize offsetDiff = offset & (alignment -1); | |
| offset = offset - offsetDiff; | |
| size = (size + alignment - 1) & ~(alignment - 1); | |
| #ifdef SK_DEBUG | |
| SkASSERT(offset >= alloc.fOffset); | |
| SkASSERT(offset + size <= alloc.fOffset + alloc.fSize); | |
| SkASSERT(0 == (offset & (alignment-1))); | |
| SkASSERT(size > 0); | |
| SkASSERT(0 == (size & (alignment-1))); | |
| #endif | |
| std::memset(range, 0, sizeof(VkMappedMemoryRange)); | |
| range->sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; | |
| range->memory = alloc.fMemory; | |
| range->offset = offset; | |
| range->size = size; | |
| } | |
| void VulkanMemory::FlushMappedAlloc(VulkanMemoryAllocator* allocator, | |
| const VulkanAlloc& alloc, | |
| VkDeviceSize offset, | |
| VkDeviceSize size, | |
| const std::function<CheckResult>& checkResult) { | |
| if (alloc.fFlags & VulkanAlloc::kNoncoherent_Flag) { | |
| SkASSERT(offset == 0); | |
| SkASSERT(size <= alloc.fSize); | |
| SkASSERT(alloc.fBackendMemory); | |
| VkResult result = allocator->flushMemory(alloc.fBackendMemory, offset, size); | |
| checkResult(result); | |
| } | |
| } | |
| void VulkanMemory::InvalidateMappedAlloc(VulkanMemoryAllocator* allocator, | |
| const VulkanAlloc& alloc, | |
| VkDeviceSize offset, | |
| VkDeviceSize size, | |
| const std::function<CheckResult>& checkResult) { | |
| if (alloc.fFlags & VulkanAlloc::kNoncoherent_Flag) { | |
| SkASSERT(offset == 0); | |
| SkASSERT(size <= alloc.fSize); | |
| SkASSERT(alloc.fBackendMemory); | |
| VkResult result = allocator->invalidateMemory(alloc.fBackendMemory, offset, size); | |
| checkResult(result); | |
| } | |
| } | |
| } // namespace skgpu |