Skip to content

Commit

Permalink
Vulkan: sampler_ycbcr_conversion step 3, bind memory for planes
Browse files Browse the repository at this point in the history
Handle image plane memory bind (through vkBindImageMemory2).

Memory requirements and bound memory info are combined in one map
within an image object.
  • Loading branch information
Qining committed Jan 15, 2019
1 parent 13c26de commit 0c71251
Show file tree
Hide file tree
Showing 13 changed files with 185 additions and 130 deletions.
7 changes: 4 additions & 3 deletions gapii/cc/vulkan_extras.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,9 +581,10 @@ VulkanSpy::fetchPhysicalDeviceFormatProperties(
return props;
}

gapil::Ref<ImageMemoryRequirements> VulkanSpy::fetchImageMemoryRequirements(
CallObserver* observer, VkDevice device, VkImage image, bool hasSparseBit) {
auto reqs = gapil::Ref<ImageMemoryRequirements>::create(arena());
gapil::Ref<FetchedImageMemoryRequirements>
VulkanSpy::fetchImageMemoryRequirements(CallObserver* observer, VkDevice device,
VkImage image, bool hasSparseBit) {
auto reqs = gapil::Ref<FetchedImageMemoryRequirements>::create(arena());
VkMemoryRequirements rawReq{0};
mImports.mVkDeviceFunctions[device].vkGetImageMemoryRequirements(
device, image, &rawReq);
Expand Down
27 changes: 14 additions & 13 deletions gapii/cc/vulkan_mid_execution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,11 @@ void VulkanSpy::serializeGPUBuffers(StateSerializer *serializer) {
// swapchain ones), we can copy directly from all such images. Note that
// later this fact soon will be changed.

bool denseBound = img->mBoundMemory != nullptr;
// TODO: Handle multi-planar images
bool denseBound =
subGetImagePlaneMemoryInfo(nullptr, nullptr, img, 0) != nullptr &&
subGetImagePlaneMemoryInfo(nullptr, nullptr, img, 0)->mBoundMemory !=
nullptr;
bool sparseBound = (img->mOpaqueSparseMemoryBindings.count() > 0) ||
(img->mSparseImageMemoryBindings.count() > 0);
bool sparseBinding =
Expand All @@ -630,13 +634,12 @@ void VulkanSpy::serializeGPUBuffers(StateSerializer *serializer) {
bool is_valid = true;
// If this is a sparsely resident image, then at least ALL metadata
// must be bound.
for (const auto &requirements :
img->mMemoryRequirements->mAspectBitsToSparseMemoryRequirements) {
const auto &prop = requirements.second.mformatProperties;
for (const auto &req : img->mSparseMemoryRequirements) {
const auto &prop = req.second.mformatProperties;
if (prop.maspectMask ==
VkImageAspectFlagBits::VK_IMAGE_ASPECT_METADATA_BIT) {
if (!IsFullyBound(requirements.second.mimageMipTailOffset,
requirements.second.mimageMipTailSize,
if (!IsFullyBound(req.second.mimageMipTailOffset,
req.second.mimageMipTailSize,
img->mOpaqueSparseMemoryBindings)) {
is_valid = false;
break;
Expand All @@ -650,11 +653,10 @@ void VulkanSpy::serializeGPUBuffers(StateSerializer *serializer) {
// If we are not sparsely-resident, then all memory must
// be bound before we are used.
// TODO: Handle multi-planar images
if (!IsFullyBound(
0,
img->mMemoryRequirements->mPlaneBitsToMemoryRequirements[0]
.msize,
img->mOpaqueSparseMemoryBindings)) {
auto planeMemInfo =
subGetImagePlaneMemoryInfo(nullptr, nullptr, img, 0);
if (!IsFullyBound(0, planeMemInfo->mMemoryRequirements.msize,
img->mOpaqueSparseMemoryBindings)) {
continue;
}
}
Expand All @@ -679,8 +681,7 @@ void VulkanSpy::serializeGPUBuffers(StateSerializer *serializer) {
if (denseBound || !sparseResidency) {
walkImageSubRng(img, img_whole_rng, append_image_level_to_opaque_pieces);
} else {
for (const auto &req :
img->mMemoryRequirements->mAspectBitsToSparseMemoryRequirements) {
for (const auto &req : img->mSparseMemoryRequirements) {
const auto &prop = req.second.mformatProperties;
if (prop.maspectMask == img->mImageAspect) {
if (prop.mflags & VkSparseImageFormatFlagBits::
Expand Down
22 changes: 12 additions & 10 deletions gapis/api/vulkan/api/coherent_memory.api
Original file line number Diff line number Diff line change
Expand Up @@ -191,16 +191,18 @@ sub void writeMemoryInBufferViewBindings(map!(u32, VkBufferView) bufferViews) {

sub void readCoherentMemoryInImage(ref!ImageObject image) {
if image != null {
mem := image.BoundMemory
if mem != null {
// Host access to image memory is only well-defined for images created with
// VK_IMAGE_TILING_LINEAR tiling and for image subresources of those images
// which are currently in either VK_IMAGE_LAYOUT_PREINITIALIZED or
// VK_IMAGE_LAYOUT_GENERAL layout.
// TODO: Complete the layout tracking logic then update this if statement
// to check the layout of the underlying image.
if image.Info.Tiling == VK_IMAGE_TILING_LINEAR {
readCoherentMemory(mem, image.BoundMemoryOffset, inferImageSize(image))
for _, _, m in image.PlaneMemoryInfo {
mem := m.BoundMemory
if mem != null {
// Host access to image memory is only well-defined for images created with
// VK_IMAGE_TILING_LINEAR tiling and for image subresources of those images
// which are currently in either VK_IMAGE_LAYOUT_PREINITIALIZED or
// VK_IMAGE_LAYOUT_GENERAL layout.
// TODO: Complete the layout tracking logic then update this if statement
// to check the layout of the underlying image.
if image.Info.Tiling == VK_IMAGE_TILING_LINEAR {
readCoherentMemory(mem, m.BoundMemoryOffset, inferImageSize(image))
}
}
}
}
Expand Down
108 changes: 68 additions & 40 deletions gapis/api/vulkan/api/image.api
Original file line number Diff line number Diff line change
Expand Up @@ -58,27 +58,37 @@

@resource
@internal class ImageObject {
@unused VkDevice Device
ref!DeviceMemoryObject BoundMemory
VkDeviceSize BoundMemoryOffset
@unused VkDevice Device

// mapping from plane bits (0 for non-disjoint or single planar images) to memory information
map!(VkImageAspectFlagBits, ref!ImagePlaneMemoryInfo) PlaneMemoryInfo

// mapping from the resource offsets to the sparse bindings in the unit of sparse blocks
map!(u64, VkSparseMemoryBind) OpaqueSparseMemoryBindings
// mapping from image aspect flag bits to binding info
map!(u32, ref!SparseBoundImageAspectInfo) SparseImageMemoryBindings
@unused bool IsSwapchainImage
VkImage VulkanHandle
ImageInfo Info
VkImageAspectFlags ImageAspect
map!(VkImageAspectFlagBits, ref!ImageAspect) Aspects
@unused ref!VulkanDebugMarkerInfo DebugInfo
ref!ImageMemoryRequirements MemoryRequirements
map!(u32, VkSparseImageMemoryRequirements) SparseMemoryRequirements
map!(u64, VkSparseMemoryBind) OpaqueSparseMemoryBindings

// mapping from image aspect flag bits to sparse binding info
map!(VkImageAspectFlagBits, ref!SparseBoundImageAspectInfo) SparseImageMemoryBindings
@unused bool IsSwapchainImage
VkImage VulkanHandle
ImageInfo Info
VkImageAspectFlags ImageAspect
map!(VkImageAspectFlagBits, ref!ImageAspect) Aspects
@unused ref!VulkanDebugMarkerInfo DebugInfo
map!(VkImageAspectFlagBits, VkSparseImageMemoryRequirements) SparseMemoryRequirements

// Vulkan 1.1 promoted from extension: VK_KHR_dedicated_allocation
ref!DedicatedRequirements DedicatedRequirements
ref!DedicatedRequirements DedicatedRequirements

// If ever layer/level is set to the same queue, then set it here instead.
// This can save expensive looping through Aspects/Layers/Levels
@untracked @unused ref!QueueObject LastBoundQueue
map!(VkImageView, ref!ImageViewObject) Views
@untracked @unused ref!QueueObject LastBoundQueue
map!(VkImageView, ref!ImageViewObject) Views
}

@internal class ImagePlaneMemoryInfo {
ref!DeviceMemoryObject BoundMemory
VkDeviceSize BoundMemoryOffset
VkMemoryRequirements MemoryRequirements
}

@internal class ImageAspect {
Expand Down Expand Up @@ -122,9 +132,9 @@
VkSparseMemoryBindFlags Flags
}

@internal class ImageMemoryRequirements {
map!(VkImageAspectFlagBits, VkMemoryRequirements) PlaneBitsToMemoryRequirements
map!(u32, VkSparseImageMemoryRequirements) AspectBitsToSparseMemoryRequirements
@internal class FetchedImageMemoryRequirements {
map!(VkImageAspectFlagBits, VkMemoryRequirements) PlaneBitsToMemoryRequirements
map!(VkImageAspectFlagBits, VkSparseImageMemoryRequirements) AspectBitsToSparseMemoryRequirements
}

@internal class LinearImageLayouts {
Expand Down Expand Up @@ -222,12 +232,19 @@ cmd VkResult vkCreateImage(
}
}

object.MemoryRequirements = new!ImageMemoryRequirements()
fetchedRequirements := fetchImageMemoryRequirements(device, handle, hasSparseBit)
// If the vkCreateImage is inserted by GAPID (e.g. the staging image for
// reading framebuffer), NO memory requirements will be returned.
fetchedRequirements := fetchImageMemoryRequirements(device, handle, hasSparseBit)
if fetchedRequirements != null {
object.MemoryRequirements = fetchedRequirements
for _, p, _ in fetchedRequirements.PlaneBitsToMemoryRequirements {
if !(p in object.PlaneMemoryInfo) {
object.PlaneMemoryInfo[p] = new!ImagePlaneMemoryInfo()
}
object.PlaneMemoryInfo[p].MemoryRequirements = fetchedRequirements.PlaneBitsToMemoryRequirements[p]
}
for _, a, _ in fetchedRequirements.AspectBitsToSparseMemoryRequirements {
object.SparseMemoryRequirements[a] = fetchedRequirements.AspectBitsToSparseMemoryRequirements[a]
}
}

// If the image tiling is LINEAR, get the VkSubresourceLayout for each linear image level
Expand Down Expand Up @@ -268,9 +285,11 @@ cmd void vkDestroyImage(
if !(image in Images) { vkErrorInvalidImage(image) } else {
if (image != as!VkImage(0)) {
imageObject := Images[image]
if (imageObject.BoundMemory != null) {
// If the memory is deleted first, then do not try to remove ourselves.
delete(imageObject.BoundMemory.BoundObjects, as!u64(image))
for _, _, m in imageObject.PlaneMemoryInfo {
if m.BoundMemory != null {
// If the memory is deleted first, then do not try to remove ourselves.
delete(m.BoundMemory.BoundObjects, as!u64(image))
}
}
delete(Images, image)
for _ , _ , v in imageObject.Views {
Expand Down Expand Up @@ -311,8 +330,13 @@ sub void BindImageMemory(
vkErrorInvalidImage(image)
} else {
imageObject := Images[image]
imageObject.BoundMemory = DeviceMemories[memory]
imageObject.BoundMemoryOffset = memoryOffset
// Must be a single planar image, the plane bit should always be zero
plane := as!VkImageAspectFlagBits(0)
if !(plane in imageObject.PlaneMemoryInfo) {
imageObject.PlaneMemoryInfo[plane] = new!ImagePlaneMemoryInfo()
}
imageObject.PlaneMemoryInfo[plane].BoundMemory = DeviceMemories[memory]
imageObject.PlaneMemoryInfo[plane].BoundMemoryOffset = memoryOffset
DeviceMemories[memory].BoundObjects[as!u64(image)] = memoryOffset

for _ , _ , aspectBit in unpackImageAspectFlags(imageObject.ImageAspect) {
Expand Down Expand Up @@ -350,7 +374,7 @@ sub void BindImageMemory(
(as!u64(level.LinearLayout.size) > as!u64(tightlyPackedSize)) {
loffset := as!u64(memoryOffset + level.LinearLayout.offset)
lsize := as!u64(level.LinearLayout.size)
level.Data = imageObject.BoundMemory.Data[loffset:loffset + lsize]
level.Data = getImagePlaneMemoryInfo(imageObject, plane).BoundMemory.Data[loffset:loffset + lsize]
} else {
level.Data = make!u8(tightlyPackedSize)
}
Expand Down Expand Up @@ -449,15 +473,19 @@ cmd VkResult vkCreateImageView(
// Checking this here also ensures correct dependencies from
// vkCreateImageView to vkBindImageMemory.
hasSparseBit := (as!u32(imageObject.Info.Flags) & as!u32(VK_IMAGE_CREATE_SPARSE_BINDING_BIT)) != 0
if (!hasSparseBit) && (imageObject.BoundMemory == null) {
vkErrorImageMemoryNotBound(image_view_create_info.image)
}

if ((0xFFFFFFFF - as!u32(imageObject.ImageAspect)) & as!u32(image_view_create_info.subresourceRange.aspectMask)) != 0 {
vkErrorInvalidImageAspect(imageObject.VulkanHandle,
as!VkImageAspectFlagBits(image_view_create_info.subresourceRange.aspectMask))
// TODO: Handle multi-planar images
planeMemInfo := getImagePlaneMemoryInfo(imageObject, as!VkImageAspectFlagBits(0))
if planeMemInfo != null {
planeBoundMemory := planeMemInfo.BoundMemory
if (!hasSparseBit) && (planeBoundMemory != null) {
vkErrorImageMemoryNotBound(image_view_create_info.image)
}
if ((0xFFFFFFFF - as!u32(imageObject.ImageAspect)) & as!u32(image_view_create_info.subresourceRange.aspectMask)) != 0 {
vkErrorInvalidImageAspect(imageObject.VulkanHandle,
as!VkImageAspectFlagBits(image_view_create_info.subresourceRange.aspectMask))
}
imageObject.Views[handle] = imageViewObject
}
imageObject.Views[handle] = imageViewObject
}
if pView == null {
vkErrorNullPointer("VkImageView")
Expand Down Expand Up @@ -977,12 +1005,12 @@ sub dense_map!(u32, VkImageAspectFlagBits) getAspectKeysWithAspectFlags(ref!Imag
return keys.Bits
}

sub VkMemoryRequirements getImagePlaneMemoryRequirements(ref!ImageObject img, VkImageAspectFlagBits plane) {
sub ref!ImagePlaneMemoryInfo getImagePlaneMemoryInfo(ref!ImageObject img, VkImageAspectFlagBits plane) {
disjoint := isDisjointImage(img)
return switch disjoint {
case true:
img.MemoryRequirements.PlaneBitsToMemoryRequirements[plane]
img.PlaneMemoryInfo[plane]
default:
img.MemoryRequirements.PlaneBitsToMemoryRequirements[as!VkImageAspectFlagBits(0)]
img.PlaneMemoryInfo[as!VkImageAspectFlagBits(0)]
}
}
17 changes: 13 additions & 4 deletions gapis/api/vulkan/api/properties_features_requirements.api
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,12 @@ cmd void vkGetImageMemoryRequirements(
requirements := ?
if pMemoryRequirements == null { vkErrorNullPointer("VkMemoryRequirements") }
pMemoryRequirements[0] = requirements
Images[image].MemoryRequirements.PlaneBitsToMemoryRequirements[as!VkImageAspectFlagBits(0)] = requirements
// This command can be only used for single-planar images
plane := as!VkImageAspectFlagBits(0)
if !(plane in Images[image].PlaneMemoryInfo) {
Images[image].PlaneMemoryInfo[plane] = new!ImagePlaneMemoryInfo()
}
Images[image].PlaneMemoryInfo[plane].MemoryRequirements = requirements
}
}

Expand All @@ -298,7 +303,7 @@ cmd void vkGetImageSparseMemoryRequirements(
for i in (0 .. count) {
requirements[i] = ?
aspect := requirements[i].formatProperties.aspectMask
Images[image].MemoryRequirements.AspectBitsToSparseMemoryRequirements[as!u32(aspect)] = requirements[i]
Images[image].SparseMemoryRequirements[as!VkImageAspectFlagBits(aspect)] = requirements[i]
}
pSparseMemoryRequirementCount[0] = count
}
Expand Down Expand Up @@ -878,7 +883,11 @@ sub void GetImageMemoryRequirements2(
if !(info.image in Images) { vkErrorInvalidImage(info.image) }
// TODO: Drop the touch of the image object once we extract the memory
// requirement info out of the image object.
Images[info.image].MemoryRequirements.PlaneBitsToMemoryRequirements[as!VkImageAspectFlagBits(plane.Val)] = memReq.memoryRequirements
// TODO: Handle multi-planar images
if !(as!VkImageAspectFlagBits(plane.Val) in Images[info.image].PlaneMemoryInfo) {
Images[info.image].PlaneMemoryInfo[as!VkImageAspectFlagBits(plane.Val)] = new!ImagePlaneMemoryInfo()
}
Images[info.image].PlaneMemoryInfo[as!VkImageAspectFlagBits(plane.Val)].MemoryRequirements = memReq.memoryRequirements

if memReq.pNext != null {
numPNext := numberOfPNext(as!const void*(memReq.pNext))
Expand Down Expand Up @@ -944,7 +953,7 @@ sub void GetImageSparseMemoryRequirements2(
// TODO: handle pNext for 'requirements[i]'
aspect := requirements[i].memoryRequirements.formatProperties.aspectMask
// TODO: Drop the touch of the image object.
Images[image].MemoryRequirements.AspectBitsToSparseMemoryRequirements[as!u32(aspect)] = requirements[i].memoryRequirements
Images[image].SparseMemoryRequirements[as!VkImageAspectFlagBits(aspect)] = requirements[i].memoryRequirements
}
pSparseMemoryRequirementCount[0] = count
}
Expand Down
8 changes: 4 additions & 4 deletions gapis/api/vulkan/api/queue.api
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ cmd VkResult vkQueueWaitIdle(

sub void addSparseImageMemoryBinding(VkImage image, VkSparseImageMemoryBind bind) {
img := Images[image]
aspect := as!u32(bind.subresource.aspectMask)
aspect := as!VkImageAspectFlagBits(bind.subresource.aspectMask)
if !(aspect in img.SparseImageMemoryBindings) {
img.SparseImageMemoryBindings[aspect] = new!SparseBoundImageAspectInfo()
}
Expand All @@ -260,9 +260,9 @@ sub void addSparseImageMemoryBinding(VkImage image, VkSparseImageMemoryBind bind
levelInfo := layerInfo.Levels[level]

// TODO: Handle multi-planar images
blockSize := getImagePlaneMemoryRequirements(img, as!VkImageAspectFlagBits(0)).alignment
if (aspect in img.MemoryRequirements.AspectBitsToSparseMemoryRequirements) {
gran := img.MemoryRequirements.AspectBitsToSparseMemoryRequirements[aspect].formatProperties.imageGranularity
blockSize := getImagePlaneMemoryInfo(img, as!VkImageAspectFlagBits(0)).MemoryRequirements.alignment
if (aspect in img.SparseMemoryRequirements) {
gran := img.SparseMemoryRequirements[aspect].formatProperties.imageGranularity
mipWidth := getMipSize(img.Info.Extent.Width, level)
mipHeight := getMipSize(img.Info.Extent.Height, level)
widthInBlocks := roundUpTo(mipWidth, gran.Width)
Expand Down
2 changes: 1 addition & 1 deletion gapis/api/vulkan/api/queued_command_tracking.api
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ sub void execPendingCommands(VkQueue queue, bool isRoot) {
if (!img in Images) { vkErrorInvalidImage(img) }
image := Images[img]
// TODO: Handle multi-planar images
blockSize := getImagePlaneMemoryRequirements(image, as!VkImageAspectFlagBits(0)).alignment
blockSize := getImagePlaneMemoryInfo(image, as!VkImageAspectFlagBits(0)).MemoryRequirements.alignment
for _ , _ , bind in binds.SparseMemoryBinds {
numBlocks := (bind.size + blockSize - 1) / blockSize
memOffset := bind.memoryOffset
Expand Down
3 changes: 1 addition & 2 deletions gapis/api/vulkan/extensions/khr_swapchain.api
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,9 @@ cmd VkResult vkGetSwapchainImagesKHR(
for i in (0 .. count) {
images[i] = ?
if !(images[i] in Images) {
object := new!ImageObject(BoundMemory: null,
object := new!ImageObject(
Device: device,
VulkanHandle: images[i],
BoundMemoryOffset: 0,
Info: swapchainObject.Info,
ImageAspect: as!VkImageAspectFlags(VK_IMAGE_ASPECT_COLOR_BIT)
)
Expand Down
10 changes: 5 additions & 5 deletions gapis/api/vulkan/externs.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,18 +301,18 @@ func (e externs) fetchPhysicalDeviceFormatProperties(inst VkInstance, devs VkPhy
return NilPhysicalDevicesFormatPropertiesʳ
}

func (e externs) fetchImageMemoryRequirements(dev VkDevice, img VkImage, hasSparseBit bool) ImageMemoryRequirementsʳ {
func (e externs) fetchImageMemoryRequirements(dev VkDevice, img VkImage, hasSparseBit bool) FetchedImageMemoryRequirementsʳ {
// Only fetch memory requirements for application commands, skip any commands
// inserted by GAPID
if e.cmdID == api.CmdNoID {
return NilImageMemoryRequirementsʳ
return NilFetchedImageMemoryRequirementsʳ
}
for _, ee := range e.cmd.Extras().All() {
if r, ok := ee.(ImageMemoryRequirements); ok {
return MakeImageMemoryRequirementsʳ(e.s.Arena).Set(r).Clone(e.s.Arena, api.CloneContext{})
if r, ok := ee.(FetchedImageMemoryRequirements); ok {
return MakeFetchedImageMemoryRequirementsʳ(e.s.Arena).Set(r).Clone(e.s.Arena, api.CloneContext{})
}
}
return NilImageMemoryRequirementsʳ
return NilFetchedImageMemoryRequirementsʳ
}

func (e externs) fetchUsedDescriptors(ShaderModuleObjectʳ) DescriptorInfoʳ {
Expand Down
Loading

0 comments on commit 0c71251

Please sign in to comment.