2D scene rendering + image loading #15
@@ -86,22 +86,28 @@ void RenderContext::endFrame() {
|
||||
FrameData& frame = this->frames[this->currentFrameIndex];
|
||||
frame.commandBuffer.end();
|
||||
|
||||
vk::Semaphore waitSemaphore = frame.imageAvailable.get();
|
||||
vk::Semaphore signalSemaphore =
|
||||
this->renderFinishedSemaphores.at(this->currentImageIndex).get();
|
||||
vk::PipelineStageFlags waitStage = SWAPCHAIN_ACQUIRE_STAGE;
|
||||
vk::CommandBuffer commandBuffer = frame.commandBuffer;
|
||||
|
||||
vk::SubmitInfo submitInfo{};
|
||||
submitInfo.waitSemaphoreCount = 1;
|
||||
submitInfo.pWaitSemaphores = &waitSemaphore;
|
||||
submitInfo.pWaitDstStageMask = &waitStage;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &commandBuffer;
|
||||
submitInfo.signalSemaphoreCount = 1;
|
||||
submitInfo.pSignalSemaphores = &signalSemaphore;
|
||||
vk::SemaphoreSubmitInfo waitInfo{};
|
||||
waitInfo.semaphore = frame.imageAvailable.get();
|
||||
waitInfo.stageMask = SWAPCHAIN_ACQUIRE_STAGE;
|
||||
|
||||
this->device.getGraphicsQueue().submit(submitInfo, frame.inFlight.get());
|
||||
// Present has no pipeline stage to wait on, so signal once everything in
|
||||
// the submission is done.
|
||||
vk::SemaphoreSubmitInfo signalInfo{};
|
||||
signalInfo.semaphore = signalSemaphore;
|
||||
signalInfo.stageMask = vk::PipelineStageFlagBits2::eAllCommands;
|
||||
|
||||
vk::CommandBufferSubmitInfo commandBufferInfo{};
|
||||
commandBufferInfo.commandBuffer = frame.commandBuffer;
|
||||
|
||||
vk::SubmitInfo2 submitInfo{};
|
||||
submitInfo.setWaitSemaphoreInfos(waitInfo);
|
||||
submitInfo.setCommandBufferInfos(commandBufferInfo);
|
||||
submitInfo.setSignalSemaphoreInfos(signalInfo);
|
||||
|
||||
this->device.getGraphicsQueue().submit2(submitInfo, frame.inFlight.get());
|
||||
|
||||
vk::Result result = this->swapchain->present(
|
||||
this->device.getPresentQueue(), this->currentImageIndex, signalSemaphore);
|
||||
|
||||
@@ -55,8 +55,6 @@ void RenderGraph::transitionTo(ImageRef ref, const AccessState& next,
|
||||
pending.barriers.push_back(makeImageBarrier(
|
||||
imported.image->get(), imported.image->getSubresourceRange(),
|
||||
imported.state, next));
|
||||
pending.srcStages |= imported.state.stage;
|
||||
pending.dstStages |= next.stage;
|
||||
imported.state = next;
|
||||
} else {
|
||||
// Same-layout read after read. Nothing to record, but a later write has
|
||||
@@ -68,12 +66,7 @@ void RenderGraph::transitionTo(ImageRef ref, const AccessState& next,
|
||||
|
||||
void RenderGraph::flush(vk::CommandBuffer commandBuffer,
|
||||
PendingBarriers& pending) {
|
||||
if (pending.barriers.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
commandBuffer.pipelineBarrier(pending.srcStages, pending.dstStages, {},
|
||||
nullptr, nullptr, pending.barriers);
|
||||
recordImageBarriers(commandBuffer, pending.barriers);
|
||||
pending = PendingBarriers{};
|
||||
}
|
||||
|
||||
|
||||
@@ -104,9 +104,7 @@ class RenderGraph {
|
||||
};
|
||||
|
||||
struct PendingBarriers {
|
||||
std::vector<vk::ImageMemoryBarrier> barriers;
|
||||
vk::PipelineStageFlags srcStages;
|
||||
vk::PipelineStageFlags dstStages;
|
||||
std::vector<vk::ImageMemoryBarrier2> barriers;
|
||||
};
|
||||
|
||||
void transitionTo(ImageRef ref, const AccessState& next,
|
||||
|
||||
@@ -14,10 +14,11 @@ constexpr std::array<Access, 7> ALL_ACCESSES = {
|
||||
Access::Present,
|
||||
};
|
||||
|
||||
constexpr vk::AccessFlags WRITE_ACCESSES =
|
||||
vk::AccessFlagBits::eColorAttachmentWrite |
|
||||
vk::AccessFlagBits::eDepthStencilAttachmentWrite |
|
||||
vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eTransferWrite;
|
||||
constexpr vk::AccessFlags2 WRITE_ACCESSES =
|
||||
vk::AccessFlagBits2::eColorAttachmentWrite |
|
||||
vk::AccessFlagBits2::eDepthStencilAttachmentWrite |
|
||||
vk::AccessFlagBits2::eShaderStorageWrite |
|
||||
vk::AccessFlagBits2::eTransferWrite;
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -25,34 +26,37 @@ AccessState getAccessState(Access access) {
|
||||
switch (access) {
|
||||
case Access::ColorWrite:
|
||||
return {vk::ImageLayout::eColorAttachmentOptimal,
|
||||
vk::PipelineStageFlagBits::eColorAttachmentOutput,
|
||||
vk::AccessFlagBits::eColorAttachmentRead |
|
||||
vk::AccessFlagBits::eColorAttachmentWrite};
|
||||
vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||
vk::AccessFlagBits2::eColorAttachmentRead |
|
||||
vk::AccessFlagBits2::eColorAttachmentWrite};
|
||||
case Access::DepthWrite:
|
||||
return {vk::ImageLayout::eDepthStencilAttachmentOptimal,
|
||||
vk::PipelineStageFlagBits::eEarlyFragmentTests |
|
||||
vk::PipelineStageFlagBits::eLateFragmentTests,
|
||||
vk::AccessFlagBits::eDepthStencilAttachmentRead |
|
||||
vk::AccessFlagBits::eDepthStencilAttachmentWrite};
|
||||
vk::PipelineStageFlagBits2::eEarlyFragmentTests |
|
||||
vk::PipelineStageFlagBits2::eLateFragmentTests,
|
||||
vk::AccessFlagBits2::eDepthStencilAttachmentRead |
|
||||
vk::AccessFlagBits2::eDepthStencilAttachmentWrite};
|
||||
case Access::SampledRead:
|
||||
return {vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
vk::PipelineStageFlagBits::eFragmentShader,
|
||||
vk::AccessFlagBits::eShaderRead};
|
||||
vk::PipelineStageFlagBits2::eFragmentShader,
|
||||
vk::AccessFlagBits2::eShaderSampledRead};
|
||||
case Access::StorageReadWrite:
|
||||
return {
|
||||
vk::ImageLayout::eGeneral, vk::PipelineStageFlagBits::eComputeShader,
|
||||
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite};
|
||||
return {vk::ImageLayout::eGeneral,
|
||||
vk::PipelineStageFlagBits2::eComputeShader,
|
||||
vk::AccessFlagBits2::eShaderStorageRead |
|
||||
vk::AccessFlagBits2::eShaderStorageWrite};
|
||||
case Access::TransferSrc:
|
||||
return {vk::ImageLayout::eTransferSrcOptimal,
|
||||
vk::PipelineStageFlagBits::eTransfer,
|
||||
vk::AccessFlagBits::eTransferRead};
|
||||
vk::PipelineStageFlagBits2::eTransfer,
|
||||
vk::AccessFlagBits2::eTransferRead};
|
||||
case Access::TransferDst:
|
||||
return {vk::ImageLayout::eTransferDstOptimal,
|
||||
vk::PipelineStageFlagBits::eTransfer,
|
||||
vk::AccessFlagBits::eTransferWrite};
|
||||
vk::PipelineStageFlagBits2::eTransfer,
|
||||
vk::AccessFlagBits2::eTransferWrite};
|
||||
case Access::Present:
|
||||
// Presentation isn't a pipeline stage; the present waits on a semaphore
|
||||
// instead, so the barrier into this state has nothing to block.
|
||||
return {vk::ImageLayout::ePresentSrcKHR,
|
||||
vk::PipelineStageFlagBits::eBottomOfPipe, vk::AccessFlags{}};
|
||||
vk::PipelineStageFlagBits2::eNone, vk::AccessFlags2{}};
|
||||
}
|
||||
|
||||
log::fatal("Unknown Access value.");
|
||||
@@ -83,22 +87,37 @@ bool needsBarrier(const AccessState& from, const AccessState& to) {
|
||||
return from.layout != to.layout || writesImage(from) || writesImage(to);
|
||||
}
|
||||
|
||||
vk::ImageMemoryBarrier makeImageBarrier(vk::Image image,
|
||||
vk::ImageMemoryBarrier2 makeImageBarrier(vk::Image image,
|
||||
const vk::ImageSubresourceRange& range,
|
||||
const AccessState& from,
|
||||
const AccessState& to) {
|
||||
vk::ImageMemoryBarrier barrier{};
|
||||
vk::ImageMemoryBarrier2 barrier{};
|
||||
barrier.srcStageMask = from.stage;
|
||||
barrier.dstStageMask = to.stage;
|
||||
// Only writes need to be made available; reads just need the execution
|
||||
// dependency the stage masks already give.
|
||||
barrier.srcAccessMask = from.access & WRITE_ACCESSES;
|
||||
barrier.dstAccessMask = to.access;
|
||||
barrier.oldLayout = from.layout;
|
||||
barrier.newLayout = to.layout;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = image;
|
||||
barrier.subresourceRange = range;
|
||||
// Only writes need to be made available; reads just need the execution
|
||||
// dependency the stage masks already give.
|
||||
barrier.srcAccessMask = from.access & WRITE_ACCESSES;
|
||||
barrier.dstAccessMask = to.access;
|
||||
return barrier;
|
||||
}
|
||||
|
||||
void recordImageBarriers(
|
||||
vk::CommandBuffer commandBuffer,
|
||||
vk::ArrayProxy<const vk::ImageMemoryBarrier2> barriers) {
|
||||
if (barriers.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
vk::DependencyInfo dependency{};
|
||||
dependency.imageMemoryBarrierCount = barriers.size();
|
||||
dependency.pImageMemoryBarriers = barriers.data();
|
||||
commandBuffer.pipelineBarrier2(dependency);
|
||||
}
|
||||
|
||||
} // namespace sophia
|
||||
|
||||
@@ -25,8 +25,8 @@ enum class Access {
|
||||
*/
|
||||
struct AccessState {
|
||||
vk::ImageLayout layout = vk::ImageLayout::eUndefined;
|
||||
vk::PipelineStageFlags stage = vk::PipelineStageFlagBits::eTopOfPipe;
|
||||
vk::AccessFlags access;
|
||||
vk::PipelineStageFlags2 stage = vk::PipelineStageFlagBits2::eNone;
|
||||
vk::AccessFlags2 access;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -35,8 +35,8 @@ struct AccessState {
|
||||
* just-acquired state has to use this as its source stage, otherwise the
|
||||
* layout transition isn't ordered after the acquire.
|
||||
*/
|
||||
inline constexpr vk::PipelineStageFlags SWAPCHAIN_ACQUIRE_STAGE =
|
||||
vk::PipelineStageFlagBits::eColorAttachmentOutput;
|
||||
inline constexpr vk::PipelineStageFlags2 SWAPCHAIN_ACQUIRE_STAGE =
|
||||
vk::PipelineStageFlagBits2::eColorAttachmentOutput;
|
||||
|
||||
AccessState getAccessState(Access access);
|
||||
|
||||
@@ -55,9 +55,17 @@ bool writesImage(const AccessState& state);
|
||||
*/
|
||||
bool needsBarrier(const AccessState& from, const AccessState& to);
|
||||
|
||||
vk::ImageMemoryBarrier makeImageBarrier(vk::Image image,
|
||||
/**
|
||||
* A barrier carrying its own stage masks, for recording with
|
||||
* pipelineBarrier2. Barriers flushed together don't share stages.
|
||||
*/
|
||||
vk::ImageMemoryBarrier2 makeImageBarrier(vk::Image image,
|
||||
const vk::ImageSubresourceRange& range,
|
||||
const AccessState& from,
|
||||
const AccessState& to);
|
||||
|
||||
void recordImageBarriers(
|
||||
vk::CommandBuffer commandBuffer,
|
||||
vk::ArrayProxy<const vk::ImageMemoryBarrier2> barriers);
|
||||
|
||||
} // namespace sophia
|
||||
|
||||
@@ -56,10 +56,9 @@ void Image::transitionLayout(vk::CommandBuffer commandBuffer,
|
||||
AccessState to = getStateForLayout(newLayout);
|
||||
|
||||
if (needsBarrier(from, to)) {
|
||||
vk::ImageMemoryBarrier barrier =
|
||||
vk::ImageMemoryBarrier2 barrier =
|
||||
makeImageBarrier(this->get(), this->getSubresourceRange(), from, to);
|
||||
commandBuffer.pipelineBarrier(from.stage, to.stage, {}, nullptr, nullptr,
|
||||
barrier);
|
||||
recordImageBarriers(commandBuffer, barrier);
|
||||
}
|
||||
|
||||
this->layout = newLayout;
|
||||
|
||||
Reference in New Issue
Block a user