[amdgpu] Add ImageRef utility

This commit is contained in:
DH 2023-07-19 15:02:57 +03:00
parent 31fd85ce1d
commit 21f9c9b8ec
2 changed files with 156 additions and 134 deletions

View File

@ -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

View File

@ -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<std::uint32_t> 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;
}