Skip to content

Commit

Permalink
Fix for linear image with preinitialized intial layout (#1960)
Browse files Browse the repository at this point in the history
1) If an image has linear tiling and has initial layout set to
PREINITIALIZED, all its subresources data pool will be linked back to
the bound device memory, no new pool will be created for those
subresources.

2) If an image has linear tiling and has initial layout set to
PREINITIALIZED, and it can not be used as TRANSFER_DST, render target or
imageStore target, its data will be primed by maping memory and flush
map memory ranges.
  • Loading branch information
Qining authored Jun 6, 2018
1 parent b681282 commit b468b98
Show file tree
Hide file tree
Showing 6 changed files with 250 additions and 78 deletions.
33 changes: 33 additions & 0 deletions gapii/cc/vulkan_extras.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,39 @@ VkMemoryRequirements VulkanSpy::fetchBufferMemoryRequirements(
return reqs;
}

gapil::Ref<LinearImageLayouts> VulkanSpy::fetchLinearImageSubresourceLayouts(
CallObserver* observer, VkDevice device, gapil::Ref<ImageObject> image,
VkImageSubresourceRange rng) {
auto layouts = gapil::Ref<LinearImageLayouts>::create(arena());
walkImageSubRng(
image, rng,
[&layouts, device, &image, this](uint32_t aspect_bit, uint32_t layer, uint32_t level) {
VkImageSubresource subres(VkImageAspectFlags(aspect_bit), // aspectMask
level, // mipLevel
layer // arrayLayer
);
auto aspect_i = layouts->mAspectLayouts.find(aspect_bit);
if (aspect_i == layouts->mAspectLayouts.end()) {
layouts->mAspectLayouts[aspect_bit] =
gapil::Ref<LinearImageAspectLayouts>::create(arena());
aspect_i = layouts->mAspectLayouts.find(aspect_bit);
}
auto layer_i = aspect_i->second->mLayerLayouts.find(layer);
if (layer_i == aspect_i->second->mLayerLayouts.end()) {
aspect_i->second->mLayerLayouts[layer] =
gapil::Ref<LinearImageLayerLayouts>::create(arena());
layer_i = aspect_i->second->mLayerLayouts.find(layer);
}
layer_i->second->mLevelLayouts[level] =
gapil::Ref<VkSubresourceLayout>::create(arena());
mImports.mVkDeviceFunctions[device].vkGetImageSubresourceLayout(
device, image->mVulkanHandle, &subres,
&*layer_i->second->mLevelLayouts[level]);
});
observer->encode(*layouts.get());
return layouts;
}

// Override API functions
// SpyOverride_vkGetInstanceProcAddr(), SpyOverride_vkGetDeviceProcAddr(),
// SpyOverride_vkCreateInstance() and SpyOverride_vkCreateDevice() require
Expand Down
81 changes: 66 additions & 15 deletions gapis/api/vulkan/api/image.api
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
VkDeviceSize BoundMemoryOffset
// mapping from the resource offsets to the sparse bindings in the unit of sparse blocks
map!(u64, VkSparseMemoryBind) OpaqueSparseMemoryBindings
// mapping from image aspect flags to binding info
// mapping from image aspect flag bits to binding info
map!(u32, ref!SparseBoundImageAspectInfo) SparseImageMemoryBindings
@unused bool IsSwapchainImage
VkImage VulkanHandle
Expand Down Expand Up @@ -92,6 +92,7 @@
@spy_disabled
@hidden @nobox @internal u8[] Data
VkImageLayout Layout
ref!VkSubresourceLayout LinearLayout
}

@internal class SparseBoundImageAspectInfo {
Expand All @@ -116,10 +117,22 @@
}

@internal class ImageMemoryRequirements {
VkMemoryRequirements MemoryRequirements
VkMemoryRequirements MemoryRequirements
map!(u32, VkSparseImageMemoryRequirements) AspectBitsToSparseMemoryRequirements
}

@internal class LinearImageLayouts {
map!(u32, ref!LinearImageAspectLayouts) AspectLayouts
}

@internal class LinearImageAspectLayouts {
map!(u32, ref!LinearImageLayerLayouts) LayerLayouts
}

@internal class LinearImageLayerLayouts {
map!(u32, ref!VkSubresourceLayout) LevelLayouts
}

@threadSafety("system")
@indirect("VkDevice")
@override
Expand All @@ -134,17 +147,17 @@ cmd VkResult vkCreateImage(
queueFamilyIndices := info.pQueueFamilyIndices[0:info.queueFamilyIndexCount]

imageInfo := ImageInfo(
Flags: info.flags,
ImageType: info.imageType,
Format: info.format,
Extent: info.extent,
MipLevels: info.mipLevels,
ArrayLayers: info.arrayLayers,
Samples: info.samples,
Tiling: info.tiling,
Usage: info.usage,
SharingMode: info.sharingMode,
InitialLayout: info.initialLayout,
Flags: info.flags,
ImageType: info.imageType,
Format: info.format,
Extent: info.extent,
MipLevels: info.mipLevels,
ArrayLayers: info.arrayLayers,
Samples: info.samples,
Tiling: info.tiling,
Usage: info.usage,
SharingMode: info.sharingMode,
InitialLayout: info.initialLayout,
)

for i in (0 .. info.queueFamilyIndexCount) {
Expand Down Expand Up @@ -228,6 +241,29 @@ cmd VkResult vkCreateImage(
}
}

// If the image tiling is LINEAR, get the VkSubresourceLayout for each linear image level
if (info.tiling == VK_IMAGE_TILING_LINEAR) {
linearLayouts := fetchLinearImageSubresourceLayouts(device, object,
VkImageSubresourceRange(
aspectMask: imageAspect,
baseMipLevel: 0,
levelCount: imageInfo.MipLevels,
baseArrayLayer: 0,
layerCount: imageInfo.ArrayLayers,
))
if (linearLayouts != null) {
for _ , aspectBit , al in linearLayouts.AspectLayouts {
for _ , layer , layl in al.LayerLayouts {
for _ , level , levl in layl.LevelLayouts {
if levl != null {
object.Aspects[as!VkImageAspectFlagBits(aspectBit)].Layers[layer].Levels[level].LinearLayout = levl
}
}
}
}
}
}

Images[handle] = object

return ?
Expand Down Expand Up @@ -310,9 +346,24 @@ cmd VkResult vkBindImageMemory(
// stencil element is always 1 byte wide
as!u32(1)
}
// Align to the next multiple times of 8
size := widthInBlocks * heightInBlocks * level.Depth * elementSize
level.Data = make!u8(size)

// If the image has LINEAR tiling and the image level has layout
// PREINITIALIZED, link the data back to the bound device memory.
// Otherwise creates its own shadow memory pool.
// TODO: If the image as a whole requires more memory than we
// calculated, we should link the data back to the bound device memory
// no matter whether the tiling is LINEAR or OPTIMAL. But we need to
// come up with a 'linear layout' used in GAPID.
if (imageObject.Info.Tiling == VK_IMAGE_TILING_LINEAR) &&
(level.Layout == VK_IMAGE_LAYOUT_PREINITIALIZED) &&
(level.LinearLayout != null) {
loffset := as!u64(memoryOffset + level.LinearLayout.offset)
lsize := as!u64(level.LinearLayout.size)
level.Data = imageObject.BoundMemory.Data[loffset:lsize]
} else {
level.Data = make!u8(size)
}
}
}
}
Expand Down
14 changes: 14 additions & 0 deletions gapis/api/vulkan/externs.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,20 @@ func (e externs) fetchBufferMemoryRequirements(dev VkDevice, buf VkBuffer) VkMem
return MakeVkMemoryRequirements(e.s.Arena)
}

func (e externs) fetchLinearImageSubresourceLayouts(dev VkDevice, img ImageObjectʳ, rng VkImageSubresourceRange) LinearImageLayoutsʳ {
// Only fetch linear image layouts for application commands, skip any commands
// inserted by GAPID
if e.cmdID == api.CmdNoID {
return NilLinearImageLayoutsʳ
}
for _, ee := range e.cmd.Extras().All() {
if r, ok := ee.(LinearImageLayouts); ok {
return MakeLinearImageLayoutsʳ(e.s.Arena).Set(r).Clone(e.s.Arena)
}
}
return NilLinearImageLayoutsʳ
}

func (e externs) vkErrInvalidHandle(handleType string, handle uint64) {
var issue replay.Issue
issue.Command = e.cmdID
Expand Down
Loading

0 comments on commit b468b98

Please sign in to comment.