From 5c39b3e13c398c7a781835b82a38796dc5c1ae27 Mon Sep 17 00:00:00 2001 From: Andrew Woloszyn Date: Tue, 24 Apr 2018 11:56:20 -0400 Subject: [PATCH] Update to read_framebuffer to allow compute presentation. --- gapis/api/api.go | 2 +- gapis/api/gles/gles.go | 18 ++-- gapis/api/gvr/gvr.go | 4 +- gapis/api/vulkan/read_framebuffer.go | 120 +++++++++++++++--------- gapis/api/vulkan/state.go | 32 +++++-- gapis/api/vulkan/vulkan.go | 14 +-- gapis/resolve/framebuffer_attachment.go | 8 +- gapis/resolve/framebuffer_changes.go | 4 +- 8 files changed, 124 insertions(+), 78 deletions(-) diff --git a/gapis/api/api.go b/gapis/api/api.go index d2f5248380..b360b1e1bf 100644 --- a/gapis/api/api.go +++ b/gapis/api/api.go @@ -46,7 +46,7 @@ type API interface { after []uint64, state *GlobalState, thread uint64, - attachment FramebufferAttachment) (width, height, index uint32, format *image.Format, err error) + attachment FramebufferAttachment) (width, height, index uint32, format *image.Format, canResize bool, err error) // Context returns the active context for the given state. Context(state *GlobalState, thread uint64) Context diff --git a/gapis/api/gles/gles.go b/gapis/api/gles/gles.go index d4730f2624..49ced7faa3 100644 --- a/gapis/api/gles/gles.go +++ b/gapis/api/gles/gles.go @@ -193,7 +193,7 @@ func (API) GetFramebufferAttachmentInfo( after []uint64, state *api.GlobalState, thread uint64, - attachment api.FramebufferAttachment) (width, height, index uint32, format *image.Format, err error) { + attachment api.FramebufferAttachment) (width, height, index uint32, format *image.Format, canResize bool, err error) { return GetFramebufferAttachmentInfoByID(state, thread, attachment, 0) } @@ -205,37 +205,37 @@ func GetFramebufferAttachmentInfoByID( state *api.GlobalState, thread uint64, attachment api.FramebufferAttachment, - fb FramebufferId) (width, height, index uint32, format *image.Format, err error) { + fb FramebufferId) (width, height, index uint32, format *image.Format, canResize bool, err error) { s := GetState(state) if fb == 0 { c := s.GetContext(thread) if c == nil { - return 0, 0, 0, nil, fmt.Errorf("No context bound") + return 0, 0, 0, nil, true, fmt.Errorf("No context bound") } if !c.Other.Initialized { - return 0, 0, 0, nil, fmt.Errorf("Context not initialized") + return 0, 0, 0, nil, true, fmt.Errorf("Context not initialized") } fb = c.Bound.DrawFramebuffer.GetID() } glAtt, err := attachmentToEnum(attachment) if err != nil { - return 0, 0, 0, nil, err + return 0, 0, 0, nil, true, err } fbai, err := s.getFramebufferAttachmentInfo(thread, fb, glAtt) if fbai.format == 0 { - return 0, 0, 0, nil, fmt.Errorf("No format set") + return 0, 0, 0, nil, true, fmt.Errorf("No format set") } if err != nil { - return 0, 0, 0, nil, err + return 0, 0, 0, nil, true, err } fmt, ty := getUnsizedFormatAndType(fbai.format) f, err := getImageFormat(fmt, ty) if err != nil { - return 0, 0, 0, nil, err + return 0, 0, 0, nil, true, err } switch { case attachment.IsDepth(): @@ -243,7 +243,7 @@ func GetFramebufferAttachmentInfoByID( case attachment.IsStencil(): f = filterUncompressedImageFormat(f, stream.Channel.IsStencil) } - return fbai.width, fbai.height, 0, f, nil + return fbai.width, fbai.height, 0, f, true, nil } // Context returns the active context for the given state and thread. diff --git a/gapis/api/gvr/gvr.go b/gapis/api/gvr/gvr.go index e9be439a3b..190c9f64cd 100644 --- a/gapis/api/gvr/gvr.go +++ b/gapis/api/gvr/gvr.go @@ -91,11 +91,11 @@ func (API) GetFramebufferAttachmentInfo( after []uint64, state *api.GlobalState, thread uint64, - attachment api.FramebufferAttachment) (width, height, index uint32, format *image.Format, err error) { + attachment api.FramebufferAttachment) (width, height, index uint32, format *image.Format, canResize bool, err error) { fb, err := getFramebuffer(ctx, api.CmdID(after[0])) if err != nil { - return 0, 0, 0, nil, err + return 0, 0, 0, nil, false, err } return gles.GetFramebufferAttachmentInfoByID(state, thread, attachment, fb) } diff --git a/gapis/api/vulkan/read_framebuffer.go b/gapis/api/vulkan/read_framebuffer.go index 3f3953d98c..1bd9026c80 100644 --- a/gapis/api/vulkan/read_framebuffer.go +++ b/gapis/api/vulkan/read_framebuffer.go @@ -219,6 +219,10 @@ func postImageData(ctx context.Context, device := GetState(s).Devices.Get(vkDevice) vkPhysicalDevice := device.PhysicalDevice physicalDevice := GetState(s).PhysicalDevices.Get(vkPhysicalDevice) + + requestWidth := reqWidth + requestHeight := reqHeight + // Rendered image should always has a graphics-capable queue bound, if none // of such a queue found for this image or the bound queue does not have // graphics capability, throw error messages and return. @@ -228,8 +232,17 @@ func postImageData(ctx context.Context, } if properties, ok := physicalDevice.QueueFamilyProperties.Lookup(queue.Family); ok { if properties.QueueFlags&VkQueueFlags(VkQueueFlagBits_VK_QUEUE_GRAPHICS_BIT) == 0 { - res(nil, &service.ErrDataUnavailable{Reason: messages.ErrMessage("The bound vkQueue does not have VK_QUEUE_GRAPHICS_BIT capability")}) - return + if imageObject.Info.Samples == VkSampleCountFlagBits_VK_SAMPLE_COUNT_1_BIT && + aspect == VkImageAspectFlagBits_VK_IMAGE_ASPECT_COLOR_BIT { + // If this is on the compute queue, we cannot do a blit operation, + // We can however do it on the CPU afterwards, or let the + // client deal with it + requestWidth = imgWidth + requestHeight = imgHeight + } else { + res(nil, &service.ErrDataUnavailable{Reason: messages.ErrMessage("Unhandled: Reading a multisampled or depth image on the compute queue")}) + return + } } } else { res(nil, &service.ErrDataUnavailable{Reason: messages.ErrMessage("Not found the properties information of the bound vkQueue")}) @@ -273,13 +286,13 @@ func postImageData(ctx context.Context, } } - bufferSize := uint64(formatOfImgRes.Size(int(reqWidth), int(reqHeight), 1)) + bufferSize := uint64(formatOfImgRes.Size(int(requestWidth), int(requestHeight), 1)) // For the depth aspect of VK_FORMAT_X8_D24_UNORM_PACK32 and // VK_FORMAT_D24_UNORM_S8_UINT format, each depth element requires 4 bytes in // the buffer when used in buffer image copy. if aspect == VkImageAspectFlagBits_VK_IMAGE_ASPECT_DEPTH_BIT && (vkFormat == VkFormat_VK_FORMAT_X8_D24_UNORM_PACK32 || vkFormat == VkFormat_VK_FORMAT_D24_UNORM_S8_UINT) { r32Fmt, _ := getImageFormatFromVulkanFormat(VkFormat_VK_FORMAT_R32_UINT) - bufferSize = uint64(r32Fmt.Size(int(reqWidth), int(reqHeight), 1)) + bufferSize = uint64(r32Fmt.Size(int(requestWidth), int(requestHeight), 1)) } // Data and info for destination buffer creation @@ -315,8 +328,8 @@ func postImageData(ctx context.Context, ImageType: VkImageType_VK_IMAGE_TYPE_2D, Fmt: vkFormat, Extent: VkExtent3D{ - Width: reqWidth, - Height: reqHeight, + Width: requestWidth, + Height: requestHeight, Depth: 1, }, MipLevels: 1, @@ -413,7 +426,7 @@ func postImageData(ctx context.Context, LayerCount: 1, }, ImageOffset: VkOffset3D{X: 0, Y: 0, Z: 0}, - ImageExtent: VkExtent3D{Width: reqWidth, Height: reqHeight, Depth: 1}, + ImageExtent: VkExtent3D{Width: requestWidth, Height: requestHeight, Depth: 1}, } bufferImageCopyData := MustAllocData(ctx, s, bufferImageCopy) @@ -629,8 +642,8 @@ func postImageData(ctx context.Context, Z: 0, }, { - X: int32(reqWidth), - Y: int32(reqHeight), + X: int32(requestWidth), + Y: int32(requestHeight), Z: 1, }, }, @@ -906,36 +919,60 @@ func postImageData(ctx context.Context, if aspect != VkImageAspectFlagBits_VK_IMAGE_ASPECT_COLOR_BIT { filter = VkFilter_VK_FILTER_NEAREST } + + doBlit := true + copySrc := stagingImageId + + if requestWidth == imgWidth && requestHeight == imgHeight { + doBlit = false + copySrc = blitSrcImage + } + + if doBlit { + writeEach(ctx, out, + cb.VkCmdBlitImage( + commandBufferId, + blitSrcImage, + VkImageLayout_VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + stagingImageId, + VkImageLayout_VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + imageBlitData.Ptr(), + filter, + ).AddRead(imageBlitData.Data()), + // Set the blit image to transfer src + cb.VkCmdPipelineBarrier( + commandBufferId, + VkPipelineStageFlags(VkPipelineStageFlagBits_VK_PIPELINE_STAGE_ALL_COMMANDS_BIT), + VkPipelineStageFlags(VkPipelineStageFlagBits_VK_PIPELINE_STAGE_ALL_COMMANDS_BIT), + VkDependencyFlags(0), + 0, + memory.Nullptr, + 0, + memory.Nullptr, + 1, + stagingImageToSrcBarrierData.Ptr(), + ).AddRead( + stagingImageToSrcBarrierData.Data(), + ), + ) + } + writeEach(ctx, out, - cb.VkCmdBlitImage( + cb.VkCmdCopyImageToBuffer( commandBufferId, - blitSrcImage, + copySrc, VkImageLayout_VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - stagingImageId, - VkImageLayout_VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + bufferId, 1, - imageBlitData.Ptr(), - filter, - ).AddRead(imageBlitData.Data()), + bufferImageCopyData.Ptr(), + ).AddRead( + bufferImageCopyData.Data(), + ), ) - // Change the layout of staging image and attachment image, copy staging image to buffer, - // end command buffer writeEach(ctx, out, - cb.VkCmdPipelineBarrier( - commandBufferId, - VkPipelineStageFlags(VkPipelineStageFlagBits_VK_PIPELINE_STAGE_ALL_COMMANDS_BIT), - VkPipelineStageFlags(VkPipelineStageFlagBits_VK_PIPELINE_STAGE_ALL_COMMANDS_BIT), - VkDependencyFlags(0), - 0, - memory.Nullptr, - 0, - memory.Nullptr, - 1, - stagingImageToSrcBarrierData.Ptr(), - ).AddRead( - stagingImageToSrcBarrierData.Data(), - ), + // Reset the image, and end the command buffer. cb.VkCmdPipelineBarrier( commandBufferId, VkPipelineStageFlags(VkPipelineStageFlagBits_VK_PIPELINE_STAGE_ALL_COMMANDS_BIT), @@ -950,20 +987,11 @@ func postImageData(ctx context.Context, ).AddRead( attachmentImageResetLayoutBarrierData.Data(), ), - cb.VkCmdCopyImageToBuffer( - commandBufferId, - stagingImageId, - VkImageLayout_VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - bufferId, - 1, - bufferImageCopyData.Ptr(), - ).AddRead( - bufferImageCopyData.Data(), - ), cb.VkEndCommandBuffer( commandBufferId, VkResult_VK_SUCCESS, - )) + ), + ) // Submit all the commands above, wait until finish. writeEach(ctx, out, @@ -1036,7 +1064,7 @@ func postImageData(ctx context.Context, } // Flip the image in Y axis - rowSizeInBytes := uint64(formatOfImgRes.Size(int(reqWidth), 1, 1)) + rowSizeInBytes := uint64(formatOfImgRes.Size(int(requestWidth), 1, 1)) top := uint64(0) bottom := bufferSize - rowSizeInBytes var temp = make([]byte, rowSizeInBytes) @@ -1055,8 +1083,8 @@ func postImageData(ctx context.Context, img := &image.Data{ Bytes: bytes, - Width: uint32(reqWidth), - Height: uint32(reqHeight), + Width: uint32(requestWidth), + Height: uint32(requestHeight), Depth: 1, Format: formatOfImgRes, } diff --git a/gapis/api/vulkan/state.go b/gapis/api/vulkan/state.go index b0017489a7..b8df91a4ab 100644 --- a/gapis/api/vulkan/state.go +++ b/gapis/api/vulkan/state.go @@ -20,9 +20,9 @@ import ( "github.com/google/gapid/gapis/api" ) -func (st *State) getSubmitAttachmentInfo(attachment api.FramebufferAttachment) (w, h uint32, f VkFormat, attachmentIndex uint32, err error) { - returnError := func(format_str string, e ...interface{}) (w, h uint32, f VkFormat, attachmentIndex uint32, err error) { - return 0, 0, VkFormat_VK_FORMAT_UNDEFINED, 0, fmt.Errorf(format_str, e...) +func (st *State) getSubmitAttachmentInfo(attachment api.FramebufferAttachment) (w, h uint32, f VkFormat, attachmentIndex uint32, canResize bool, err error) { + returnError := func(format_str string, e ...interface{}) (w, h uint32, f VkFormat, attachmentIndex uint32, canResize bool, err error) { + return 0, 0, VkFormat_VK_FORMAT_UNDEFINED, 0, true, fmt.Errorf(format_str, e...) } lastQueue := st.LastBoundQueue @@ -54,7 +54,7 @@ func (st *State) getSubmitAttachmentInfo(attachment api.FramebufferAttachment) ( attachment_index := uint32(attachment - api.FramebufferAttachment_Color0) if att_ref, ok := subpass_desc.ColorAttachments.Lookup(attachment_index); ok { if ca, ok := lastDrawInfo.Framebuffer.ImageAttachments.Lookup(att_ref.Attachment); ok { - return ca.Image.Info.Extent.Width, ca.Image.Info.Extent.Height, ca.Image.Info.Fmt, att_ref.Attachment, nil + return ca.Image.Info.Extent.Width, ca.Image.Info.Extent.Height, ca.Image.Info.Fmt, att_ref.Attachment, true, nil } } @@ -63,7 +63,7 @@ func (st *State) getSubmitAttachmentInfo(attachment api.FramebufferAttachment) ( att_ref := subpass_desc.DepthStencilAttachment if attachment, ok := lastDrawInfo.Framebuffer.ImageAttachments.Lookup(att_ref.Attachment); ok { depth_img := attachment.Image - return depth_img.Info.Extent.Width, depth_img.Info.Extent.Height, depth_img.Info.Fmt, att_ref.Attachment, nil + return depth_img.Info.Extent.Width, depth_img.Info.Extent.Height, depth_img.Info.Fmt, att_ref.Attachment, true, nil } } case api.FramebufferAttachment_Stencil: @@ -75,9 +75,9 @@ func (st *State) getSubmitAttachmentInfo(attachment api.FramebufferAttachment) ( return returnError("%s is not bound", attachment) } -func (st *State) getPresentAttachmentInfo(attachment api.FramebufferAttachment) (w, h uint32, f VkFormat, attachmentIndex uint32, err error) { - returnError := func(format_str string, e ...interface{}) (w, h uint32, f VkFormat, attachmentIndex uint32, err error) { - return 0, 0, VkFormat_VK_FORMAT_UNDEFINED, 0, fmt.Errorf(format_str, e...) +func (st *State) getPresentAttachmentInfo(attachment api.FramebufferAttachment) (w, h uint32, f VkFormat, attachmentIndex uint32, canResize bool, err error) { + returnError := func(format_str string, e ...interface{}) (w, h uint32, f VkFormat, attachmentIndex uint32, canResize bool, err error) { + return 0, 0, VkFormat_VK_FORMAT_UNDEFINED, 0, false, fmt.Errorf(format_str, e...) } switch attachment { @@ -91,7 +91,19 @@ func (st *State) getPresentAttachmentInfo(attachment api.FramebufferAttachment) } color_img := st.LastPresentInfo.PresentImages.Get(image_idx) if color_img != nil { - return color_img.Info.Extent.Width, color_img.Info.Extent.Height, color_img.Info.Fmt, image_idx, nil + queue := color_img.LastBoundQueue + vkDevice := queue.Device + device := st.Devices.Get(vkDevice) + vkPhysicalDevice := device.PhysicalDevice + physicalDevice := st.PhysicalDevices.Get(vkPhysicalDevice) + if properties, ok := physicalDevice.QueueFamilyProperties.Lookup(queue.Family); ok { + if properties.QueueFlags&VkQueueFlags(VkQueueFlagBits_VK_QUEUE_GRAPHICS_BIT) != 0 { + return color_img.Info.Extent.Width, color_img.Info.Extent.Height, color_img.Info.Fmt, image_idx, true, nil + } + return color_img.Info.Extent.Width, color_img.Info.Extent.Height, color_img.Info.Fmt, image_idx, false, nil + } + + return returnError("Last present queue does not exist", attachment) } case api.FramebufferAttachment_Depth: fallthrough @@ -103,7 +115,7 @@ func (st *State) getPresentAttachmentInfo(attachment api.FramebufferAttachment) return returnError("Swapchain attachment %v does not exist", attachment) } -func (st *State) getFramebufferAttachmentInfo(attachment api.FramebufferAttachment) (uint32, uint32, VkFormat, uint32, error) { +func (st *State) getFramebufferAttachmentInfo(attachment api.FramebufferAttachment) (uint32, uint32, VkFormat, uint32, bool, error) { if st.LastSubmission == LastSubmissionType_SUBMIT { return st.getSubmitAttachmentInfo(attachment) } else { diff --git a/gapis/api/vulkan/vulkan.go b/gapis/api/vulkan/vulkan.go index de9d1914e3..47858860bf 100644 --- a/gapis/api/vulkan/vulkan.go +++ b/gapis/api/vulkan/vulkan.go @@ -96,24 +96,24 @@ func (API) GetFramebufferAttachmentInfo( after []uint64, state *api.GlobalState, thread uint64, - attachment api.FramebufferAttachment) (width, height, index uint32, format *image.Format, err error) { + attachment api.FramebufferAttachment) (width, height, index uint32, format *image.Format, canResize bool, err error) { - w, h, form, i, err := GetState(state).getFramebufferAttachmentInfo(attachment) + w, h, form, i, r, err := GetState(state).getFramebufferAttachmentInfo(attachment) switch attachment { case api.FramebufferAttachment_Stencil: - return 0, 0, 0, nil, fmt.Errorf("Unsupported Stencil") + return 0, 0, 0, nil, true, fmt.Errorf("Unsupported Stencil") case api.FramebufferAttachment_Depth: format, err := getDepthImageFormatFromVulkanFormat(form) if err != nil { - return 0, 0, 0, nil, fmt.Errorf("Unknown format for Depth attachment: %v", form) + return 0, 0, 0, nil, true, fmt.Errorf("Unknown format for Depth attachment: %v", form) } - return w, h, i, format, err + return w, h, i, format, r, err default: format, err := getImageFormatFromVulkanFormat(form) if err != nil { - return 0, 0, 0, nil, fmt.Errorf("Unknown format for Color attachment: %v", form) + return 0, 0, 0, nil, true, fmt.Errorf("Unknown format for Color attachment: %v", form) } - return w, h, i, format, err + return w, h, i, format, r, err } } diff --git a/gapis/resolve/framebuffer_attachment.go b/gapis/resolve/framebuffer_attachment.go index f119e88ae3..2f417b6397 100644 --- a/gapis/resolve/framebuffer_attachment.go +++ b/gapis/resolve/framebuffer_attachment.go @@ -83,6 +83,9 @@ func (r *FramebufferAttachmentResolvable) Resolve(ctx context.Context) (interfac } width, height := uniformScale(fbInfo.Width, fbInfo.Height, r.Settings.MaxWidth, r.Settings.MaxHeight) + if !fbInfo.CanResize { + width, height = fbInfo.Width, fbInfo.Height + } id, err := database.Store(ctx, &FramebufferAttachmentBytesResolvable{ ReplaySettings: r.ReplaySettings, @@ -139,6 +142,9 @@ type FramebufferAttachmentInfo struct { // Height of the framebuffer attachment in pixels. Height uint32 + // Can this image be resized in the server + CanResize bool + // Index of the api-specific attachment. Index uint32 @@ -156,7 +162,7 @@ func (f FramebufferAttachmentInfo) equal(o FramebufferAttachmentInfo) bool { return false } if f.Err == nil { - return fe && f.Width == o.Width && f.Height == o.Height && f.Index == o.Index + return fe && f.Width == o.Width && f.Height == o.Height && f.Index == o.Index && f.CanResize == o.CanResize } return f.Err.Error() == o.Err.Error() } diff --git a/gapis/resolve/framebuffer_changes.go b/gapis/resolve/framebuffer_changes.go index dcb3129b6a..f8fc76cc51 100644 --- a/gapis/resolve/framebuffer_changes.go +++ b/gapis/resolve/framebuffer_changes.go @@ -80,8 +80,8 @@ func (r *FramebufferChangesResolvable) Resolve(ctx context.Context) (interface{} for _, att := range allFramebufferAttachments { info := FramebufferAttachmentInfo{After: idx} if api != nil { - if w, h, i, f, err := api.GetFramebufferAttachmentInfo(ctx, idx, s, cmd.Thread(), att); err == nil && f != nil { - info.Width, info.Height, info.Index, info.Format = w, h, i, f + if w, h, i, f, r, err := api.GetFramebufferAttachmentInfo(ctx, idx, s, cmd.Thread(), att); err == nil && f != nil { + info.Width, info.Height, info.Index, info.Format, info.CanResize = w, h, i, f, r } else { info.Err = err }