mirror of
https://github.com/RPCSX/rpcsx.git
synced 2025-03-04 00:27:40 +00:00
[amdgpu] Add ImageRef utility
This commit is contained in:
parent
31fd85ce1d
commit
21f9c9b8ec
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user