| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954 |
- // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
- // All rights reserved.
- // Code licensed under the BSD License.
- // http://www.anki3d.org/LICENSE
- #include <AnKi/Gr/Vulkan/CommandBufferImpl.h>
- #include <AnKi/Gr/Vulkan/TextureImpl.h>
- #include <AnKi/Gr/OcclusionQuery.h>
- #include <AnKi/Gr/Vulkan/OcclusionQueryImpl.h>
- #include <AnKi/Gr/TimestampQuery.h>
- #include <AnKi/Gr/Vulkan/TimestampQueryImpl.h>
- #include <AnKi/Util/Tracer.h>
- namespace anki
- {
- inline void CommandBufferImpl::setStencilCompareMask(FaceSelectionBit face, U32 mask)
- {
- commandCommon();
- VkStencilFaceFlags flags = 0;
- if(!!(face & FaceSelectionBit::FRONT) && m_stencilCompareMasks[0] != mask)
- {
- m_stencilCompareMasks[0] = mask;
- flags = VK_STENCIL_FACE_FRONT_BIT;
- }
- if(!!(face & FaceSelectionBit::BACK) && m_stencilCompareMasks[1] != mask)
- {
- m_stencilCompareMasks[1] = mask;
- flags |= VK_STENCIL_FACE_BACK_BIT;
- }
- if(flags)
- {
- ANKI_CMD(vkCmdSetStencilCompareMask(m_handle, flags, mask), ANY_OTHER_COMMAND);
- }
- }
- inline void CommandBufferImpl::setStencilWriteMask(FaceSelectionBit face, U32 mask)
- {
- commandCommon();
- VkStencilFaceFlags flags = 0;
- if(!!(face & FaceSelectionBit::FRONT) && m_stencilWriteMasks[0] != mask)
- {
- m_stencilWriteMasks[0] = mask;
- flags = VK_STENCIL_FACE_FRONT_BIT;
- }
- if(!!(face & FaceSelectionBit::BACK) && m_stencilWriteMasks[1] != mask)
- {
- m_stencilWriteMasks[1] = mask;
- flags |= VK_STENCIL_FACE_BACK_BIT;
- }
- if(flags)
- {
- ANKI_CMD(vkCmdSetStencilWriteMask(m_handle, flags, mask), ANY_OTHER_COMMAND);
- }
- }
- inline void CommandBufferImpl::setStencilReference(FaceSelectionBit face, U32 ref)
- {
- commandCommon();
- VkStencilFaceFlags flags = 0;
- if(!!(face & FaceSelectionBit::FRONT) && m_stencilReferenceMasks[0] != ref)
- {
- m_stencilReferenceMasks[0] = ref;
- flags = VK_STENCIL_FACE_FRONT_BIT;
- }
- if(!!(face & FaceSelectionBit::BACK) && m_stencilReferenceMasks[1] != ref)
- {
- m_stencilWriteMasks[1] = ref;
- flags |= VK_STENCIL_FACE_BACK_BIT;
- }
- if(flags)
- {
- ANKI_CMD(vkCmdSetStencilReference(m_handle, flags, ref), ANY_OTHER_COMMAND);
- }
- }
- inline void CommandBufferImpl::setImageBarrier(VkPipelineStageFlags srcStage, VkAccessFlags srcAccess,
- VkImageLayout prevLayout, VkPipelineStageFlags dstStage,
- VkAccessFlags dstAccess, VkImageLayout newLayout, VkImage img,
- const VkImageSubresourceRange& range)
- {
- ANKI_ASSERT(img);
- commandCommon();
- VkImageMemoryBarrier inf = {};
- inf.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- inf.srcAccessMask = srcAccess;
- inf.dstAccessMask = dstAccess;
- inf.oldLayout = prevLayout;
- inf.newLayout = newLayout;
- inf.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- inf.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- inf.image = img;
- inf.subresourceRange = range;
- #if ANKI_BATCH_COMMANDS
- flushBatches(CommandBufferCommandType::SET_BARRIER);
- if(m_imgBarriers.getSize() <= m_imgBarrierCount)
- {
- m_imgBarriers.resize(m_alloc, max<U32>(2, m_imgBarrierCount * 2));
- }
- m_imgBarriers[m_imgBarrierCount++] = inf;
- m_srcStageMask |= srcStage;
- m_dstStageMask |= dstStage;
- #else
- ANKI_CMD(vkCmdPipelineBarrier(m_handle, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &inf), ANY_OTHER_COMMAND);
- ANKI_TRACE_INC_COUNTER(VK_PIPELINE_BARRIERS, 1);
- #endif
- }
- inline void CommandBufferImpl::setTextureBarrierRange(TexturePtr tex, TextureUsageBit prevUsage,
- TextureUsageBit nextUsage, const VkImageSubresourceRange& range)
- {
- const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
- ANKI_ASSERT(impl.usageValid(prevUsage));
- ANKI_ASSERT(impl.usageValid(nextUsage));
- ANKI_ASSERT(((nextUsage & TextureUsageBit::GENERATE_MIPMAPS) == TextureUsageBit::GENERATE_MIPMAPS
- || (nextUsage & TextureUsageBit::GENERATE_MIPMAPS) == TextureUsageBit::NONE)
- && "GENERATE_MIPMAPS should be alone");
- VkPipelineStageFlags srcStage;
- VkAccessFlags srcAccess;
- VkImageLayout oldLayout;
- VkPipelineStageFlags dstStage;
- VkAccessFlags dstAccess;
- VkImageLayout newLayout;
- impl.computeBarrierInfo(prevUsage, nextUsage, range.baseMipLevel, srcStage, srcAccess, dstStage, dstAccess);
- oldLayout = impl.computeLayout(prevUsage, range.baseMipLevel);
- newLayout = impl.computeLayout(nextUsage, range.baseMipLevel);
- setImageBarrier(srcStage, srcAccess, oldLayout, dstStage, dstAccess, newLayout, impl.m_imageHandle, range);
- m_microCmdb->pushObjectRef(tex);
- }
- inline void CommandBufferImpl::setTextureBarrier(TexturePtr tex, TextureUsageBit prevUsage, TextureUsageBit nextUsage,
- const TextureSubresourceInfo& subresource_)
- {
- TextureSubresourceInfo subresource = subresource_;
- const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
- // The transition of the non zero mip levels happens inside CommandBufferImpl::generateMipmapsX so limit the
- // subresource
- if(nextUsage == TextureUsageBit::GENERATE_MIPMAPS)
- {
- ANKI_ASSERT(impl.isSubresourceGoodForMipmapGeneration(subresource));
- subresource.m_firstMipmap = 0;
- subresource.m_mipmapCount = 1;
- }
- ANKI_ASSERT(tex->isSubresourceValid(subresource));
- VkImageSubresourceRange range;
- impl.computeVkImageSubresourceRange(subresource, range);
- setTextureBarrierRange(tex, prevUsage, nextUsage, range);
- }
- inline void CommandBufferImpl::setTextureSurfaceBarrier(TexturePtr tex, TextureUsageBit prevUsage,
- TextureUsageBit nextUsage, const TextureSurfaceInfo& surf)
- {
- if(ANKI_UNLIKELY(surf.m_level > 0 && nextUsage == TextureUsageBit::GENERATE_MIPMAPS))
- {
- // This transition happens inside CommandBufferImpl::generateMipmapsX. No need to do something
- return;
- }
- const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
- VkImageSubresourceRange range;
- impl.computeVkImageSubresourceRange(TextureSubresourceInfo(surf, impl.getDepthStencilAspect()), range);
- setTextureBarrierRange(tex, prevUsage, nextUsage, range);
- }
- inline void CommandBufferImpl::setTextureVolumeBarrier(TexturePtr tex, TextureUsageBit prevUsage,
- TextureUsageBit nextUsage, const TextureVolumeInfo& vol)
- {
- if(vol.m_level > 0)
- {
- ANKI_ASSERT(!(nextUsage & TextureUsageBit::GENERATE_MIPMAPS)
- && "This transition happens inside CommandBufferImpl::generateMipmaps");
- }
- const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
- VkImageSubresourceRange range;
- impl.computeVkImageSubresourceRange(TextureSubresourceInfo(vol, impl.getDepthStencilAspect()), range);
- setTextureBarrierRange(tex, prevUsage, nextUsage, range);
- }
- inline void CommandBufferImpl::setBufferBarrier(VkPipelineStageFlags srcStage, VkAccessFlags srcAccess,
- VkPipelineStageFlags dstStage, VkAccessFlags dstAccess, PtrSize offset,
- PtrSize size, VkBuffer buff)
- {
- ANKI_ASSERT(buff);
- commandCommon();
- VkBufferMemoryBarrier b = {};
- b.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
- b.srcAccessMask = srcAccess;
- b.dstAccessMask = dstAccess;
- b.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- b.buffer = buff;
- b.offset = offset;
- b.size = size;
- #if ANKI_BATCH_COMMANDS
- flushBatches(CommandBufferCommandType::SET_BARRIER);
- if(m_buffBarriers.getSize() <= m_buffBarrierCount)
- {
- m_buffBarriers.resize(m_alloc, max<U32>(2, m_buffBarrierCount * 2));
- }
- m_buffBarriers[m_buffBarrierCount++] = b;
- m_srcStageMask |= srcStage;
- m_dstStageMask |= dstStage;
- #else
- ANKI_CMD(vkCmdPipelineBarrier(m_handle, srcStage, dstStage, 0, 0, nullptr, 1, &b, 0, nullptr), ANY_OTHER_COMMAND);
- ANKI_TRACE_INC_COUNTER(VK_PIPELINE_BARRIERS, 1);
- #endif
- }
- inline void CommandBufferImpl::setBufferBarrier(BufferPtr& buff, BufferUsageBit before, BufferUsageBit after,
- PtrSize offset, PtrSize size)
- {
- const BufferImpl& impl = static_cast<const BufferImpl&>(*buff);
- VkPipelineStageFlags srcStage;
- VkAccessFlags srcAccess;
- VkPipelineStageFlags dstStage;
- VkAccessFlags dstAccess;
- impl.computeBarrierInfo(before, after, srcStage, srcAccess, dstStage, dstAccess);
- setBufferBarrier(srcStage, srcAccess, dstStage, dstAccess, offset, size, impl.getHandle());
- m_microCmdb->pushObjectRef(buff);
- }
- inline void CommandBufferImpl::setAccelerationStructureBarrierInternal(AccelerationStructurePtr& as,
- AccelerationStructureUsageBit prevUsage,
- AccelerationStructureUsageBit nextUsage)
- {
- commandCommon();
- VkPipelineStageFlags srcStage;
- VkAccessFlags srcAccess;
- VkPipelineStageFlags dstStage;
- VkAccessFlags dstAccess;
- AccelerationStructureImpl::computeBarrierInfo(prevUsage, nextUsage, srcStage, srcAccess, dstStage, dstAccess);
- #if ANKI_BATCH_COMMANDS
- flushBatches(CommandBufferCommandType::SET_BARRIER);
- VkMemoryBarrier memBarrier = {};
- memBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
- memBarrier.srcAccessMask = srcAccess;
- memBarrier.dstAccessMask = dstAccess;
- if(m_memBarriers.getSize() <= m_memBarrierCount)
- {
- m_memBarriers.resize(m_alloc, max<U32>(2, m_memBarrierCount * 2));
- }
- m_memBarriers[m_memBarrierCount++] = memBarrier;
- m_srcStageMask |= srcStage;
- m_dstStageMask |= dstStage;
- #else
- ANKI_ASSERT(!"TODO");
- #endif
- }
- inline void CommandBufferImpl::drawArrays(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 first,
- U32 baseInstance)
- {
- m_state.setPrimitiveTopology(topology);
- drawcallCommon();
- ANKI_CMD(vkCmdDraw(m_handle, count, instanceCount, first, baseInstance), ANY_OTHER_COMMAND);
- }
- inline void CommandBufferImpl::drawElements(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 firstIndex,
- U32 baseVertex, U32 baseInstance)
- {
- m_state.setPrimitiveTopology(topology);
- drawcallCommon();
- ANKI_CMD(vkCmdDrawIndexed(m_handle, count, instanceCount, firstIndex, baseVertex, baseInstance), ANY_OTHER_COMMAND);
- }
- inline void CommandBufferImpl::drawArraysIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset,
- BufferPtr& buff)
- {
- m_state.setPrimitiveTopology(topology);
- drawcallCommon();
- const BufferImpl& impl = static_cast<const BufferImpl&>(*buff);
- ANKI_ASSERT(impl.usageValid(BufferUsageBit::INDIRECT_DRAW));
- ANKI_ASSERT((offset % 4) == 0);
- ANKI_ASSERT((offset + sizeof(DrawArraysIndirectInfo) * drawCount) <= impl.getSize());
- ANKI_CMD(vkCmdDrawIndirect(m_handle, impl.getHandle(), offset, drawCount, sizeof(DrawArraysIndirectInfo)),
- ANY_OTHER_COMMAND);
- }
- inline void CommandBufferImpl::drawElementsIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset,
- BufferPtr& buff)
- {
- m_state.setPrimitiveTopology(topology);
- drawcallCommon();
- const BufferImpl& impl = static_cast<const BufferImpl&>(*buff);
- ANKI_ASSERT(impl.usageValid(BufferUsageBit::INDIRECT_DRAW));
- ANKI_ASSERT((offset % 4) == 0);
- ANKI_ASSERT((offset + sizeof(DrawElementsIndirectInfo) * drawCount) <= impl.getSize());
- ANKI_CMD(vkCmdDrawIndexedIndirect(m_handle, impl.getHandle(), offset, drawCount, sizeof(DrawElementsIndirectInfo)),
- ANY_OTHER_COMMAND);
- }
- inline void CommandBufferImpl::dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ)
- {
- ANKI_ASSERT(m_computeProg);
- ANKI_ASSERT(m_computeProg->getReflectionInfo().m_pushConstantsSize == m_setPushConstantsSize
- && "Forgot to set pushConstants");
- commandCommon();
- getGrManagerImpl().beginMarker(m_handle, m_computeProg->getName());
- // Bind descriptors
- for(U32 i = 0; i < MAX_DESCRIPTOR_SETS; ++i)
- {
- if(m_computeProg->getReflectionInfo().m_descriptorSetMask.get(i))
- {
- DescriptorSet dset;
- Bool dirty;
- Array<PtrSize, MAX_BINDINGS_PER_DESCRIPTOR_SET> dynamicOffsetsPtrSize;
- U32 dynamicOffsetCount;
- if(getGrManagerImpl().getDescriptorSetFactory().newDescriptorSet(
- m_tid, m_alloc, m_dsetState[i], dset, dirty, dynamicOffsetsPtrSize, dynamicOffsetCount))
- {
- ANKI_VK_LOGF("Cannot recover");
- }
- if(dirty)
- {
- // Vulkan should have had the dynamic offsets as VkDeviceSize and not U32. Workaround that.
- Array<U32, MAX_BINDINGS_PER_DESCRIPTOR_SET> dynamicOffsets;
- for(U32 i = 0; i < dynamicOffsetCount; ++i)
- {
- dynamicOffsets[i] = U32(dynamicOffsetsPtrSize[i]);
- }
- VkDescriptorSet dsHandle = dset.getHandle();
- ANKI_CMD(vkCmdBindDescriptorSets(m_handle, VK_PIPELINE_BIND_POINT_COMPUTE,
- m_computeProg->getPipelineLayout().getHandle(), i, 1, &dsHandle,
- dynamicOffsetCount, &dynamicOffsets[0]),
- ANY_OTHER_COMMAND);
- }
- }
- }
- ANKI_CMD(vkCmdDispatch(m_handle, groupCountX, groupCountY, groupCountZ), ANY_OTHER_COMMAND);
- getGrManagerImpl().endMarker(m_handle);
- }
- inline void CommandBufferImpl::traceRaysInternal(BufferPtr& sbtBuffer, PtrSize sbtBufferOffset, U32 sbtRecordSize32,
- U32 hitGroupSbtRecordCount, U32 rayTypeCount, U32 width, U32 height,
- U32 depth)
- {
- const PtrSize sbtRecordSize = sbtRecordSize32;
- ANKI_ASSERT(hitGroupSbtRecordCount > 0);
- ANKI_ASSERT(width > 0 && height > 0 && depth > 0);
- ANKI_ASSERT(m_rtProg);
- const ShaderProgramImpl& sprog = static_cast<const ShaderProgramImpl&>(*m_rtProg);
- ANKI_ASSERT(sprog.getReflectionInfo().m_pushConstantsSize == m_setPushConstantsSize
- && "Forgot to set pushConstants");
- ANKI_ASSERT(rayTypeCount == sprog.getMissShaderCount() && "All the miss shaders should be in use");
- ANKI_ASSERT((hitGroupSbtRecordCount % rayTypeCount) == 0);
- const PtrSize sbtRecordCount = 1 + rayTypeCount + hitGroupSbtRecordCount;
- const PtrSize sbtBufferSize = sbtRecordCount * sbtRecordSize;
- (void)sbtBufferSize;
- ANKI_ASSERT(sbtBufferSize + sbtBufferOffset <= sbtBuffer->getSize());
- ANKI_ASSERT(isAligned(getGrManagerImpl().getDeviceCapabilities().m_sbtRecordAlignment, sbtBufferOffset));
- commandCommon();
- getGrManagerImpl().beginMarker(m_handle, m_rtProg->getName());
- // Bind descriptors
- for(U32 i = 0; i < MAX_DESCRIPTOR_SETS; ++i)
- {
- if(sprog.getReflectionInfo().m_descriptorSetMask.get(i))
- {
- DescriptorSet dset;
- Bool dirty;
- Array<PtrSize, MAX_BINDINGS_PER_DESCRIPTOR_SET> dynamicOffsetsPtrSize;
- U32 dynamicOffsetCount;
- if(getGrManagerImpl().getDescriptorSetFactory().newDescriptorSet(
- m_tid, m_alloc, m_dsetState[i], dset, dirty, dynamicOffsetsPtrSize, dynamicOffsetCount))
- {
- ANKI_VK_LOGF("Cannot recover");
- }
- if(dirty)
- {
- // Vulkan should have had the dynamic offsets as VkDeviceSize and not U32. Workaround that.
- Array<U32, MAX_BINDINGS_PER_DESCRIPTOR_SET> dynamicOffsets;
- for(U32 i = 0; i < dynamicOffsetCount; ++i)
- {
- dynamicOffsets[i] = U32(dynamicOffsetsPtrSize[i]);
- }
- VkDescriptorSet dsHandle = dset.getHandle();
- ANKI_CMD(vkCmdBindDescriptorSets(m_handle, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR,
- sprog.getPipelineLayout().getHandle(), i, 1, &dsHandle,
- dynamicOffsetCount, &dynamicOffsets[0]),
- ANY_OTHER_COMMAND);
- }
- }
- }
- Array<VkStridedDeviceAddressRegionKHR, 4> regions;
- const U64 stbBufferAddress = sbtBuffer->getGpuAddress() + sbtBufferOffset;
- ANKI_ASSERT(isAligned(getGrManagerImpl().getDeviceCapabilities().m_sbtRecordAlignment, stbBufferAddress));
- // Rgen
- regions[0].deviceAddress = stbBufferAddress;
- regions[0].stride = sbtRecordSize;
- regions[0].size = sbtRecordSize;
- // Miss
- regions[1].deviceAddress = regions[0].deviceAddress + regions[0].size;
- regions[1].stride = sbtRecordSize;
- regions[1].size = sbtRecordSize * rayTypeCount;
- // Hit
- regions[2].deviceAddress = regions[1].deviceAddress + regions[1].size;
- regions[2].stride = sbtRecordSize * rayTypeCount;
- regions[2].size = sbtRecordSize * hitGroupSbtRecordCount;
- // Callable, nothing for now
- regions[3] = VkStridedDeviceAddressRegionKHR();
- ANKI_CMD(vkCmdTraceRaysKHR(m_handle, ®ions[0], ®ions[1], ®ions[2], ®ions[3], width, height, depth),
- ANY_OTHER_COMMAND);
- getGrManagerImpl().endMarker(m_handle);
- }
- inline void CommandBufferImpl::resetOcclusionQuery(OcclusionQueryPtr query)
- {
- commandCommon();
- VkQueryPool handle = static_cast<const OcclusionQueryImpl&>(*query).m_handle.getQueryPool();
- U32 idx = static_cast<const OcclusionQueryImpl&>(*query).m_handle.getQueryIndex();
- ANKI_ASSERT(handle);
- #if ANKI_BATCH_COMMANDS
- flushBatches(CommandBufferCommandType::RESET_QUERY);
- QueryResetAtom atom;
- atom.m_pool = handle;
- atom.m_queryIdx = idx;
- m_queryResetAtoms.emplaceBack(m_alloc, atom);
- #else
- ANKI_CMD(vkCmdResetQueryPool(m_handle, handle, idx, 1), ANY_OTHER_COMMAND);
- #endif
- m_microCmdb->pushObjectRef(query);
- }
- inline void CommandBufferImpl::beginOcclusionQuery(OcclusionQueryPtr query)
- {
- commandCommon();
- const VkQueryPool handle = static_cast<const OcclusionQueryImpl&>(*query).m_handle.getQueryPool();
- const U32 idx = static_cast<const OcclusionQueryImpl&>(*query).m_handle.getQueryIndex();
- ANKI_ASSERT(handle);
- ANKI_CMD(vkCmdBeginQuery(m_handle, handle, idx, 0), ANY_OTHER_COMMAND);
- m_microCmdb->pushObjectRef(query);
- }
- inline void CommandBufferImpl::endOcclusionQuery(OcclusionQueryPtr query)
- {
- commandCommon();
- const VkQueryPool handle = static_cast<const OcclusionQueryImpl&>(*query).m_handle.getQueryPool();
- const U32 idx = static_cast<const OcclusionQueryImpl&>(*query).m_handle.getQueryIndex();
- ANKI_ASSERT(handle);
- ANKI_CMD(vkCmdEndQuery(m_handle, handle, idx), ANY_OTHER_COMMAND);
- m_microCmdb->pushObjectRef(query);
- }
- inline void CommandBufferImpl::resetTimestampQueryInternal(TimestampQueryPtr& query)
- {
- commandCommon();
- const VkQueryPool handle = static_cast<const TimestampQueryImpl&>(*query).m_handle.getQueryPool();
- const U32 idx = static_cast<const TimestampQueryImpl&>(*query).m_handle.getQueryIndex();
- ANKI_ASSERT(handle);
- #if ANKI_BATCH_COMMANDS
- flushBatches(CommandBufferCommandType::RESET_QUERY);
- QueryResetAtom atom;
- atom.m_pool = handle;
- atom.m_queryIdx = idx;
- m_queryResetAtoms.emplaceBack(m_alloc, atom);
- #else
- ANKI_CMD(vkCmdResetQueryPool(m_handle, handle, idx, 1), ANY_OTHER_COMMAND);
- #endif
- m_microCmdb->pushObjectRef(query);
- }
- inline void CommandBufferImpl::writeTimestampInternal(TimestampQueryPtr& query)
- {
- commandCommon();
- const VkQueryPool handle = static_cast<const TimestampQueryImpl&>(*query).m_handle.getQueryPool();
- const U32 idx = static_cast<const TimestampQueryImpl&>(*query).m_handle.getQueryIndex();
- ANKI_CMD(vkCmdWriteTimestamp(m_handle, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, handle, idx), ANY_OTHER_COMMAND);
- m_microCmdb->pushObjectRef(query);
- }
- inline void CommandBufferImpl::clearTextureView(TextureViewPtr texView, const ClearValue& clearValue)
- {
- commandCommon();
- const TextureViewImpl& view = static_cast<const TextureViewImpl&>(*texView);
- const TextureImpl& tex = view.getTextureImpl();
- VkClearColorValue vclear;
- static_assert(sizeof(vclear) == sizeof(clearValue), "See file");
- memcpy(&vclear, &clearValue, sizeof(clearValue));
- if(!view.getSubresource().m_depthStencilAspect)
- {
- VkImageSubresourceRange vkRange = view.getVkImageSubresourceRange();
- ANKI_CMD(vkCmdClearColorImage(m_handle, tex.m_imageHandle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &vclear, 1,
- &vkRange),
- ANY_OTHER_COMMAND);
- }
- else
- {
- ANKI_ASSERT(!"TODO");
- }
- m_microCmdb->pushObjectRef(texView);
- }
- inline void CommandBufferImpl::pushSecondLevelCommandBuffer(CommandBufferPtr cmdb)
- {
- commandCommon();
- ANKI_ASSERT(insideRenderPass());
- ANKI_ASSERT(m_subpassContents == VK_SUBPASS_CONTENTS_MAX_ENUM
- || m_subpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
- ANKI_ASSERT(static_cast<const CommandBufferImpl&>(*cmdb).m_finalized);
- m_subpassContents = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
- if(ANKI_UNLIKELY(m_rpCommandCount == 0))
- {
- beginRenderPassInternal();
- }
- #if ANKI_BATCH_COMMANDS
- flushBatches(CommandBufferCommandType::PUSH_SECOND_LEVEL);
- if(m_secondLevelAtoms.getSize() <= m_secondLevelAtomCount)
- {
- m_secondLevelAtoms.resize(m_alloc, max<U32>(8, m_secondLevelAtomCount * 2));
- }
- m_secondLevelAtoms[m_secondLevelAtomCount++] = static_cast<const CommandBufferImpl&>(*cmdb).m_handle;
- #else
- ANKI_CMD(vkCmdExecuteCommands(m_handle, 1, &static_cast<const CommandBufferImpl&>(*cmdb).m_handle),
- ANY_OTHER_COMMAND);
- #endif
- ++m_rpCommandCount;
- m_microCmdb->pushObjectRef(cmdb);
- }
- inline void CommandBufferImpl::drawcallCommon()
- {
- // Preconditions
- commandCommon();
- ANKI_ASSERT(m_graphicsProg);
- ANKI_ASSERT(insideRenderPass() || secondLevel());
- ANKI_ASSERT(m_subpassContents == VK_SUBPASS_CONTENTS_MAX_ENUM || m_subpassContents == VK_SUBPASS_CONTENTS_INLINE);
- ANKI_ASSERT(m_graphicsProg->getReflectionInfo().m_pushConstantsSize == m_setPushConstantsSize
- && "Forgot to set pushConstants");
- m_subpassContents = VK_SUBPASS_CONTENTS_INLINE;
- if(ANKI_UNLIKELY(m_rpCommandCount == 0) && !secondLevel())
- {
- beginRenderPassInternal();
- }
- ++m_rpCommandCount;
- // Get or create ppline
- Pipeline ppline;
- Bool stateDirty;
- m_graphicsProg->getPipelineFactory().getOrCreatePipeline(m_state, ppline, stateDirty);
- if(stateDirty)
- {
- ANKI_CMD(vkCmdBindPipeline(m_handle, VK_PIPELINE_BIND_POINT_GRAPHICS, ppline.getHandle()), ANY_OTHER_COMMAND);
- }
- // Bind dsets
- for(U32 i = 0; i < MAX_DESCRIPTOR_SETS; ++i)
- {
- if(m_graphicsProg->getReflectionInfo().m_descriptorSetMask.get(i))
- {
- DescriptorSet dset;
- Bool dirty;
- Array<PtrSize, MAX_BINDINGS_PER_DESCRIPTOR_SET> dynamicOffsetsPtrSize;
- U32 dynamicOffsetCount;
- if(getGrManagerImpl().getDescriptorSetFactory().newDescriptorSet(
- m_tid, m_alloc, m_dsetState[i], dset, dirty, dynamicOffsetsPtrSize, dynamicOffsetCount))
- {
- ANKI_VK_LOGF("Cannot recover");
- }
- if(dirty)
- {
- // Vulkan should have had the dynamic offsets as VkDeviceSize and not U32. Workaround that.
- Array<U32, MAX_BINDINGS_PER_DESCRIPTOR_SET> dynamicOffsets;
- for(U32 i = 0; i < dynamicOffsetCount; ++i)
- {
- dynamicOffsets[i] = U32(dynamicOffsetsPtrSize[i]);
- }
- VkDescriptorSet dsHandle = dset.getHandle();
- ANKI_CMD(vkCmdBindDescriptorSets(m_handle, VK_PIPELINE_BIND_POINT_GRAPHICS,
- m_graphicsProg->getPipelineLayout().getHandle(), i, 1, &dsHandle,
- dynamicOffsetCount, &dynamicOffsets[0]),
- ANY_OTHER_COMMAND);
- }
- }
- }
- // Flush viewport
- if(ANKI_UNLIKELY(m_viewportDirty))
- {
- const Bool flipvp = flipViewport();
- U32 fbWidth, fbHeight;
- static_cast<const FramebufferImpl&>(*m_activeFb).getAttachmentsSize(fbWidth, fbHeight);
- VkViewport vp = computeViewport(&m_viewport[0], fbWidth, fbHeight, flipvp);
- // Additional optimization
- if(memcmp(&vp, &m_lastViewport, sizeof(vp)) != 0)
- {
- ANKI_CMD(vkCmdSetViewport(m_handle, 0, 1, &vp), ANY_OTHER_COMMAND);
- m_lastViewport = vp;
- }
- m_viewportDirty = false;
- }
- // Flush scissor
- if(ANKI_UNLIKELY(m_scissorDirty))
- {
- const Bool flipvp = flipViewport();
- U32 fbWidth, fbHeight;
- static_cast<const FramebufferImpl&>(*m_activeFb).getAttachmentsSize(fbWidth, fbHeight);
- VkRect2D scissor = computeScissor(&m_scissor[0], fbWidth, fbHeight, flipvp);
- // Additional optimization
- if(memcmp(&scissor, &m_lastScissor, sizeof(scissor)) != 0)
- {
- ANKI_CMD(vkCmdSetScissor(m_handle, 0, 1, &scissor), ANY_OTHER_COMMAND);
- m_lastScissor = scissor;
- }
- m_scissorDirty = false;
- }
- // Some checks
- #if ANKI_ENABLE_ASSERTIONS
- if(m_state.getPrimitiveTopology() == PrimitiveTopology::LINES
- || m_state.getPrimitiveTopology() == PrimitiveTopology::LINE_STRIP)
- {
- ANKI_ASSERT(m_lineWidthSet == true);
- }
- #endif
- ANKI_TRACE_INC_COUNTER(GR_DRAWCALLS, 1);
- }
- inline void CommandBufferImpl::commandCommon()
- {
- ANKI_ASSERT(!m_finalized);
- #if ANKI_EXTRA_CHECKS
- ++m_commandCount;
- #endif
- m_empty = false;
- if(ANKI_UNLIKELY(!m_beganRecording))
- {
- beginRecording();
- m_beganRecording = true;
- }
- ANKI_ASSERT(Thread::getCurrentThreadId() == m_tid
- && "Commands must be recorder and flushed by the thread this command buffer was created");
- ANKI_ASSERT(m_handle);
- }
- inline void CommandBufferImpl::flushBatches(CommandBufferCommandType type)
- {
- if(type != m_lastCmdType)
- {
- switch(m_lastCmdType)
- {
- case CommandBufferCommandType::SET_BARRIER:
- flushBarriers();
- break;
- case CommandBufferCommandType::RESET_QUERY:
- flushQueryResets();
- break;
- case CommandBufferCommandType::WRITE_QUERY_RESULT:
- flushWriteQueryResults();
- break;
- case CommandBufferCommandType::PUSH_SECOND_LEVEL:
- ANKI_ASSERT(m_secondLevelAtomCount > 0);
- vkCmdExecuteCommands(m_handle, m_secondLevelAtomCount, &m_secondLevelAtoms[0]);
- m_secondLevelAtomCount = 0;
- break;
- case CommandBufferCommandType::ANY_OTHER_COMMAND:
- break;
- default:
- ANKI_ASSERT(0);
- }
- m_lastCmdType = type;
- }
- }
- inline void CommandBufferImpl::fillBuffer(BufferPtr buff, PtrSize offset, PtrSize size, U32 value)
- {
- commandCommon();
- ANKI_ASSERT(!insideRenderPass());
- const BufferImpl& impl = static_cast<const BufferImpl&>(*buff);
- ANKI_ASSERT(impl.usageValid(BufferUsageBit::TRANSFER_DESTINATION));
- ANKI_ASSERT(offset < impl.getSize());
- ANKI_ASSERT((offset % 4) == 0 && "Should be multiple of 4");
- size = (size == MAX_PTR_SIZE) ? (impl.getActualSize() - offset) : size;
- alignRoundUp(4, size); // Needs to be multiple of 4
- ANKI_ASSERT(offset + size <= impl.getActualSize());
- ANKI_ASSERT((size % 4) == 0 && "Should be multiple of 4");
- ANKI_CMD(vkCmdFillBuffer(m_handle, impl.getHandle(), offset, size, value), ANY_OTHER_COMMAND);
- m_microCmdb->pushObjectRef(buff);
- }
- inline void CommandBufferImpl::writeOcclusionQueryResultToBuffer(OcclusionQueryPtr query, PtrSize offset,
- BufferPtr buff)
- {
- commandCommon();
- ANKI_ASSERT(!insideRenderPass());
- const BufferImpl& impl = static_cast<const BufferImpl&>(*buff);
- ANKI_ASSERT(impl.usageValid(BufferUsageBit::TRANSFER_DESTINATION));
- ANKI_ASSERT((offset % 4) == 0);
- ANKI_ASSERT((offset + sizeof(U32)) <= impl.getSize());
- const OcclusionQueryImpl& q = static_cast<const OcclusionQueryImpl&>(*query);
- #if ANKI_BATCH_COMMANDS
- flushBatches(CommandBufferCommandType::WRITE_QUERY_RESULT);
- WriteQueryAtom atom;
- atom.m_pool = q.m_handle.getQueryPool();
- atom.m_queryIdx = q.m_handle.getQueryIndex();
- atom.m_buffer = impl.getHandle();
- atom.m_offset = offset;
- m_writeQueryAtoms.emplaceBack(m_alloc, atom);
- #else
- ANKI_CMD(vkCmdCopyQueryPoolResults(m_handle, q.m_handle.m_pool, q.m_handle.m_queryIndex, 1, impl.getHandle(),
- offset, sizeof(U32), VK_QUERY_RESULT_PARTIAL_BIT),
- ANY_OTHER_COMMAND);
- #endif
- m_microCmdb->pushObjectRef(query);
- m_microCmdb->pushObjectRef(buff);
- }
- inline void CommandBufferImpl::bindShaderProgram(ShaderProgramPtr& prog)
- {
- commandCommon();
- ShaderProgramImpl& impl = static_cast<ShaderProgramImpl&>(*prog);
- if(impl.isGraphics())
- {
- m_graphicsProg = &impl;
- m_computeProg = nullptr; // Unbind the compute prog. Doesn't work like vulkan
- m_rtProg = nullptr; // See above
- m_state.bindShaderProgram(&impl);
- }
- else if(!!(impl.getStages() & ShaderTypeBit::COMPUTE))
- {
- m_computeProg = &impl;
- m_graphicsProg = nullptr; // See comment in the if()
- m_rtProg = nullptr; // See above
- // Bind the pipeline now
- ANKI_CMD(vkCmdBindPipeline(m_handle, VK_PIPELINE_BIND_POINT_COMPUTE, impl.getComputePipelineHandle()),
- ANY_OTHER_COMMAND);
- }
- else
- {
- ANKI_ASSERT(!!(impl.getStages() & ShaderTypeBit::ALL_RAY_TRACING));
- m_computeProg = nullptr;
- m_graphicsProg = nullptr;
- m_rtProg = &impl;
- // Bind now
- ANKI_CMD(
- vkCmdBindPipeline(m_handle, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, impl.getRayTracingPipelineHandle()),
- ANY_OTHER_COMMAND);
- }
- for(U32 i = 0; i < MAX_DESCRIPTOR_SETS; ++i)
- {
- if(impl.getReflectionInfo().m_descriptorSetMask.get(i))
- {
- m_dsetState[i].setLayout(impl.getDescriptorSetLayout(i));
- }
- else
- {
- // According to the spec the bound DS may be disturbed if the ppline layout is not compatible. Play it safe
- // and dirty the slot. That will force rebind of the DS at drawcall time.
- m_dsetState[i].setLayout(DescriptorSetLayout());
- }
- }
- m_microCmdb->pushObjectRef(prog);
- #if ANKI_EXTRA_CHECKS
- m_setPushConstantsSize = 0;
- #endif
- }
- inline void CommandBufferImpl::copyBufferToBuffer(BufferPtr& src, PtrSize srcOffset, BufferPtr& dst, PtrSize dstOffset,
- PtrSize range)
- {
- ANKI_ASSERT(static_cast<const BufferImpl&>(*src).usageValid(BufferUsageBit::TRANSFER_SOURCE));
- ANKI_ASSERT(static_cast<const BufferImpl&>(*dst).usageValid(BufferUsageBit::TRANSFER_DESTINATION));
- ANKI_ASSERT(srcOffset + range <= src->getSize());
- ANKI_ASSERT(dstOffset + range <= dst->getSize());
- commandCommon();
- VkBufferCopy region = {};
- region.srcOffset = srcOffset;
- region.dstOffset = dstOffset;
- region.size = range;
- ANKI_CMD(vkCmdCopyBuffer(m_handle, static_cast<const BufferImpl&>(*src).getHandle(),
- static_cast<const BufferImpl&>(*dst).getHandle(), 1, ®ion),
- ANY_OTHER_COMMAND);
- m_microCmdb->pushObjectRef(src);
- m_microCmdb->pushObjectRef(dst);
- }
- inline Bool CommandBufferImpl::flipViewport() const
- {
- return static_cast<const FramebufferImpl&>(*m_activeFb).hasPresentableTexture();
- }
- inline void CommandBufferImpl::setPushConstants(const void* data, U32 dataSize)
- {
- ANKI_ASSERT(data && dataSize && dataSize % 16 == 0);
- const ShaderProgramImpl& prog = getBoundProgram();
- ANKI_ASSERT(prog.getReflectionInfo().m_pushConstantsSize == dataSize
- && "The bound program should have push constants equal to the \"dataSize\" parameter");
- commandCommon();
- ANKI_CMD(vkCmdPushConstants(m_handle, prog.getPipelineLayout().getHandle(), VK_SHADER_STAGE_ALL, 0, dataSize, data),
- ANY_OTHER_COMMAND);
- #if ANKI_EXTRA_CHECKS
- m_setPushConstantsSize = dataSize;
- #endif
- }
- inline void CommandBufferImpl::setRasterizationOrder(RasterizationOrder order)
- {
- commandCommon();
- if(!!(getGrManagerImpl().getExtensions() & VulkanExtensions::AMD_RASTERIZATION_ORDER))
- {
- m_state.setRasterizationOrder(order);
- }
- }
- inline void CommandBufferImpl::setLineWidth(F32 width)
- {
- commandCommon();
- vkCmdSetLineWidth(m_handle, width);
- #if ANKI_ENABLE_ASSERTIONS
- m_lineWidthSet = true;
- #endif
- }
- } // end namespace anki
|