mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-11 13:36:24 +02:00
Vulkan: Add facility to auto-generate mipmap levels. Not yet used.
Intended for replacement textures and optional quality improvements later.
This commit is contained in:
1 parent
2ebae034a4
commit
bd40479224
6 files changed
+59
-22
No files matched your search
@@ -894,11 +894,10 @@ bool VulkanContext::CreateShaderModule(const std::vector<uint32_t> &spirv, VkSha
|
||||
}
|
||||
}
|
||||
|
||||
void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask,
|
||||
void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int numMipLevels, VkImageAspectFlags aspectMask,
|
||||
VkImageLayout oldImageLayout, VkImageLayout newImageLayout,
|
||||
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
|
||||
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask,
|
||||
int numMipLevels) {
|
||||
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) {
|
||||
VkImageMemoryBarrier image_memory_barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
image_memory_barrier.srcAccessMask = srcAccessMask;
|
||||
image_memory_barrier.dstAccessMask = dstAccessMask;
|
||||
@@ -906,7 +905,7 @@ void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, VkImageAspectFla
|
||||
image_memory_barrier.newLayout = newImageLayout;
|
||||
image_memory_barrier.image = image;
|
||||
image_memory_barrier.subresourceRange.aspectMask = aspectMask;
|
||||
image_memory_barrier.subresourceRange.baseMipLevel = 0;
|
||||
image_memory_barrier.subresourceRange.baseMipLevel = baseMip;
|
||||
image_memory_barrier.subresourceRange.levelCount = numMipLevels;
|
||||
image_memory_barrier.subresourceRange.layerCount = 1; // We never use more than one layer, and old Mali drivers have problems with VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS.
|
||||
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
|
||||
@@ -309,10 +309,10 @@ private:
|
||||
};
|
||||
|
||||
// Detailed control.
|
||||
void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask,
|
||||
void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int mipLevels, VkImageAspectFlags aspectMask,
|
||||
VkImageLayout oldImageLayout, VkImageLayout newImageLayout,
|
||||
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
|
||||
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, int mipLevels = VK_REMAINING_MIP_LEVELS);
|
||||
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask);
|
||||
|
||||
// GLSL compiler
|
||||
void init_glslang();
|
||||
|
||||
@@ -134,13 +134,13 @@ void VulkanTexture::Unlock(VkCommandBuffer cmd) {
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
// Since we're going to blit from the mappable image, set its layout to SOURCE_OPTIMAL
|
||||
TransitionImageLayout2(cmd, mappableImage,
|
||||
TransitionImageLayout2(cmd, mappableImage, 0, 1,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
|
||||
|
||||
TransitionImageLayout2(cmd, image,
|
||||
TransitionImageLayout2(cmd, image, 0, 1,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
@@ -174,7 +174,7 @@ void VulkanTexture::Unlock(VkCommandBuffer cmd) {
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
// Set the layout for the texture image from DESTINATION_OPTIMAL to SHADER_READ_ONLY
|
||||
TransitionImageLayout2(cmd, image,
|
||||
TransitionImageLayout2(cmd, image, 0, 1,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
@@ -268,7 +268,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips,
|
||||
if (initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && initialLayout != VK_IMAGE_LAYOUT_PREINITIALIZED) {
|
||||
switch (initialLayout) {
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
TransitionImageLayout2(cmd, image, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
TransitionImageLayout2(cmd, image, 0, numMips, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
@@ -356,8 +356,40 @@ void VulkanTexture::UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mi
|
||||
vkCmdCopyBufferToImage(cmd, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region);
|
||||
}
|
||||
|
||||
void VulkanTexture::GenerateMip(VkCommandBuffer cmd, int mip) {
|
||||
_assert_msg_(G3D, mip != 0, "Cannot generate the first level");
|
||||
_assert_msg_(G3D, mip < numMips_, "Cannot generate mipmaps past the maximum created (%d vs %d)", mip, numMips_);
|
||||
VkImageBlit blit{};
|
||||
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
blit.srcSubresource.layerCount = 1;
|
||||
blit.srcSubresource.mipLevel = mip - 1;
|
||||
blit.srcOffsets[1].x = tex_width >> (mip - 1);
|
||||
blit.srcOffsets[1].y = tex_height >> (mip - 1);
|
||||
blit.srcOffsets[1].z = 1;
|
||||
|
||||
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
blit.dstSubresource.layerCount = 1;
|
||||
blit.dstSubresource.mipLevel = mip;
|
||||
blit.dstOffsets[1].x = tex_width >> mip;
|
||||
blit.dstOffsets[1].y = tex_height >> mip;
|
||||
blit.dstOffsets[1].z = 1;
|
||||
|
||||
TransitionImageLayout2(cmd, image, mip - 1, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
|
||||
|
||||
// Low-quality mipmap generation, but works okay.
|
||||
vkCmdBlitImage(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR);
|
||||
|
||||
TransitionImageLayout2(cmd, image, mip - 1, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
}
|
||||
|
||||
void VulkanTexture::EndCreate(VkCommandBuffer cmd, bool vertexTexture) {
|
||||
TransitionImageLayout2(cmd, image,
|
||||
TransitionImageLayout2(cmd, image, 0, 1,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, vertexTexture ? VK_PIPELINE_STAGE_VERTEX_SHADER_BIT : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
|
||||
@@ -33,6 +33,7 @@ public:
|
||||
// When using UploadMip, initialLayout should be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL.
|
||||
bool CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, const VkComponentMapping *mapping = nullptr);
|
||||
void UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength); // rowLength is in pixels
|
||||
void GenerateMip(VkCommandBuffer cmd, int mip);
|
||||
void EndCreate(VkCommandBuffer cmd, bool vertexTexture = false);
|
||||
|
||||
void Destroy();
|
||||
|
||||
@@ -223,6 +223,12 @@ void VulkanQueueRunner::InitRenderpasses() {
|
||||
|
||||
void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, const std::vector<VKRStep *> &steps) {
|
||||
// Optimizes renderpasses, then sequences them.
|
||||
// Planned optimizations:
|
||||
// * Push down empty "Clear/Store" renderpasses, and merge them with the first "Load/Store" to the same framebuffer.
|
||||
// (These happen in Wipeout)
|
||||
// * Create copies of render target that are rendered to multiple times and textured from in sequence, and push those render passes
|
||||
// as early as possible in the frame (Wipeout billboards).
|
||||
|
||||
for (int i = 0; i < steps.size(); i++) {
|
||||
const VKRStep &step = *steps[i];
|
||||
switch (step.stepType) {
|
||||
@@ -556,10 +562,10 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step
|
||||
}
|
||||
|
||||
// Due to a known bug in the Mali driver, pass the level count explicitly.
|
||||
TransitionImageLayout2(cmd, fb->color.image, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
TransitionImageLayout2(cmd, fb->color.image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
fb->color.layout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
srcStage, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
srcAccessMask, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, 1);
|
||||
srcAccessMask, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
|
||||
fb->color.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
if (fb->depth.layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
||||
@@ -585,11 +591,10 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step
|
||||
}
|
||||
|
||||
// Due to a known bug in the Mali driver, pass the level count explicitly (last param).
|
||||
TransitionImageLayout2(cmd, fb->depth.image, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
|
||||
TransitionImageLayout2(cmd, fb->depth.image, 0, 1, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
|
||||
fb->depth.layout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
srcStage, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
srcAccessMask, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
|
||||
1);
|
||||
srcAccessMask, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT);
|
||||
fb->depth.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
@@ -872,7 +877,7 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd
|
||||
if (step.readback.src == nullptr) {
|
||||
// We only take screenshots after the main render pass (anything else would be stupid) so we need to transition out of PRESENT,
|
||||
// and then back into it.
|
||||
TransitionImageLayout2(cmd, backbufferImage_, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
TransitionImageLayout2(cmd, backbufferImage_, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1,
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, VK_ACCESS_TRANSFER_READ_BIT);
|
||||
@@ -909,7 +914,7 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd
|
||||
if (step.readback.src == nullptr) {
|
||||
// We only take screenshots after the main render pass (anything else would be stupid) so we need to transition out of PRESENT,
|
||||
// and then back into it.
|
||||
TransitionImageLayout2(cmd, backbufferImage_, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
TransitionImageLayout2(cmd, backbufferImage_, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
VK_ACCESS_TRANSFER_READ_BIT, 0);
|
||||
@@ -942,7 +947,7 @@ void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffe
|
||||
vkCmdCopyImageToBuffer(cmd, step.readback_image.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, readbackBuffer_, 1, ®ion);
|
||||
|
||||
// Now transfer it back to a texture.
|
||||
TransitionImageLayout2(cmd, step.readback_image.image,
|
||||
TransitionImageLayout2(cmd, step.readback_image.image, 0, 1,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
|
||||
@@ -84,7 +84,7 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int
|
||||
break;
|
||||
}
|
||||
|
||||
TransitionImageLayout2(cmd, img.image, aspects,
|
||||
TransitionImageLayout2(cmd, img.image, 0, 1, aspects,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, initialLayout,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, dstStage,
|
||||
0, dstAccessMask);
|
||||
@@ -166,7 +166,7 @@ void VulkanRenderManager::CreateBackbuffers() {
|
||||
|
||||
// Pre-set them to PRESENT_SRC_KHR, as the first thing we do after acquiring
|
||||
// in image to render to will be to transition them away from that.
|
||||
TransitionImageLayout2(cmdInit, sc_buffer.image,
|
||||
TransitionImageLayout2(cmdInit, sc_buffer.image, 0, 1,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
|
||||
@@ -573,7 +573,7 @@ bool VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) {
|
||||
if (res != VK_SUCCESS)
|
||||
return false;
|
||||
|
||||
TransitionImageLayout2(cmd, depth_.image,
|
||||
TransitionImageLayout2(cmd, depth_.image, 0, 1,
|
||||
aspectMask,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
|
||||
|
||||
Reference in new issue
Block a user