Skip to content

Commit

Permalink
Vulkan deferred renderer fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
ksuprynowicz committed Jan 5, 2025
1 parent 585c582 commit 352073e
Show file tree
Hide file tree
Showing 17 changed files with 224 additions and 47 deletions.
9 changes: 9 additions & 0 deletions android/libraries/oculus/src/main/assets/shaders/present.vert
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@ layout(location = 0) out vec4 vTexCoordLR;

void main(void) {
const float depth = 0.0;
#ifdef VULKAN
const vec4 UNIT_QUAD[4] = vec4[4](
vec4(-1.0, 1.0, depth, 1.0),
vec4(1.0, 1.0, depth, 1.0),
vec4(-1.0, -1.0, depth, 1.0),
vec4(1.0, -1.0, depth, 1.0)
);
#else
const vec4 UNIT_QUAD[4] = vec4[4](
vec4(-1.0, -1.0, depth, 1.0),
vec4(1.0, -1.0, depth, 1.0),
vec4(-1.0, 1.0, depth, 1.0),
vec4(1.0, 1.0, depth, 1.0)
);
#endif
vec4 pos = UNIT_QUAD[gl_VertexID];
gl_Position = pos;
vTexCoordLR.xy = pos.xy;
Expand Down
143 changes: 111 additions & 32 deletions libraries/gpu-vk/src/gpu/vk/VKBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,9 @@ void VKBackend::executeFrame(const FramePointer& frame) {
if (batch.getName() == "SurfaceGeometryPass::run") {
printf("SurfaceGeometryPass");
}
if (batch.getName() == "BlurGaussian::run") {
/*if (batch.getName() == "BlurGaussian::run") {
continue;
}
}*/
cmdBeginLabel(commandBuffer, "batch:" + batch.getName(), glm::vec4{ 1, 1, 0, 1 });
const auto& commands = batch.getCommands();
const auto& offsets = batch.getCommandOffsets();
Expand Down Expand Up @@ -363,7 +363,9 @@ void VKBackend::executeFrame(const FramePointer& frame) {
if (batch.getName() == "Resample::run") {
_outputTexture = syncGPUObject(*_cache.pipelineState.framebuffer);
}

if (batch.getName() == "CompositeHUD") {
_outputTexture = syncGPUObject(*_cache.pipelineState.framebuffer);
}
if (renderpassActive) {
cmdEndLabel(commandBuffer);
renderpassActive = false;
Expand Down Expand Up @@ -1071,10 +1073,21 @@ void VKBackend::resetQueryStage() {
}

void VKBackend::updateRenderPass() {
// If framebuffer has changed, it means that render pass changed. _currentRenderPass is set to nullptr in such case.
if (_hasFramebufferChanged) {
Q_ASSERT(_currentVkRenderPass == nullptr);
// Current renderpass has ended and vkCmdEndRenderPass was already called so we cat set proper layouts here
// and avoid generating render pass twice.
if (_currentFramebuffer) {
updateAttachmentLayoutsAfterRenderPass();
}
transitionAttachmentImageLayouts(*_cache.pipelineState.framebuffer);
}
// Retrieve from cache or create render pass.
auto renderPass = _cache.pipelineState.getRenderPass(_context);
auto framebuffer = syncGPUObject(*_cache.pipelineState.framebuffer);

// Current render pass is already up to date
// Current render pass is already up to date.
// VKTODO: check if framebuffer has changed and if so update render pass too
if (_currentVkRenderPass == renderPass && _currentVkFramebuffer == framebuffer->vkFramebuffer) {
return;
Expand All @@ -1084,12 +1097,19 @@ void VKBackend::updateRenderPass() {
if (_currentVkRenderPass) {
vkCmdEndRenderPass(_currentCommandBuffer);
updateAttachmentLayoutsAfterRenderPass();
transitionAttachmentImageLayouts(*_cache.pipelineState.framebuffer);
}
// Input image layouts shouldn't affect render pass and always need to be done between
transitionInputImageLayouts();

// Render pass needs to be retrieved twice, since `updateAttachmentLayoutsAfterRenderPass` and `transitionAttachmentImageLayouts`
// can be called only once we know that renderpass ended and may change attachment image layouts and thus change render pass again.
renderPass = _cache.pipelineState.getRenderPass(_context);

_currentVkRenderPass = renderPass;
_currentFramebuffer = _cache.pipelineState.framebuffer;
_currentVkFramebuffer = framebuffer->vkFramebuffer;
_hasFramebufferChanged = false;

auto renderPassBeginInfo = vks::initializers::renderPassBeginInfo();
renderPassBeginInfo.renderPass = renderPass;
Expand Down Expand Up @@ -1370,6 +1390,9 @@ void VKBackend::renderPassDraw(const Batch& batch) {
offset++;
}
resetRenderPass();
if (_currentVkRenderPass) {
updateAttachmentLayoutsAfterRenderPass();
}
_currentVkRenderPass = VK_NULL_HANDLE;
_currentFramebuffer = nullptr;
// VKTODO: which other stages should be reset here?
Expand Down Expand Up @@ -1855,6 +1878,10 @@ void VKBackend::FrameData::addGlUniform(size_t size, const void* data, size_t co

VKBackend::FrameData::FrameData(VKBackend *backend) : _backend(backend) {
createDescriptorPool();
_cameraCorrectionBuffer.edit<CameraCorrection>() = CameraCorrection();
_cameraCorrectionBuffer._buffer->flush();
_cameraCorrectionBufferIdentity.edit<CameraCorrection>() = CameraCorrection();
_cameraCorrectionBufferIdentity._buffer->flush();
}

VKBackend::FrameData::~FrameData() {
Expand Down Expand Up @@ -1964,20 +1991,51 @@ void VKBackend::transitionInputImageLayouts() {
mipSubRange);
attachmentTexture->_vkImageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
} else if (attachmentTexture->_vkImageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
VkImageSubresourceRange mipSubRange = {};
mipSubRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
mipSubRange.baseMipLevel = 0;
mipSubRange.levelCount = 1;
mipSubRange.layerCount = 1;
vks::tools::insertImageMemoryBarrier(_currentCommandBuffer, attachmentTexture->_vkImage,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, // VKTODO
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, // VKTODO
mipSubRange);
attachmentTexture->_vkImageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
// Sometimes texture is used both as an input and as a depth stencil framebuffer attachment, we need to check for this
bool isAttachment = false;
auto &framebuffer = _cache.pipelineState.framebuffer;
if (framebuffer) {
auto depthStencilBuffer = _cache.pipelineState.framebuffer->getDepthStencilBuffer();
if (depthStencilBuffer) {
auto depthStencilGpuObject = Backend::getGPUObject<VKTexture>(*depthStencilBuffer);
if (depthStencilGpuObject) {
if (depthStencilGpuObject->_vkImage == attachmentTexture->_vkImage) {
isAttachment = true;
}
}
}
}
if (isAttachment) {
VkImageSubresourceRange mipSubRange = {};
mipSubRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
mipSubRange.baseMipLevel = 0;
mipSubRange.levelCount = 1;
mipSubRange.layerCount = 1;
vks::tools::insertImageMemoryBarrier(_currentCommandBuffer, attachmentTexture->_vkImage,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_GENERAL, // VKTODO: is here a better alyout for this use case?
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, // VKTODO
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, // VKTODO
mipSubRange);
attachmentTexture->_vkImageLayout = VK_IMAGE_LAYOUT_GENERAL;
} else {
VkImageSubresourceRange mipSubRange = {};
mipSubRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
mipSubRange.baseMipLevel = 0;
mipSubRange.levelCount = 1;
mipSubRange.layerCount = 1;
vks::tools::insertImageMemoryBarrier(_currentCommandBuffer, attachmentTexture->_vkImage,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, // VKTODO
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, // VKTODO
mipSubRange);
attachmentTexture->_vkImageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
};

}
Expand All @@ -1994,12 +2052,13 @@ void VKBackend::transitionAttachmentImageLayouts(gpu::Framebuffer &framebuffer)
continue;
}
auto attachmentTexture = dynamic_cast<VKAttachmentTexture*>(gpuObject);
if (attachmentTexture) {
if (!attachmentTexture) {
continue;
}

if (attachmentTexture->_vkImageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
if (attachmentTexture->_gpuObject.isDepthStencilRenderTarget()) {
// VKTODO: Check if the same depth render target is used as one of the inputs, if so then don't update it here
VkImageSubresourceRange mipSubRange = {};
mipSubRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
mipSubRange.baseMipLevel = 0;
Expand Down Expand Up @@ -2039,11 +2098,11 @@ void VKBackend::transitionAttachmentImageLayouts(gpu::Framebuffer &framebuffer)
return;
}
auto attachmentTexture = dynamic_cast<VKAttachmentTexture*>(gpuObject);
if (attachmentTexture) {
if (!attachmentTexture) {
return;
}
if (attachmentTexture->_vkImageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
Q_ASSERT(attachmentTexture->_gpuObject.isDepthStencilRenderTarget());
Q_ASSERT(attachmentTexture->_gpuObject.isDepthStencilRenderTarget());
VkImageSubresourceRange mipSubRange = {};
mipSubRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
mipSubRange.baseMipLevel = 0;
Expand Down Expand Up @@ -2259,6 +2318,14 @@ void VKBackend::updateTransform(const gpu::Batch& batch) {
vkCmdBindVertexBuffers(_currentCommandBuffer, gpu::Stream::DRAW_CALL_INFO, 1, &_currentFrame->_drawCallInfoBuffer->buffer, &vkOffset);
//glBindVertexBuffer(gpu::Stream::DRAW_CALL_INFO, _transform._drawCallInfoBuffer, (GLintptr)_transform._drawCallInfoOffsets[batch._currentNamedCall], 2 * sizeof(GLushort));
}
_resource._buffers;

// VKTODO: camera correction
auto* cameraCorrectionObject = syncGPUObject(*_currentFrame->_cameraCorrectionBuffer._buffer);
Q_ASSERT(cameraCorrectionObject);
_uniform._buffers[gpu::slot::buffer::CameraCorrection].buffer = _currentFrame->_cameraCorrectionBuffer._buffer.get();
_uniform._buffers[gpu::slot::buffer::CameraCorrection].offset = _currentFrame->_cameraCorrectionBuffer._offset;
_uniform._buffers[gpu::slot::buffer::CameraCorrection].size = _currentFrame->_cameraCorrectionBuffer._size;
}

void VKBackend::updatePipeline() {
Expand Down Expand Up @@ -2539,9 +2606,9 @@ void VKBackend::do_multiDrawIndexedIndirect(const Batch& batch, size_t paramOffs
void VKBackend::do_setFramebuffer(const Batch& batch, size_t paramOffset) {
auto framebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint);
_cache.pipelineState.setFramebuffer(framebuffer);
if (framebuffer) {
transitionAttachmentImageLayouts(*framebuffer);
}

resetRenderPass();
_hasFramebufferChanged = true;
// VKTODO?
/*auto framebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint);
if (_output._framebuffer != framebuffer) {
Expand All @@ -2561,6 +2628,8 @@ void VKBackend::do_setFramebufferSwapChain(const Batch& batch, size_t paramOffse
auto index = batch._params[paramOffset + 1]._uint;
const auto& framebuffer = swapChain->get(index);
_cache.pipelineState.setFramebuffer(framebuffer);
resetRenderPass();
_hasFramebufferChanged = true;
}
}

Expand Down Expand Up @@ -2623,22 +2692,32 @@ void VKBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
} else {
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
}
if ((masks & Framebuffer::BUFFER_DEPTH) && (masks & Framebuffer::BUFFER_STENCIL)) {
attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
} else {
attachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
// Texture state needs to be updated
auto depthStencil = framebuffer->getDepthStencilBuffer();
Q_ASSERT(depthStencil);
auto gpuDepthStencil = syncGPUObject(*depthStencil);
Q_ASSERT(gpuDepthStencil);
auto depthStencilAttachmentTexture = dynamic_cast<VKAttachmentTexture*>(gpuDepthStencil);
Q_ASSERT(depthStencilAttachmentTexture);
depthStencilAttachmentTexture->_vkImageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

if ((masks & Framebuffer::BUFFER_DEPTH) && (masks & Framebuffer::BUFFER_STENCIL)) {
attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthStencilAttachmentTexture->_vkImageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
} else {
if (depthStencilAttachmentTexture->_vkImageLayout == VK_IMAGE_LAYOUT_GENERAL) {
attachment.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
attachment.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
depthReference.layout = VK_IMAGE_LAYOUT_GENERAL;
} else {
attachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthStencilAttachmentTexture->_vkImageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
}
depthReference.attachment = (uint32_t)(attachments.size());
depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
} else {
clearValues.push_back(VkClearValue{.color = VkClearColorValue{.float32 = { color.x, color.y, color.z, color.w }}});
if (masks & Framebuffer::BUFFER_COLORS) {
Expand Down
8 changes: 6 additions & 2 deletions libraries/gpu-vk/src/gpu/vk/VKBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ class VKBackend : public Backend, public std::enable_shared_from_this<VKBackend>
VkRenderPass _currentVkRenderPass{ VK_NULL_HANDLE };
gpu::FramebufferReference _currentFramebuffer{ nullptr }; // Framebuffer used in currently happening render pass
VkFramebuffer _currentVkFramebuffer{ VK_NULL_HANDLE }; // Framebuffer used in currently happening render pass
bool _hasFramebufferChanged {false}; // Set to true when batch calls setFramebuffer command. Used to end render pass and update input image layouts.
// Checks if renderpass change is needed and changes it if required
void updateRenderPass();
void updateAttachmentLayoutsAfterRenderPass();
Expand All @@ -287,6 +288,9 @@ class VKBackend : public Backend, public std::enable_shared_from_this<VKBackend>
std::unordered_map<int, size_t> _glUniformOffsetMap;
size_t _glUniformBufferPosition {0}; // Position where data from next glUniform... call is placed

BufferView _cameraCorrectionBuffer { gpu::BufferView(std::make_shared<gpu::Buffer>(gpu::Buffer::UniformBuffer, sizeof(CameraCorrection), nullptr )) };
BufferView _cameraCorrectionBufferIdentity { gpu::BufferView(std::make_shared<gpu::Buffer>(gpu::Buffer::UniformBuffer, sizeof(CameraCorrection), nullptr )) };

void addGlUniform(size_t size, const void *data, size_t commandIndex);

FrameData(VKBackend *backend);
Expand Down Expand Up @@ -452,8 +456,8 @@ class VKBackend : public Backend, public std::enable_shared_from_this<VKBackend>
// VKTODO: quick hack
VKFramebuffer *_outputTexture{ nullptr };
protected:
void transitionInputImageLayouts();
void transitionAttachmentImageLayouts(gpu::Framebuffer &framebuffer);
void transitionInputImageLayouts(); // This can be called only form `updateRenderPass`
void transitionAttachmentImageLayouts(gpu::Framebuffer &framebuffer); // This can be called only form `updateRenderPass`

// These are filled by syncGPUObject() calls, and are needed to track backend objects so that they can be destroyed before
// destroying backend.
Expand Down
15 changes: 12 additions & 3 deletions libraries/gpu-vk/src/gpu/vk/VKPipelineCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,16 +229,25 @@ VkRenderPass Cache::Pipeline::getRenderPass(const vks::Context& context) {
if (isDepthStencilFormat(formatAndLayout.first)) {
if (!attachmentTexture || attachmentTexture->getVkImageLayout() == VK_IMAGE_LAYOUT_UNDEFINED) {
attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
} else {
attachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
if (attachmentTexture->getVkImageLayout() == VK_IMAGE_LAYOUT_GENERAL) {
attachment.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
attachment.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
depthReference.layout = VK_IMAGE_LAYOUT_GENERAL;
} else {
Q_ASSERT(attachmentTexture->getVkImageLayout() == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
attachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
}
attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthReference.attachment = (uint32_t)(attachments.size());
depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
} else {
if (!attachmentTexture || attachmentTexture->getVkImageLayout() == VK_IMAGE_LAYOUT_UNDEFINED) {
attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
} else {
Q_ASSERT(attachmentTexture->getVkImageLayout() == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
attachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
Expand Down
1 change: 1 addition & 0 deletions libraries/gpu/src/gpu/Buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ class Buffer : public Resource {

// FIXME find a more generic way to do this.
friend class ::gpu::vk::VKBuffer;
friend class ::gpu::vk::VKBackend;
friend class gl::GLBackend;
friend class gl::GLBuffer;
friend class gl41::GL41Buffer;
Expand Down
Loading

0 comments on commit 352073e

Please sign in to comment.