diff --git a/gapis/api/vulkan/BUILD.bazel b/gapis/api/vulkan/BUILD.bazel index a85a237191..c308ea5696 100644 --- a/gapis/api/vulkan/BUILD.bazel +++ b/gapis/api/vulkan/BUILD.bazel @@ -100,6 +100,7 @@ go_library( "//gapis/api/vulkan/vulkan_pb:go_default_library", # keep "//gapis/capture:go_default_library", "//gapis/config:go_default_library", + "//gapis/database:go_default_library", "//gapis/memory:go_default_library", "//gapis/memory/memory_pb:go_default_library", # keep "//gapis/messages:go_default_library", diff --git a/gapis/api/vulkan/image_primer.go b/gapis/api/vulkan/image_primer.go index 49d9a0a358..45f058e8d8 100644 --- a/gapis/api/vulkan/image_primer.go +++ b/gapis/api/vulkan/image_primer.go @@ -196,18 +196,31 @@ func (p *imagePrimer) primeByPreinitialization(img ImageObjectʳ, opaqueBoundRan newMem := newImg.BoundMemory() boundOffset := img.BoundMemoryOffset() boundSize := img.MemoryRequirements().Size() - newData := make([]uint8, boundSize) - transitionInfo := []imgSubRngLayoutTransitionInfo{} + dat := p.sb.MustReserve(uint64(boundSize)) + at := NewVoidᵖ(dat.Ptr()) + atdata := p.sb.newState.AllocDataOrPanic(p.sb.ctx, at) + p.sb.write(p.sb.cb.VkMapMemory( + newMem.Device(), + newMem.VulkanHandle(), + boundOffset, + boundSize, + VkMemoryMapFlags(0), + atdata.Ptr(), + VkResult_VK_SUCCESS, + ).AddRead(atdata.Data()).AddWrite(atdata.Data())) + atdata.Free() + + transitionInfo := []imgSubRngLayoutTransitionInfo{} for _, rng := range opaqueBoundRanges { walkImageSubresourceRange(p.sb, img, rng, func(aspect VkImageAspectFlagBits, layer, level uint32, unused byteSizeAndExtent) { origLevel := img.Aspects().Get(aspect).Layers().Get(layer).Levels().Get(level) - origData := origLevel.Data().MustRead(p.sb.ctx, nil, p.sb.oldState, nil) + origDataSlice := origLevel.Data() linearLayout := origLevel.LinearLayout() - start := uint64(linearLayout.Offset()) - end := start + uint64(linearLayout.Size()) - copy(newData[start:end], origData[:]) + + p.sb.ReadDataAt(origDataSlice.ResourceID(p.sb.ctx, p.sb.oldState), uint64(linearLayout.Offset())+dat.Address(), origDataSlice.Size()) + transitionInfo = append(transitionInfo, imgSubRngLayoutTransitionInfo{ aspectMask: VkImageAspectFlags(aspect), baseMipLevel: level, @@ -220,21 +233,6 @@ func (p *imagePrimer) primeByPreinitialization(img ImageObjectʳ, opaqueBoundRan }) } - dat := p.sb.newState.AllocDataOrPanic(p.sb.ctx, newData) - defer dat.Free() - at := NewVoidᵖ(dat.Ptr()) - atdata := p.sb.newState.AllocDataOrPanic(p.sb.ctx, at) - defer atdata.Free() - p.sb.write(p.sb.cb.VkMapMemory( - newMem.Device(), - newMem.VulkanHandle(), - boundOffset, - boundSize, - VkMemoryMapFlags(0), - atdata.Ptr(), - VkResult_VK_SUCCESS, - ).AddRead(atdata.Data()).AddWrite(atdata.Data())) - p.sb.write(p.sb.cb.VkFlushMappedMemoryRanges( newMem.Device(), 1, @@ -246,7 +244,8 @@ func (p *imagePrimer) primeByPreinitialization(img ImageObjectʳ, opaqueBoundRan boundSize, // size )).Ptr(), VkResult_VK_SUCCESS, - ).AddRead(dat.Data())) + )) + dat.Free() p.sb.write(p.sb.cb.VkUnmapMemory( newMem.Device(), @@ -654,7 +653,7 @@ func (h *ipStoreHandler) dispatchAndSubmit(info ipStoreDispatchInfo, queue Queue // data buffer and buffer view dataBuf, dataMem := h.sb.allocAndFillScratchBuffer( - h.sb.s.Devices().Get(info.dev), info.data, + h.sb.s.Devices().Get(info.dev), []bufferSubRangeFillInfo{newBufferSubRangeFillInfoFromNewData(info.data, 0)}, VkBufferUsageFlagBits_VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) defer h.sb.freeScratchBuffer(h.sb.s.Devices().Get(info.dev), dataBuf, dataMem) dataBufView := VkBufferView(newUnusedID(true, func(x uint64) bool { @@ -755,7 +754,7 @@ func (h *ipStoreHandler) dispatchAndSubmit(info ipStoreDispatchInfo, queue Queue var db bytes.Buffer binary.Write(&db, binary.LittleEndian, metadata) metadataBuf, metadataMem := h.sb.allocAndFillScratchBuffer( - h.sb.s.Devices().Get(info.dev), db.Bytes(), + h.sb.s.Devices().Get(info.dev), []bufferSubRangeFillInfo{newBufferSubRangeFillInfoFromNewData(db.Bytes(), 0)}, VkBufferUsageFlagBits_VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) defer h.sb.freeScratchBuffer(h.sb.s.Devices().Get(info.dev), metadataBuf, metadataMem) @@ -956,6 +955,10 @@ type ipRenderHandler struct { pipelines map[ipGfxPipelineInfo]GraphicsPipelineObjectʳ // shader modules indexed by the shader info. shaders map[ipRenderShaderInfo]ShaderModuleObjectʳ + // the fill info for the scratch buffers for vertex buffer and index buffer, + // the raw content of the those two buffers are supposed to be contants. + vertexBufferFillInfo *bufferSubRangeFillInfo + indexBufferFillInfo *bufferSubRangeFillInfo } // Interfaces of render handler to interact with image primer @@ -1089,7 +1092,7 @@ func (h *ipRenderHandler) render(job *ipRenderJob, queue QueueObjectʳ) error { stencilBitIndices := []uint32{0} var sbic bytes.Buffer binary.Write(&sbic, binary.LittleEndian, stencilBitIndices) - stencilIndexBuf, stencilIndexMem = h.sb.allocAndFillScratchBuffer(h.sb.s.Devices().Get(dev), sbic.Bytes(), VkBufferUsageFlagBits_VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT|VkBufferUsageFlagBits_VK_BUFFER_USAGE_TRANSFER_DST_BIT) + stencilIndexBuf, stencilIndexMem = h.sb.allocAndFillScratchBuffer(h.sb.s.Devices().Get(dev), []bufferSubRangeFillInfo{newBufferSubRangeFillInfoFromNewData(sbic.Bytes(), 0)}, VkBufferUsageFlagBits_VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT|VkBufferUsageFlagBits_VK_BUFFER_USAGE_TRANSFER_DST_BIT) defer h.sb.freeScratchBuffer(h.sb.s.Devices().Get(dev), stencilIndexBuf, stencilIndexMem) bufInfoList := []VkDescriptorBufferInfo{ @@ -1155,19 +1158,29 @@ func (h *ipRenderHandler) render(job *ipRenderJob, queue QueueObjectʳ) error { return log.Errf(h.sb.ctx, err, "[Getting graphics pipeline]") } - var vc bytes.Buffer - binary.Write(&vc, binary.LittleEndian, []float32{ - // positions, offset: 0 bytes - 1.0, 1.0, 0.0, -1.0, -1.0, 0.0, -1.0, 1.0, 0.0, 1.0, -1.0, 0.0, - }) - vertexBuf, vertexBufMem := h.sb.allocAndFillScratchBuffer(h.sb.s.Devices().Get(dev), vc.Bytes(), VkBufferUsageFlagBits_VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) + if h.vertexBufferFillInfo == nil { + var vc bytes.Buffer + binary.Write(&vc, binary.LittleEndian, []float32{ + // positions, offset: 0 bytes + 1.0, 1.0, 0.0, -1.0, -1.0, 0.0, -1.0, 1.0, 0.0, 1.0, -1.0, 0.0, + }) + i := newBufferSubRangeFillInfoFromNewData(vc.Bytes(), 0) + h.vertexBufferFillInfo = &i + h.vertexBufferFillInfo.storeNewData(h.sb) + } + vertexBuf, vertexBufMem := h.sb.allocAndFillScratchBuffer(h.sb.s.Devices().Get(dev), []bufferSubRangeFillInfo{*h.vertexBufferFillInfo}, VkBufferUsageFlagBits_VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) defer h.sb.freeScratchBuffer(h.sb.s.Devices().Get(dev), vertexBuf, vertexBufMem) - var ic bytes.Buffer - binary.Write(&ic, binary.LittleEndian, []uint32{ - 0, 1, 2, 0, 3, 1, - }) - indexBuf, indexBufMem := h.sb.allocAndFillScratchBuffer(h.sb.s.Devices().Get(dev), ic.Bytes(), VkBufferUsageFlagBits_VK_BUFFER_USAGE_INDEX_BUFFER_BIT) + if h.indexBufferFillInfo == nil { + var ic bytes.Buffer + binary.Write(&ic, binary.LittleEndian, []uint32{ + 0, 1, 2, 0, 3, 1, + }) + i := newBufferSubRangeFillInfoFromNewData(ic.Bytes(), 0) + h.indexBufferFillInfo = &i + h.indexBufferFillInfo.storeNewData(h.sb) + } + indexBuf, indexBufMem := h.sb.allocAndFillScratchBuffer(h.sb.s.Devices().Get(dev), []bufferSubRangeFillInfo{*h.indexBufferFillInfo}, VkBufferUsageFlagBits_VK_BUFFER_USAGE_INDEX_BUFFER_BIT) defer h.sb.freeScratchBuffer(h.sb.s.Devices().Get(dev), indexBuf, indexBufMem) commandBuffer, commandPool := h.sb.getCommandBuffer(queue) @@ -1223,7 +1236,7 @@ func (h *ipRenderHandler) render(job *ipRenderJob, queue QueueObjectʳ) error { uint32(queue.Family()), // dstQueueFamilyIndex vertexBuf, // buffer 0, // offset - VkDeviceSize(len(vc.Bytes())), // size + VkDeviceSize(h.vertexBufferFillInfo.size()), // size ), NewVkBufferMemoryBarrier(h.sb.ta, VkStructureType_VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // sType @@ -1234,7 +1247,7 @@ func (h *ipRenderHandler) render(job *ipRenderJob, queue QueueObjectʳ) error { uint32(queue.Family()), // dstQueueFamilyIndex indexBuf, // buffer 0, // offset - VkDeviceSize(len(ic.Bytes())), // size + VkDeviceSize(h.indexBufferFillInfo.size()), // size ), } @@ -2072,10 +2085,11 @@ func (s *ipBufCopyJob) addDst(ctx context.Context, srcAspect, dstAspect VkImageA } type ipBufferCopySession struct { - copies map[ImageObjectʳ][]VkBufferImageCopy - content []uint8 - job *ipBufCopyJob - sb *stateBuilder + copies map[ImageObjectʳ][]VkBufferImageCopy + content []bufferSubRangeFillInfo + totalSize uint64 + job *ipBufCopyJob + sb *stateBuilder } // interfaces to interact with image primer @@ -2083,7 +2097,7 @@ type ipBufferCopySession struct { func newImagePrimerBufferCopySession(sb *stateBuilder, job *ipBufCopyJob) *ipBufferCopySession { h := &ipBufferCopySession{ copies: map[ImageObjectʳ][]VkBufferImageCopy{}, - content: []uint8{}, + content: []bufferSubRangeFillInfo{}, job: job, sb: sb, } @@ -2096,7 +2110,6 @@ func newImagePrimerBufferCopySession(sb *stateBuilder, job *ipBufCopyJob) *ipBuf } func (h *ipBufferCopySession) collectCopiesFromSubresourceRange(srcRng VkImageSubresourceRange) { - offset := uint64(len(h.content)) walkImageSubresourceRange(h.sb, h.job.srcImg, srcRng, func(aspect VkImageAspectFlagBits, layer, level uint32, levelSize byteSizeAndExtent) { extent := NewVkExtent3D(h.sb.ta, @@ -2109,47 +2122,46 @@ func (h *ipBufferCopySession) collectCopiesFromSubresourceRange(srcRng VkImageSu // like R64G64B64A64 // TODO: handle wide format _ = dstIndex - data, bufImgCopy, err := h.getCopyAndData( + bufFillInfo, bufImgCopy, err := h.getCopyAndData( dstImg, h.job.srcAspectsToDsts[aspect].dstAspect, h.job.srcImg, aspect, layer, level, MakeVkOffset3D(h.sb.ta), - extent, offset) + extent, h.totalSize) if err != nil { log.E(h.sb.ctx, "[Getting VkBufferImageCopy and raw data for priming data at image: %v, aspect: %v, layer: %v, level: %v] %v", h.job.srcImg.VulkanHandle(), aspect, layer, level, err) continue } h.copies[dstImg] = append(h.copies[dstImg], bufImgCopy) - h.content = append(h.content, data...) - offset += uint64(len(data)) + h.content = append(h.content, bufFillInfo) + h.totalSize += bufFillInfo.size() } }) } func (h *ipBufferCopySession) collectCopiesFromSparseImageBindings() { - offset := uint64(len(h.content)) walkSparseImageMemoryBindings(h.sb, h.job.srcImg, func(aspect VkImageAspectFlagBits, layer, level uint32, blockData SparseBoundImageBlockInfoʳ) { for dstIndex, dstImg := range h.job.srcAspectsToDsts[aspect].dstImgs { // dstIndex is reserved for handling wide channel image format // TODO: handle wide format _ = dstIndex - data, bufImgCopy, err := h.getCopyAndData( + bufFillInfo, bufImgCopy, err := h.getCopyAndData( dstImg, h.job.srcAspectsToDsts[aspect].dstAspect, h.job.srcImg, aspect, layer, level, blockData.Offset(), - blockData.Extent(), offset) + blockData.Extent(), h.totalSize) if err != nil { log.E(h.sb.ctx, "[Getting VkBufferImageCopy and raw data from sparse image binding at image: %v, aspect: %v, layer: %v, level: %v, offset: %v, extent: %v] %v", h.job.srcImg.VulkanHandle(), aspect, layer, level, blockData.Offset(), blockData.Extent(), err) continue } h.copies[dstImg] = append(h.copies[dstImg], bufImgCopy) - h.content = append(h.content, data...) - offset += uint64(len(data)) + h.content = append(h.content, bufFillInfo) + h.totalSize += bufFillInfo.size() } }) } func (h *ipBufferCopySession) rolloutBufCopies(submissionQueue QueueObjectʳ, dstImgsOldQueue QueueObjectʳ) error { - if len(h.content) == 0 { + if h.totalSize == 0 { return log.Errf(h.sb.ctx, nil, "[Submit buf -> img copy commands] no valid data to copy") } @@ -2206,7 +2218,7 @@ func (h *ipBufferCopySession) rolloutBufCopies(submissionQueue QueueObjectʳ, ds uint32(submissionQueue.Family()), // dstQueueFamilyIndex scratchBuffer, // buffer 0, // offset - VkDeviceSize(len(h.content)), // size + VkDeviceSize(h.totalSize), // size )).Ptr(), uint32(len(dstImgBarriers)), h.sb.MustAllocReadData(dstImgBarriers).Ptr(), @@ -2270,7 +2282,7 @@ func (h *ipBufferCopySession) rolloutBufCopies(submissionQueue QueueObjectʳ, ds // internal functions of ipBufferCopSessionr -func (h *ipBufferCopySession) getCopyAndData(dstImg ImageObjectʳ, dstAspect VkImageAspectFlagBits, srcImg ImageObjectʳ, srcAspect VkImageAspectFlagBits, layer, level uint32, opaqueBlockOffset VkOffset3D, opaqueBlockExtent VkExtent3D, bufDataOffset uint64) ([]uint8, VkBufferImageCopy, error) { +func (h *ipBufferCopySession) getCopyAndData(dstImg ImageObjectʳ, dstAspect VkImageAspectFlagBits, srcImg ImageObjectʳ, srcAspect VkImageAspectFlagBits, layer, level uint32, opaqueBlockOffset VkOffset3D, opaqueBlockExtent VkExtent3D, bufDataOffset uint64) (bufferSubRangeFillInfo, VkBufferImageCopy, error) { var err error bufImgCopy := NewVkBufferImageCopy(h.sb.ta, VkDeviceSize(bufDataOffset), // bufferOffset @@ -2294,47 +2306,72 @@ func (h *ipBufferCopySession) getCopyAndData(dstImg ImageObjectʳ, dstAspect VkI opaqueBlockExtent, srcImg.Info().Fmt(), 0, srcAspect).levelSize) - data := srcImg. + dataSlice := srcImg. Aspects().Get(srcAspect). Layers().Get(layer). Levels().Get(level). - Data().Slice(srcImgDataOffset, srcImgDataOffset+srcImgDataSizeInBytes).MustRead(h.sb.ctx, nil, h.sb.oldState, nil) + Data().Slice(srcImgDataOffset, srcImgDataOffset+srcImgDataSizeInBytes) + + errorIfUnexpectedLength := func(dataLen uint64) error { + dstLevelSize := h.sb.levelSize(opaqueBlockExtent, dstImg.Info().Fmt(), 0, dstAspect) + if dataLen != dstLevelSize.alignedLevelSizeInBuf { + return log.Errf(h.sb.ctx, nil, "size of unpackedData data does not match expectation, actual: %v, expected: %v, srcFmt: %v, dstFmt: %v", dataLen, dstLevelSize.alignedLevelSizeInBuf, srcImg.Info().Fmt(), dstImg.Info().Fmt()) + } + return nil + } + + unpackedData := []uint8{} - unpacked := data if dstImg.Info().Fmt() != srcImg.Info().Fmt() { // dstImg format is different with the srcImage format, the dst image // should be a staging image. srcVkFmt := srcImg.Info().Fmt() + data := dataSlice.MustRead(h.sb.ctx, nil, h.sb.oldState, nil) if srcVkFmt == VkFormat_VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 { data, srcVkFmt, err = ebgrDataToRGB32SFloat(data, opaqueBlockExtent) if err != nil { - return []uint8{}, bufImgCopy, log.Errf(h.sb.ctx, err, "[Converting data in VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 to VK_FORMAT_R32G32B32_SFLOAT]") + return bufferSubRangeFillInfo{}, bufImgCopy, log.Errf(h.sb.ctx, err, "[Converting data in VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 to VK_FORMAT_R32G32B32_SFLOAT]") } } - unpacked, _, err = unpackDataForPriming(h.sb.ctx, data, srcVkFmt, srcAspect) + unpackedData, _, err = unpackDataForPriming(h.sb.ctx, data, srcVkFmt, srcAspect) if err != nil { - return []uint8{}, bufImgCopy, log.Errf(h.sb.ctx, err, "[Unpacking data from format: %v aspect: %v]", srcVkFmt, srcAspect) + return bufferSubRangeFillInfo{}, bufImgCopy, log.Errf(h.sb.ctx, err, "[Unpacking data from format: %v aspect: %v]", srcVkFmt, srcAspect) } + } else if srcAspect == VkImageAspectFlagBits_VK_IMAGE_ASPECT_DEPTH_BIT { // srcImg format is the same to the dstImage format, the data is ready to // be used directly, except when the src image is a dpeth 24 UNORM one. if (srcImg.Info().Fmt() == VkFormat_VK_FORMAT_D24_UNORM_S8_UINT) || (srcImg.Info().Fmt() == VkFormat_VK_FORMAT_X8_D24_UNORM_PACK32) { - unpacked, _, err = unpackDataForPriming(h.sb.ctx, data, srcImg.Info().Fmt(), srcAspect) + data := dataSlice.MustRead(h.sb.ctx, nil, h.sb.oldState, nil) + unpackedData, _, err = unpackDataForPriming(h.sb.ctx, data, srcImg.Info().Fmt(), srcAspect) if err != nil { - return []uint8{}, bufImgCopy, log.Errf(h.sb.ctx, err, "[Unpacking data from format: %v aspect: %v]", srcImg.Info().Fmt(), srcAspect) + return bufferSubRangeFillInfo{}, bufImgCopy, log.Errf(h.sb.ctx, err, "[Unpacking data from format: %v aspect: %v]", srcImg.Info().Fmt(), srcAspect) } } } - extendToMultipleOf8(&unpacked) - - dstLevelSize := h.sb.levelSize(opaqueBlockExtent, dstImg.Info().Fmt(), 0, dstAspect) - if uint64(len(unpacked)) != dstLevelSize.alignedLevelSizeInBuf { - return []uint8{}, bufImgCopy, log.Errf(h.sb.ctx, nil, "size of unpacked data does not match expectation, actual: %v, expected: %v, srcFmt: %v, dstFmt: %v", len(unpacked), dstLevelSize.alignedLevelSizeInBuf, srcImg.Info().Fmt(), dstImg.Info().Fmt()) + if len(unpackedData) != 0 { + extendToMultipleOf8(&unpackedData) + if err := errorIfUnexpectedLength(uint64(len(unpackedData))); err != nil { + return bufferSubRangeFillInfo{}, bufImgCopy, err + } + } else if dataSlice.Size()%8 != 0 { + unpackedData = dataSlice.MustRead(h.sb.ctx, nil, h.sb.oldState, nil) + extendToMultipleOf8(&unpackedData) + if err := errorIfUnexpectedLength(uint64(len(unpackedData))); err != nil { + return bufferSubRangeFillInfo{}, bufImgCopy, err + } + } else { + if err := errorIfUnexpectedLength(dataSlice.Size()); err != nil { + return bufferSubRangeFillInfo{}, bufImgCopy, err + } } - return unpacked, bufImgCopy, nil + if len(unpackedData) != 0 { + return newBufferSubRangeFillInfoFromNewData(unpackedData, bufDataOffset), bufImgCopy, nil + } + return newBufferSubRangeFillInfoFromSlice(h.sb, dataSlice, bufDataOffset), bufImgCopy, nil } // free functions diff --git a/gapis/api/vulkan/state_rebuilder.go b/gapis/api/vulkan/state_rebuilder.go index 99ea1f4a31..4f58e9f491 100644 --- a/gapis/api/vulkan/state_rebuilder.go +++ b/gapis/api/vulkan/state_rebuilder.go @@ -18,24 +18,32 @@ import ( "context" "sort" + "github.com/google/gapid/core/data/id" "github.com/google/gapid/core/log" "github.com/google/gapid/core/math/interval" "github.com/google/gapid/core/memory/arena" "github.com/google/gapid/gapis/api" + "github.com/google/gapid/gapis/database" "github.com/google/gapid/gapis/memory" ) type stateBuilder struct { - ctx context.Context - s *State - oldState *api.GlobalState - newState *api.GlobalState - cmds []api.Cmd - cb CommandBuilder - readMemories []*api.AllocResult - writeMemories []*api.AllocResult - memoryIntervals interval.U64RangeList - ta arena.Arena // temporary arena + ctx context.Context + s *State + oldState *api.GlobalState + newState *api.GlobalState + cmds []api.Cmd + cb CommandBuilder + readMemories []*api.AllocResult + writeMemories []*api.AllocResult + extraReadIDsAndRanges []idAndRng + memoryIntervals interval.U64RangeList + ta arena.Arena // temporary arena +} + +type idAndRng struct { + id id.ID + rng memory.Range } // TODO: wherever possible, use old resources instead of doing full reads on the old pools. @@ -261,6 +269,33 @@ func (sb *stateBuilder) MustUnpackWriteMap(v interface{}) api.AllocResult { return allocateResult } +func (sb *stateBuilder) MustReserve(size uint64) api.AllocResult { + res := sb.newState.AllocOrPanic(sb.ctx, size) + interval.Merge(&sb.memoryIntervals, res.Range().Span(), true) + return res +} + +func (sb *stateBuilder) ReadDataAt(dataID id.ID, base, size uint64) { + rng := memory.Range{base, size} + interval.Merge(&sb.memoryIntervals, rng.Span(), true) + sb.extraReadIDsAndRanges = append(sb.extraReadIDsAndRanges, idAndRng{ + id: dataID, + rng: rng, + }) +} + +type sliceWithID interface { + memory.Slice + ResourceID(ctx context.Context, state *api.GlobalState) id.ID +} + +func (sb *stateBuilder) mustReadSlice(v sliceWithID) api.AllocResult { + res := sb.MustReserve(v.Size()) + sb.readMemories = append(sb.readMemories, &res) + sb.ReadDataAt(v.ResourceID(sb.ctx, sb.oldState), res.Address(), v.Size()) + return res +} + func (sb *stateBuilder) getCommandBuffer(queue QueueObjectʳ) (VkCommandBuffer, VkCommandPool) { commandBufferID := VkCommandBuffer(newUnusedID(true, func(x uint64) bool { return sb.s.CommandBuffers().Contains(VkCommandBuffer(x)) })) commandPoolID := VkCommandPool(newUnusedID(true, func(x uint64) bool { return sb.s.CommandPools().Contains(VkCommandPool(x)) })) @@ -341,6 +376,9 @@ func (sb *stateBuilder) write(cmd api.Cmd) { for _, read := range sb.readMemories { cmd.Extras().GetOrAppendObservations().AddRead(read.Data()) } + for _, ir := range sb.extraReadIDsAndRanges { + cmd.Extras().GetOrAppendObservations().AddRead(ir.rng, ir.id) + } for _, write := range sb.writeMemories { cmd.Extras().GetOrAppendObservations().AddWrite(write.Data()) } @@ -359,6 +397,7 @@ func (sb *stateBuilder) write(cmd api.Cmd) { } sb.readMemories = []*api.AllocResult{} sb.writeMemories = []*api.AllocResult{} + sb.extraReadIDsAndRanges = []idAndRng{} } func (sb *stateBuilder) createInstance(vk VkInstance, inst InstanceObjectʳ) { @@ -828,16 +867,63 @@ func memoryTypeIndexFor(memTypeBits uint32, props VkPhysicalDeviceMemoryProperti return -1 } -func (sb *stateBuilder) allocAndFillScratchBuffer(device DeviceObjectʳ, data []uint8, usages ...VkBufferUsageFlagBits) (VkBuffer, VkDeviceMemory) { - buffer := VkBuffer(newUnusedID(true, func(x uint64) bool { return sb.s.Buffers().Contains(VkBuffer(x)) })) - deviceMemory := VkDeviceMemory(newUnusedID(true, func(x uint64) bool { return sb.s.DeviceMemories().Contains(VkDeviceMemory(x)) })) +type bufferSubRangeFillInfo struct { + rng interval.U64Range // Do not use memory.Range because this is not a range in memory + data []uint8 + hash id.ID + hasNewData bool +} + +func newBufferSubRangeFillInfoFromNewData(data []uint8, offsetInBuf uint64) bufferSubRangeFillInfo { + return bufferSubRangeFillInfo{ + rng: interval.U64Range{offsetInBuf, uint64(len(data))}, + data: data, + hash: id.ID{}, + hasNewData: true, + } +} + +func newBufferSubRangeFillInfoFromSlice(sb *stateBuilder, slice U8ˢ, offsetInBuf uint64) bufferSubRangeFillInfo { + return bufferSubRangeFillInfo{ + rng: interval.U64Range{offsetInBuf, slice.Size()}, + data: []uint8{}, + hash: slice.ResourceID(sb.ctx, sb.oldState), + hasNewData: false, + } +} - size := VkDeviceSize(len(data)) +func (i bufferSubRangeFillInfo) size() uint64 { + return i.rng.Count +} + +func (i *bufferSubRangeFillInfo) storeNewData(sb *stateBuilder) { + if i.hasNewData { + hash, err := database.Store(sb.ctx, i.data) + if err != nil { + panic(err) + } + i.hash = hash + i.hasNewData = false + } +} + +func (sb *stateBuilder) allocAndFillScratchBuffer(device DeviceObjectʳ, subRngs []bufferSubRangeFillInfo, usages ...VkBufferUsageFlagBits) (VkBuffer, VkDeviceMemory) { + buffer := VkBuffer(newUnusedID(true, func(x uint64) bool { + return sb.s.Buffers().Contains(VkBuffer(x)) || GetState(sb.newState).Buffers().Contains(VkBuffer(x)) + })) + deviceMemory := VkDeviceMemory(newUnusedID(true, func(x uint64) bool { + return sb.s.DeviceMemories().Contains(VkDeviceMemory(x)) || GetState(sb.newState).DeviceMemories().Contains(VkDeviceMemory(x)) + })) usageFlags := VkBufferUsageFlags(VkBufferUsageFlagBits_VK_BUFFER_USAGE_TRANSFER_SRC_BIT) for _, u := range usages { usageFlags |= VkBufferUsageFlags(u) } - + size := uint64(0) + for _, r := range subRngs { + if r.rng.Span().End > size { + size = r.rng.Span().End + } + } sb.write(sb.cb.VkCreateBuffer( device.VulkanHandle(), sb.MustAllocReadData( @@ -845,7 +931,7 @@ func (sb *stateBuilder) allocAndFillScratchBuffer(device DeviceObjectʳ, data [] VkStructureType_VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // sType 0, // pNext 0, // flags - size, // size + VkDeviceSize(size), // size usageFlags, // usage VkSharingMode_VK_SHARING_MODE_EXCLUSIVE, // sharingMode 0, // queueFamilyIndexCount @@ -888,41 +974,52 @@ func (sb *stateBuilder) allocAndFillScratchBuffer(device DeviceObjectʳ, data [] VkResult_VK_SUCCESS, )) - dat := sb.newState.AllocDataOrPanic(sb.ctx, data) - at := NewVoidᵖ(dat.Ptr()) - atdata := sb.newState.AllocDataOrPanic(sb.ctx, at) + atData := sb.MustReserve(size) + ptrAtData := sb.newState.AllocDataOrPanic(sb.ctx, NewVoidᵖ(atData.Ptr())) sb.write(sb.cb.VkMapMemory( device.VulkanHandle(), deviceMemory, VkDeviceSize(0), - size, + VkDeviceSize(size), VkMemoryMapFlags(0), - atdata.Ptr(), + ptrAtData.Ptr(), VkResult_VK_SUCCESS, - ).AddRead(atdata.Data()).AddWrite(atdata.Data())) - + ).AddRead(ptrAtData.Data()).AddWrite(ptrAtData.Data())) + ptrAtData.Free() + + for _, r := range subRngs { + var hash id.ID + var err error + if r.hasNewData { + hash, err = database.Store(sb.ctx, r.data) + if err != nil { + panic(err) + } + } else { + hash = r.hash + } + sb.ReadDataAt(hash, atData.Address()+r.rng.First, r.rng.Count) + } sb.write(sb.cb.VkFlushMappedMemoryRanges( device.VulkanHandle(), 1, sb.MustAllocReadData(NewVkMappedMemoryRange(sb.ta, VkStructureType_VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // sType - 0, // pNext - deviceMemory, // memory - 0, // offset - size, // size + 0, // pNext + deviceMemory, // memory + 0, // offset + VkDeviceSize(size), // size )).Ptr(), VkResult_VK_SUCCESS, - ).AddRead(dat.Data())) + )) + atData.Free() sb.write(sb.cb.VkUnmapMemory( device.VulkanHandle(), deviceMemory, )) - dat.Free() - atdata.Free() - return buffer, deviceMemory } @@ -1070,7 +1167,7 @@ func (sb *stateBuilder) createBuffer(buffer BufferObjectʳ) { return } - contents := []uint8{} + contents := []bufferSubRangeFillInfo{} copies := []VkBufferCopy{} offset := VkDeviceSize(0) @@ -1133,11 +1230,10 @@ func (sb *stateBuilder) createBuffer(buffer BufferObjectʳ) { if sparseResidency || IsFullyBound(0, buffer.Info().Size(), buffer.SparseMemoryBindings()) { for _, bind := range buffer.SparseMemoryBindings().All() { size := bind.Size() - data := sb.s.DeviceMemories().Get(bind.Memory()).Data().Slice( + dataSlice := sb.s.DeviceMemories().Get(bind.Memory()).Data().Slice( uint64(bind.MemoryOffset()), - uint64(bind.MemoryOffset()+size), - ).MustRead(sb.ctx, nil, sb.oldState, nil) - contents = append(contents, data...) + uint64(bind.MemoryOffset()+size)) + contents = append(contents, newBufferSubRangeFillInfoFromSlice(sb, dataSlice, uint64(offset))) copies = append(copies, NewVkBufferCopy(sb.ta, offset, // srcOffset bind.ResourceOffset(), // dstOffset @@ -1162,11 +1258,10 @@ func (sb *stateBuilder) createBuffer(buffer BufferObjectʳ) { )) size := buffer.Info().Size() - data := buffer.Memory().Data().Slice( + dataSlice := buffer.Memory().Data().Slice( uint64(buffer.MemoryOffset()), - uint64(buffer.MemoryOffset()+size), - ).MustRead(sb.ctx, nil, sb.oldState, nil) - contents = append(contents, data...) + uint64(buffer.MemoryOffset()+size)) + contents = append(contents, newBufferSubRangeFillInfoFromSlice(sb, dataSlice, uint64(offset))) copies = append(copies, NewVkBufferCopy(sb.ta, offset, // srcOffset 0, // dstOffset @@ -1805,8 +1900,7 @@ func (sb *stateBuilder) createDescriptorSetLayout(dsl DescriptorSetLayoutObject for _, kk := range b.ImmutableSamplers().Keys() { immutableSamplers = append(immutableSamplers, b.ImmutableSamplers().Get(kk).VulkanHandle()) } - allocateResult := sb.newState.AllocDataOrPanic(sb.ctx, immutableSamplers) - sb.readMemories = append(sb.readMemories, &allocateResult) + allocateResult := sb.MustAllocReadData(immutableSamplers) smp = NewVkSamplerᶜᵖ(allocateResult.Ptr()) } @@ -1908,16 +2002,14 @@ func (sb *stateBuilder) createRenderPass(rp RenderPassObjectʳ) { } func (sb *stateBuilder) createShaderModule(sm ShaderModuleObjectʳ) { - words := sm.Words().MustRead(sb.ctx, nil, sb.oldState, nil) - sb.write(sb.cb.VkCreateShaderModule( sm.Device(), sb.MustAllocReadData(NewVkShaderModuleCreateInfo(sb.ta, VkStructureType_VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // sType 0, // pNext 0, // flags - memory.Size(len(words))*4, // codeSize - NewU32ᶜᵖ(sb.MustAllocReadData(words).Ptr()), // pCode + memory.Size(sm.Words().Count()*4), // codeSize + NewU32ᶜᵖ(sb.mustReadSlice(sm.Words()).Ptr()), // pCode )).Ptr(), memory.Nullptr, sb.MustAllocWriteData(sm.VulkanHandle()).Ptr(), @@ -1948,12 +2040,12 @@ func (sb *stateBuilder) createComputePipeline(cp ComputePipelineObjectʳ) { specializationInfo := NewVkSpecializationInfoᶜᵖ(memory.Nullptr) if !cp.Stage().Specialization().IsNil() { - data := cp.Stage().Specialization().Data().MustRead(sb.ctx, nil, sb.oldState, nil) + data := cp.Stage().Specialization().Data() specializationInfo = NewVkSpecializationInfoᶜᵖ(sb.MustAllocReadData(NewVkSpecializationInfo(sb.ta, uint32(cp.Stage().Specialization().Specializations().Len()), // mapEntryCount NewVkSpecializationMapEntryᶜᵖ(sb.MustUnpackReadMap(cp.Stage().Specialization().Specializations().All()).Ptr()), // pMapEntries - memory.Size(len(data)), // dataSize - NewVoidᶜᵖ(sb.MustAllocReadData(data).Ptr()), // pData + memory.Size(data.Size()), // dataSize + NewVoidᶜᵖ(sb.mustReadSlice(data).Ptr()), // pData )).Ptr()) } @@ -2039,13 +2131,13 @@ func (sb *stateBuilder) createGraphicsPipeline(gp GraphicsPipelineObjectʳ) { s := gp.Stages().Get(ss) specializationInfo := NewVkSpecializationInfoᶜᵖ(memory.Nullptr) if !s.Specialization().IsNil() { - data := s.Specialization().Data().MustRead(sb.ctx, nil, sb.oldState, nil) + data := s.Specialization().Data() specializationInfo = NewVkSpecializationInfoᶜᵖ(sb.MustAllocReadData( NewVkSpecializationInfo(sb.ta, uint32(s.Specialization().Specializations().Len()), // mapEntryCount NewVkSpecializationMapEntryᶜᵖ(sb.MustUnpackReadMap(s.Specialization().Specializations().All()).Ptr()), // pMapEntries - memory.Size(len(data)), // dataSize - NewVoidᶜᵖ(sb.MustAllocReadData(data).Ptr()), // pData + memory.Size(data.Size()), // dataSize + NewVoidᶜᵖ(sb.mustReadSlice(data).Ptr()), // pData )).Ptr()) } stages = append(stages, NewVkPipelineShaderStageCreateInfo(sb.ta,