From 21f9c9b8ec0d094fe2051a30e759e840f2b08cb0 Mon Sep 17 00:00:00 2001 From: DH Date: Wed, 19 Jul 2023 15:02:57 +0300 Subject: [PATCH] [amdgpu] Add ImageRef utility --- hw/amdgpu/device/include/amdgpu/device/vk.hpp | 229 ++++++++++-------- hw/amdgpu/device/src/device.cpp | 61 ++--- 2 files changed, 156 insertions(+), 134 deletions(-) diff --git a/hw/amdgpu/device/include/amdgpu/device/vk.hpp b/hw/amdgpu/device/include/amdgpu/device/vk.hpp index beb624470..cc6b94f6b 100644 --- a/hw/amdgpu/device/include/amdgpu/device/vk.hpp +++ b/hw/amdgpu/device/include/amdgpu/device/vk.hpp @@ -552,107 +552,36 @@ public: bool operator!=(std::nullptr_t) const { return mBuffer != nullptr; } }; -class Image2D { +class Image2D; + +class ImageRef { VkImage mImage = VK_NULL_HANDLE; VkFormat mFormat = {}; VkImageAspectFlags mAspects = {}; - VkImageLayout mLayout = {}; + VkImageLayout *mLayout = {}; unsigned mWidth = 0; unsigned mHeight = 0; - DeviceMemoryRef mMemory; + unsigned mDepth = 0; public: - Image2D(const Image2D &) = delete; + ImageRef() = default; + ImageRef(Image2D &); - Image2D() = default; - Image2D(Image2D &&other) { *this = std::move(other); } - - ~Image2D() { - if (mImage != nullptr && mMemory.deviceMemory != VK_NULL_HANDLE) { - vkDestroyImage(g_vkDevice, mImage, g_vkAllocator); - } - } - - Image2D &operator=(Image2D &&other) { - std::swap(mImage, other.mImage); - std::swap(mFormat, other.mFormat); - std::swap(mAspects, other.mAspects); - std::swap(mLayout, other.mLayout); - std::swap(mWidth, other.mWidth); - std::swap(mHeight, other.mHeight); - std::swap(mMemory, other.mMemory); - return *this; - } - - Image2D(uint32_t width, uint32_t height, VkFormat format, - VkImageUsageFlags usage, - VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL, - VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT, - VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE, - uint32_t mipLevels = 1, uint32_t arrayLevels = 1, - VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED) { - VkImageCreateInfo imageInfo{}; - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent.width = width; - imageInfo.extent.height = height; - imageInfo.extent.depth = 1; - imageInfo.mipLevels = mipLevels; - imageInfo.arrayLayers = arrayLevels; - imageInfo.format = format; - imageInfo.tiling = tiling; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage = usage; - imageInfo.samples = samples; - imageInfo.sharingMode = sharingMode; - - mFormat = format; - - if (usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - mAspects |= VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - } else { - mAspects |= VK_IMAGE_ASPECT_COLOR_BIT; - } - - mLayout = initialLayout; - mWidth = width; - mHeight = height; - - Verify() << vkCreateImage(g_vkDevice, &imageInfo, nullptr, &mImage); - } - - static Image2D - Allocate(MemoryResource &pool, uint32_t width, uint32_t height, - VkFormat format, VkImageUsageFlags usage, - VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL, - VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT, - VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE, - uint32_t mipLevels = 1, uint32_t arrayLevels = 1, - VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED) { - - Image2D result(width, height, format, usage, tiling, samples, sharingMode, - mipLevels, arrayLevels, initialLayout); - - result.allocateAndBind(pool); - return result; - } - - static Image2D CreateFromExternal(VkImage image, VkFormat format, - VkImageAspectFlags aspects, - VkImageLayout layout, unsigned width, - unsigned height) { - Image2D result; + static ImageRef Create(VkImage image, VkFormat format, + VkImageAspectFlags aspects, VkImageLayout *layout, + unsigned width, unsigned height, unsigned depth) { + ImageRef result; result.mImage = image; result.mFormat = format; result.mAspects = aspects; result.mLayout = layout; result.mWidth = width; result.mHeight = height; + result.mDepth = depth; return result; } VkImage getHandle() const { return mImage; } - [[nodiscard]] VkImage release() { return std::exchange(mImage, nullptr); } VkMemoryRequirements getMemoryRequirements() const { VkMemoryRequirements requirements{}; @@ -660,17 +589,6 @@ public: return requirements; } - void allocateAndBind(MemoryResource &pool) { - auto memory = pool.allocate(getMemoryRequirements()); - bindMemory(memory); - } - - void bindMemory(DeviceMemoryRef memory) { - mMemory = memory; - Verify() << vkBindImageMemory(g_vkDevice, mImage, memory.deviceMemory, - memory.offset); - } - void readFromBuffer(VkCommandBuffer cmdBuffer, const Buffer &buffer, VkImageAspectFlags destAspect) { transitionLayout(cmdBuffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); @@ -749,13 +667,13 @@ public: } void transitionLayout(VkCommandBuffer cmdBuffer, VkImageLayout newLayout) { - if (mLayout == newLayout) { + if (*mLayout == newLayout) { return; } VkImageMemoryBarrier barrier{}; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.oldLayout = mLayout; + barrier.oldLayout = *mLayout; barrier.newLayout = newLayout; barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -798,7 +716,7 @@ public: } }; - auto [sourceStage, sourceAccess] = layoutToStageAccess(mLayout); + auto [sourceStage, sourceAccess] = layoutToStageAccess(*mLayout); auto [destinationStage, destinationAccess] = layoutToStageAccess(newLayout); barrier.srcAccessMask = sourceAccess; @@ -807,9 +725,122 @@ public: vkCmdPipelineBarrier(cmdBuffer, sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, &barrier); - mLayout = newLayout; + *mLayout = newLayout; + } +}; + +class Image2D { + VkImage mImage = VK_NULL_HANDLE; + VkFormat mFormat = {}; + VkImageAspectFlags mAspects = {}; + VkImageLayout mLayout = {}; + unsigned mWidth = 0; + unsigned mHeight = 0; + +public: + Image2D(const Image2D &) = delete; + + Image2D() = default; + Image2D(Image2D &&other) { *this = std::move(other); } + + ~Image2D() { + if (mImage != nullptr) { + vkDestroyImage(g_vkDevice, mImage, g_vkAllocator); + } } - // DeviceMemoryRef getMemory() const { return mMemory; } + Image2D &operator=(Image2D &&other) { + std::swap(mImage, other.mImage); + std::swap(mFormat, other.mFormat); + std::swap(mAspects, other.mAspects); + std::swap(mLayout, other.mLayout); + std::swap(mWidth, other.mWidth); + std::swap(mHeight, other.mHeight); + return *this; + } + + Image2D(uint32_t width, uint32_t height, VkFormat format, + VkImageUsageFlags usage, + VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL, + VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT, + VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE, + uint32_t mipLevels = 1, uint32_t arrayLevels = 1, + VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED) { + VkImageCreateInfo imageInfo{}; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.extent.width = width; + imageInfo.extent.height = height; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = mipLevels; + imageInfo.arrayLayers = arrayLevels; + imageInfo.format = format; + imageInfo.tiling = tiling; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.usage = usage; + imageInfo.samples = samples; + imageInfo.sharingMode = sharingMode; + + mFormat = format; + + if (usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + mAspects |= VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + } else { + mAspects |= VK_IMAGE_ASPECT_COLOR_BIT; + } + + mLayout = initialLayout; + mWidth = width; + mHeight = height; + + Verify() << vkCreateImage(g_vkDevice, &imageInfo, nullptr, &mImage); + } + + static Image2D + Allocate(MemoryResource &pool, uint32_t width, uint32_t height, + VkFormat format, VkImageUsageFlags usage, + VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL, + VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT, + VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE, + uint32_t mipLevels = 1, uint32_t arrayLevels = 1, + VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED) { + + Image2D result(width, height, format, usage, tiling, samples, sharingMode, + mipLevels, arrayLevels, initialLayout); + + result.allocateAndBind(pool); + return result; + } + + VkImage getHandle() const { return mImage; } + [[nodiscard]] VkImage release() { return std::exchange(mImage, nullptr); } + + VkMemoryRequirements getMemoryRequirements() const { + VkMemoryRequirements requirements{}; + vkGetImageMemoryRequirements(g_vkDevice, mImage, &requirements); + return requirements; + } + + void allocateAndBind(MemoryResource &pool) { + auto memory = pool.allocate(getMemoryRequirements()); + bindMemory(memory); + } + + void bindMemory(DeviceMemoryRef memory) { + Verify() << vkBindImageMemory(g_vkDevice, mImage, memory.deviceMemory, + memory.offset); + } + + friend ImageRef; }; + +inline ImageRef::ImageRef(Image2D &image) { + mImage = image.mImage; + mFormat = image.mFormat; + mAspects = image.mAspects; + mLayout = &image.mLayout; + mWidth = image.mWidth; + mHeight = image.mHeight; + mDepth = 1; +} } // namespace amdgpu::device::vk diff --git a/hw/amdgpu/device/src/device.cpp b/hw/amdgpu/device/src/device.cpp index 3f452e746..23e5faace 100644 --- a/hw/amdgpu/device/src/device.cpp +++ b/hw/amdgpu/device/src/device.cpp @@ -1978,7 +1978,7 @@ struct AreaCache { }; struct WriteBackImage { - vk::Image2D *image; + vk::ImageRef image; std::uint64_t address; std::uint32_t tileMode; std::uint32_t width; @@ -2047,7 +2047,7 @@ struct AreaCache { return result; } - vk::Image2D *getImage(std::uint64_t areaOffset, VkCommandBuffer cmdBuffer, + vk::ImageRef getImage(std::uint64_t areaOffset, VkCommandBuffer cmdBuffer, TileMode tileMode, std::uint32_t width, std::uint32_t height, std::uint32_t depth, std::uint32_t pitch, SurfaceFormat format, @@ -2068,8 +2068,10 @@ struct AreaCache { auto vkFormat = surfaceFormatToVkFormat(format, channelType); - auto image = vk::Image2D::Allocate(getDeviceLocalMemory(), width, height, - vkFormat, usage); + auto imageHandle = vk::Image2D::Allocate(getDeviceLocalMemory(), width, + height, vkFormat, usage); + + auto image = vk::ImageRef(imageHandle); if ((access & shader::AccessOp::Load) == shader::AccessOp::Load) { buffers.push_back(image.read( @@ -2078,11 +2080,11 @@ struct AreaCache { getBitWidthOfSurfaceFormat(format) / 8, pitch)); } - auto &result = images.emplace_front(std::move(image)); + images.emplace_front(std::move(imageHandle)); if ((access & shader::AccessOp::Store) == shader::AccessOp::Store) { writeBackImages.push_back({ - .image = &result, + .image = image, .address = writeBackAddress, .tileMode = tileMode, .width = width, @@ -2094,13 +2096,13 @@ struct AreaCache { }); } - return &result; + return image; } void writeImageToBuffers(VkCommandBuffer cmd) { for (auto wbImage : writeBackImages) { - auto buffer = wbImage.image->writeToBuffer(cmd, getHostVisibleMemory(), - wbImage.aspect); + auto buffer = wbImage.image.writeToBuffer(cmd, getHostVisibleMemory(), + wbImage.aspect); writeBackBuffers.push_back( {.bufferMemory = buffer.getData(), .address = wbImage.address, @@ -2246,23 +2248,6 @@ struct RenderState { return area.getBuffer(address - area.areaAddress, size, usage, access); } - vk::Image2D *getImage(std::uint64_t address, VkCommandBuffer cmdBuffer, - TileMode tileMode, std::uint32_t width, - std::uint32_t height, std::uint32_t depth, - std::uint32_t pitch, SurfaceFormat format, - TextureChannelType channelType, VkImageUsageFlags usage, - VkImageAspectFlags aspect, shader::AccessOp access, - std::uint64_t writeBackAddress) { - auto &area = getArea(address, pitch * height * depth * - getBitWidthOfSurfaceFormat(format) / 8); - - touchedAreas.insert(&area); - - return area.getImage(address - area.areaAddress, cmdBuffer, tileMode, width, - height, depth, pitch, format, channelType, usage, - aspect, access, writeBackAddress); - } - std::vector loadShader( VkCommandBuffer cmdBuffer, shader::Stage stage, std::uint64_t address, std::uint32_t *userSgprs, std::size_t userSgprsCount, int &bindingOffset, @@ -2382,10 +2367,12 @@ struct RenderState { bpp = 16; } - auto image = vk::Image2D::Allocate( + auto imageHandle = vk::Image2D::Allocate( getDeviceLocalMemory(), tbuffer->width + 1, tbuffer->height + 1, colorFormat, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + auto image = vk::ImageRef(imageHandle); + images.push_back(std::move(imageHandle)); buffers.push_back( image.read(cmdBuffer, getHostVisibleMemory(), @@ -2408,7 +2395,6 @@ struct RenderState { image.transitionLayout(cmdBuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - images.push_back(std::move(image)); break; } @@ -2563,11 +2549,13 @@ struct RenderState { surfaceFormatToVkFormat((SurfaceFormat)colorBuffer.format, TextureChannelType::kTextureChannelTypeSrgb); - auto colorImage = vk::Image2D::Allocate( + auto colorImageHandle = vk::Image2D::Allocate( getDeviceLocalMemory(), screenScissorW, screenScissorH, format, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + auto colorImage = vk::ImageRef(colorImageHandle); + colorImages.push_back(std::move(colorImageHandle)); buffers.push_back(colorImage.read( readCommandBuffer, getHostVisibleMemory(), @@ -2582,7 +2570,6 @@ struct RenderState { createImageView2D(colorImage.getHandle(), format, {}, imageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT)); - colorImages.push_back(std::move(colorImage)); framebufferAttachments.push_back(colorImageView); uint32_t attachmentIndex = attachments.size(); @@ -2604,13 +2591,14 @@ struct RenderState { }); } - auto depthImage = vk::Image2D::Allocate( + auto depthImageHandle = vk::Image2D::Allocate( getDeviceLocalMemory(), screenScissorW, screenScissorH, depthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | (depthClearEnable || zReadBase == 0 ? 0 : VK_IMAGE_USAGE_TRANSFER_DST_BIT)); + auto depthImage = vk::ImageRef(depthImageHandle); { if (!depthClearEnable && zReadBase) { @@ -2907,8 +2895,9 @@ struct RenderState { for (auto &colorImage : colorImages) { resultColorBuffers.push_back( - colorImage.writeToBuffer(writeCommandBuffer, getHostVisibleMemory(), - VK_IMAGE_ASPECT_COLOR_BIT)); + vk::ImageRef(colorImage) + .writeToBuffer(writeCommandBuffer, getHostVisibleMemory(), + VK_IMAGE_ASPECT_COLOR_BIT)); } vk::Buffer resultDepthBuffer; @@ -3475,11 +3464,13 @@ bool amdgpu::device::AmdgpuDevice::handleFlip( buffer.width, buffer.height, targetExtent.width, targetExtent.height); - auto bufferImage = vk::Image2D::Allocate( + auto bufferImageHandle = vk::Image2D::Allocate( getDeviceLocalMemory(), buffer.width, buffer.height, VK_FORMAT_R8G8B8A8_SRGB, // TODO VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + auto bufferImage = vk::ImageRef(bufferImageHandle); + auto tmpBuffer = bufferImage.read( cmd, getHostVisibleMemory(), g_hostMemory.getPointer(buffer.address), buffer.tilingMode == 1 ? kTileModeDisplay_2dThin @@ -3518,6 +3509,6 @@ bool amdgpu::device::AmdgpuDevice::handleFlip( VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); usedBuffers.push_back(tmpBuffer.release()); - usedImages.push_back(bufferImage.release()); + usedImages.push_back(bufferImageHandle.release()); return true; }