IBL now works on Vulkan!
* Image transitions are handled more correctly, reducing errors * Cubemaps are now transitioned properly when using the CopyTexture command * Cubemap image views are created correctly
This commit is contained in:
parent
dba0541376
commit
5546c88cba
3 changed files with 88 additions and 47 deletions
|
@ -98,7 +98,15 @@ private:
|
||||||
|
|
||||||
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
|
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
|
||||||
void transitionImageLayout(VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageSubresourceRange range, VkImageLayout oldLayout, VkImageLayout newLayout);
|
void transitionImageLayout(VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageSubresourceRange range, VkImageLayout oldLayout, VkImageLayout newLayout);
|
||||||
void inlineTransitionImageLayout(VkCommandBuffer command_buffer, VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageSubresourceRange range, VkImageLayout oldLayout, VkImageLayout newLayout);
|
void inlineTransitionImageLayout(VkCommandBuffer command_buffer,
|
||||||
|
VkImage image,
|
||||||
|
VkFormat format,
|
||||||
|
VkImageAspectFlags aspect,
|
||||||
|
VkImageSubresourceRange range,
|
||||||
|
VkImageLayout oldLayout,
|
||||||
|
VkImageLayout newLayout,
|
||||||
|
VkPipelineStageFlags src_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||||
|
VkPipelineStageFlags dst_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
|
||||||
VkShaderModule createShaderModule(const uint32_t* code, const int length);
|
VkShaderModule createShaderModule(const uint32_t* code, const int length);
|
||||||
VkCommandBuffer beginSingleTimeCommands();
|
VkCommandBuffer beginSingleTimeCommands();
|
||||||
void endSingleTimeCommands(VkCommandBuffer commandBuffer);
|
void endSingleTimeCommands(VkCommandBuffer commandBuffer);
|
||||||
|
|
|
@ -415,11 +415,9 @@ GFXTexture* GFXVulkan::create_texture(const GFXTextureCreateInfo& info) {
|
||||||
range.baseMipLevel = 0;
|
range.baseMipLevel = 0;
|
||||||
range.levelCount = info.mip_count;
|
range.levelCount = info.mip_count;
|
||||||
range.baseArrayLayer = 0;
|
range.baseArrayLayer = 0;
|
||||||
range.layerCount = info.array_length;
|
range.layerCount = array_length;
|
||||||
|
range.aspectMask = imageAspect;
|
||||||
if(info.type == GFXTextureType::Cubemap || info.type == GFXTextureType::CubemapArray)
|
|
||||||
range.layerCount *= 6;
|
|
||||||
|
|
||||||
texture->range = range;
|
texture->range = range;
|
||||||
|
|
||||||
transitionImageLayout(texture->handle, imageFormat, imageAspect, range, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
transitionImageLayout(texture->handle, imageFormat, imageAspect, range, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
@ -445,7 +443,6 @@ GFXTexture* GFXVulkan::create_texture(const GFXTextureCreateInfo& info) {
|
||||||
}
|
}
|
||||||
viewInfo.format = imageFormat;
|
viewInfo.format = imageFormat;
|
||||||
viewInfo.subresourceRange = range;
|
viewInfo.subresourceRange = range;
|
||||||
viewInfo.subresourceRange.aspectMask = imageAspect;
|
|
||||||
|
|
||||||
vkCreateImageView(device, &viewInfo, nullptr, &texture->view);
|
vkCreateImageView(device, &viewInfo, nullptr, &texture->view);
|
||||||
|
|
||||||
|
@ -1240,27 +1237,56 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) {
|
||||||
{
|
{
|
||||||
GFXVulkanTexture* src = (GFXVulkanTexture*)command.data.copy_texture.src;
|
GFXVulkanTexture* src = (GFXVulkanTexture*)command.data.copy_texture.src;
|
||||||
GFXVulkanTexture* dst = (GFXVulkanTexture*)command.data.copy_texture.dst;
|
GFXVulkanTexture* dst = (GFXVulkanTexture*)command.data.copy_texture.dst;
|
||||||
|
|
||||||
inlineTransitionImageLayout(cmd, src->handle, src->format, src->aspect, src->range, src->layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
|
||||||
inlineTransitionImageLayout(cmd, dst->handle, dst->format, dst->aspect, dst->range, dst->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
|
||||||
|
|
||||||
const int slice_offset = command.data.copy_texture.to_slice + command.data.copy_texture.to_layer * 6;
|
const int slice_offset = command.data.copy_texture.to_slice + command.data.copy_texture.to_layer * 6;
|
||||||
|
|
||||||
|
VkImageSubresourceRange dstRange = {};
|
||||||
|
dstRange.layerCount = 1;
|
||||||
|
dstRange.baseArrayLayer = slice_offset;
|
||||||
|
dstRange.baseMipLevel = command.data.copy_texture.to_level;
|
||||||
|
dstRange.levelCount = 1;
|
||||||
|
dstRange.aspectMask = dst->aspect;
|
||||||
|
|
||||||
|
inlineTransitionImageLayout(cmd, src->handle, src->format, src->aspect, src->range, src->layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||||
|
inlineTransitionImageLayout(cmd, dst->handle, dst->format, dst->aspect, dstRange, dst->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
|
|
||||||
VkImageCopy region = {};
|
VkImageCopy region = {};
|
||||||
region.extent = {static_cast<uint32_t>(command.data.copy_texture.width), static_cast<uint32_t>(command.data.copy_texture.height), 1};
|
region.extent.width = static_cast<uint32_t>(command.data.copy_texture.width);
|
||||||
region.dstSubresource.baseArrayLayer = slice_offset;
|
region.extent.height = static_cast<uint32_t>(command.data.copy_texture.height);
|
||||||
region.dstSubresource.mipLevel = command.data.copy_texture.to_level;
|
region.extent.depth = 1.0f;
|
||||||
region.srcSubresource.aspectMask = src->aspect;
|
|
||||||
region.dstSubresource.aspectMask = dst->aspect;
|
|
||||||
region.srcSubresource.layerCount = 1;
|
region.srcSubresource.layerCount = 1;
|
||||||
region.dstSubresource.layerCount = 1;
|
region.srcSubresource.aspectMask = src->aspect;
|
||||||
|
|
||||||
|
region.dstSubresource.baseArrayLayer = dstRange.baseArrayLayer;
|
||||||
|
region.dstSubresource.mipLevel = dstRange.baseMipLevel;
|
||||||
|
region.dstSubresource.aspectMask = dstRange.aspectMask;
|
||||||
|
region.dstSubresource.layerCount = dstRange.layerCount;
|
||||||
|
|
||||||
vkCmdCopyImage(cmd, src->handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
vkCmdCopyImage(cmd, src->handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||||
|
|
||||||
inlineTransitionImageLayout(cmd, src->handle, src->format, src->aspect, src->range, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, src->layout);
|
inlineTransitionImageLayout(cmd, src->handle, src->format, src->aspect, src->range, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, src->layout);
|
||||||
inlineTransitionImageLayout(cmd, dst->handle, dst->format, dst->aspect, dst->range, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst->layout);
|
inlineTransitionImageLayout(cmd, dst->handle, dst->format, dst->aspect, dstRange, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst->layout);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case GFXCommandType::SetViewport:
|
||||||
|
{
|
||||||
|
VkViewport viewport = {};
|
||||||
|
viewport.x = command.data.set_viewport.viewport.x;
|
||||||
|
viewport.y = command.data.set_viewport.viewport.height - command.data.set_viewport.viewport.y;
|
||||||
|
viewport.width = command.data.set_viewport.viewport.width;
|
||||||
|
viewport.height = -command.data.set_viewport.viewport.height;
|
||||||
|
viewport.maxDepth = 1.0f;
|
||||||
|
|
||||||
|
vkCmdSetViewport(cmd, 0, 1, &viewport);
|
||||||
|
|
||||||
|
VkRect2D scissor = {};
|
||||||
|
scissor.extent.width = command.data.set_viewport.viewport.width;
|
||||||
|
scissor.extent.height = command.data.set_viewport.viewport.height;
|
||||||
|
|
||||||
|
vkCmdSetScissor(cmd, 0, 1, &scissor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case GFXCommandType::EndRenderPass:
|
case GFXCommandType::EndRenderPass:
|
||||||
{
|
{
|
||||||
if(currentRenderPass != nullptr) {
|
if(currentRenderPass != nullptr) {
|
||||||
|
@ -1850,8 +1876,10 @@ void GFXVulkan::transitionImageLayout(VkImage image, VkFormat format, VkImageAsp
|
||||||
endSingleTimeCommands(commandBuffer);
|
endSingleTimeCommands(commandBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXVulkan::inlineTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageSubresourceRange range, VkImageLayout oldLayout, VkImageLayout newLayout) {
|
void GFXVulkan::inlineTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageSubresourceRange range, VkImageLayout oldLayout, VkImageLayout newLayout,
|
||||||
VkImageMemoryBarrier barrier{};
|
VkPipelineStageFlags src_stage_mask,
|
||||||
|
VkPipelineStageFlags dst_stage_mask) {
|
||||||
|
VkImageMemoryBarrier barrier = {};
|
||||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
barrier.oldLayout = oldLayout;
|
barrier.oldLayout = oldLayout;
|
||||||
barrier.newLayout = newLayout;
|
barrier.newLayout = newLayout;
|
||||||
|
@ -1861,34 +1889,31 @@ void GFXVulkan::inlineTransitionImageLayout(VkCommandBuffer commandBuffer, VkIma
|
||||||
barrier.subresourceRange = range;
|
barrier.subresourceRange = range;
|
||||||
barrier.subresourceRange.aspectMask = aspect;
|
barrier.subresourceRange.aspectMask = aspect;
|
||||||
|
|
||||||
VkPipelineStageFlags sourceStage;
|
switch(oldLayout) {
|
||||||
VkPipelineStageFlags destinationStage;
|
case VK_IMAGE_LAYOUT_UNDEFINED:
|
||||||
|
barrier.srcAccessMask = 0;
|
||||||
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
break;
|
||||||
barrier.srcAccessMask = 0;
|
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
break;
|
||||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
default:
|
||||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
break;
|
||||||
}
|
}
|
||||||
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
|
||||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
||||||
|
|
||||||
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
switch(newLayout) {
|
||||||
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||||
}
|
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
else {
|
break;
|
||||||
barrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||||
barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
break;
|
||||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
default:
|
||||||
destinationStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
vkCmdPipelineBarrier(
|
vkCmdPipelineBarrier(
|
||||||
commandBuffer,
|
commandBuffer,
|
||||||
sourceStage, destinationStage,
|
src_stage_mask, dst_stage_mask,
|
||||||
0,
|
0,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
|
|
|
@ -162,7 +162,7 @@ void SceneCapture::render(GFXCommandBuffer* command_buffer, Scene* scene) {
|
||||||
if(last_probe > max_environment_probes)
|
if(last_probe > max_environment_probes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(scene->environment_dirty[last_probe]) {
|
if(scene->environment_dirty[last_probe]) {
|
||||||
std::map<Material*, int> material_indices;
|
std::map<Material*, int> material_indices;
|
||||||
int numMaterialsInBuffer = 0;
|
int numMaterialsInBuffer = 0;
|
||||||
|
|
||||||
|
@ -342,7 +342,13 @@ void SceneCapture::render(GFXCommandBuffer* command_buffer, Scene* scene) {
|
||||||
command_buffer->draw_indexed(cubeMesh->num_indices, 0, 0, 0);
|
command_buffer->draw_indexed(cubeMesh->num_indices, 0, 0, 0);
|
||||||
|
|
||||||
command_buffer->end_render_pass();
|
command_buffer->end_render_pass();
|
||||||
command_buffer->copy_texture(irradianceOffscreenTexture, irradiance_cubemap_resolution, irradiance_cubemap_resolution, scene->irradianceCubeArray, face, last_probe, 0);
|
command_buffer->copy_texture(irradianceOffscreenTexture,
|
||||||
|
irradiance_cubemap_resolution,
|
||||||
|
irradiance_cubemap_resolution,
|
||||||
|
scene->irradianceCubeArray,
|
||||||
|
face, // slice
|
||||||
|
last_probe, // layer
|
||||||
|
0); // level
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int face = 0; face < 6; face++)
|
for (int face = 0; face < 6; face++)
|
||||||
|
@ -379,7 +385,9 @@ void SceneCapture::render(GFXCommandBuffer* command_buffer, Scene* scene) {
|
||||||
command_buffer->draw_indexed(cubeMesh->num_indices, 0, 0, 0);
|
command_buffer->draw_indexed(cubeMesh->num_indices, 0, 0, 0);
|
||||||
|
|
||||||
command_buffer->end_render_pass();
|
command_buffer->end_render_pass();
|
||||||
command_buffer->copy_texture(prefilteredOffscreenTexture, info.render_area.extent.width, info.render_area.extent.height, scene->prefilteredCubeArray, face, last_probe, mip);
|
command_buffer->copy_texture(prefilteredOffscreenTexture,
|
||||||
|
resolution, resolution,
|
||||||
|
scene->prefilteredCubeArray, face, last_probe, mip);
|
||||||
};
|
};
|
||||||
|
|
||||||
for(int mip = 0; mip < mipLevels; mip++) {
|
for(int mip = 0; mip < mipLevels; mip++) {
|
||||||
|
|
Reference in a new issue