diff --git a/filament/backend/src/vulkan/VulkanBlitter.cpp b/filament/backend/src/vulkan/VulkanBlitter.cpp index db68b94b58b..85f83d8287b 100644 --- a/filament/backend/src/vulkan/VulkanBlitter.cpp +++ b/filament/backend/src/vulkan/VulkanBlitter.cpp @@ -126,8 +126,7 @@ struct BlitterUniforms { }// anonymous namespace VulkanBlitter::VulkanBlitter(VkPhysicalDevice physicalDevice, VulkanCommands* commands) noexcept - : mPhysicalDevice(physicalDevice), - mCommands(commands) {} + : mPhysicalDevice(physicalDevice), mCommands(commands) {} void VulkanBlitter::resolve(VulkanAttachment dst, VulkanAttachment src) { @@ -151,7 +150,8 @@ void VulkanBlitter::resolve(VulkanAttachment dst, VulkanAttachment src) { } #endif - VulkanCommandBuffer& commands = mCommands->get(); + VulkanCommandBuffer& commands = dst.texture->getIsProtected() ? + mCommands->getProtected() : mCommands->get(); commands.acquire(src.texture); commands.acquire(dst.texture); resolveFast(&commands, aspect, src, dst); @@ -176,7 +176,8 @@ void VulkanBlitter::blit(VkFilter filter, #endif // src and dst should have the same aspect here VkImageAspectFlags const aspect = src.texture->getImageAspect(); - VulkanCommandBuffer& commands = mCommands->get(); + VulkanCommandBuffer& commands = dst.texture->getIsProtected() ? + mCommands->getProtected() : mCommands->get(); commands.acquire(src.texture); commands.acquire(dst.texture); blitFast(&commands, aspect, filter, src, dst, srcRectPair, dstRectPair); diff --git a/filament/backend/src/vulkan/VulkanContext.h b/filament/backend/src/vulkan/VulkanContext.h index 68c44dfdcee..902cb33ac7a 100644 --- a/filament/backend/src/vulkan/VulkanContext.h +++ b/filament/backend/src/vulkan/VulkanContext.h @@ -82,6 +82,8 @@ class VulkanTimestamps { }; struct VulkanRenderPass { + // Between the begin and end command render pass we cache the command buffer + VulkanCommandBuffer* commandBuffer; VulkanRenderTarget* renderTarget; VkRenderPass renderPass; RenderPassParams params; diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index bb72633af65..e77efb602ed 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -201,8 +201,8 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex mResourceManager(&mResourceAllocator), mThreadSafeResourceManager(&mResourceAllocator), mCommands(mPlatform->getDevice(), mPlatform->getGraphicsQueue(), - mPlatform->getGraphicsQueueFamilyIndex(), - nullptr, 0, &mContext, &mResourceAllocator), + mPlatform->getGraphicsQueueFamilyIndex(), mPlatform->getProtectedGraphicsQueue(), + mPlatform->getProtectedGraphicsQueueFamilyIndex(), &mContext, &mResourceAllocator), mPipelineLayoutCache(mPlatform->getDevice(), &mResourceAllocator), mPipelineCache(mPlatform->getDevice(), mAllocator), mStagePool(mAllocator, &mCommands), @@ -682,7 +682,12 @@ void VulkanDriver::destroyRenderTarget(Handle rth) { } void VulkanDriver::createFenceR(Handle fh, int) { - VulkanCommandBuffer* cmdbuf = &mCommands.get(); + VulkanCommandBuffer* cmdbuf; + if (mCurrentRenderPass.commandBuffer) { + cmdbuf = mCurrentRenderPass.commandBuffer; + } else { + cmdbuf = &mCommands.get(); + } mResourceAllocator.construct(fh, cmdbuf->getFenceStatus()); } @@ -695,6 +700,13 @@ void VulkanDriver::createSwapChainR(Handle sch, void* nativeWindow, auto swapChain = mResourceAllocator.construct(sch, mPlatform, mContext, mAllocator, &mCommands, &mResourceAllocator, mStagePool, nativeWindow, flags); mResourceManager.acquire(swapChain); + + if (flags & backend::SWAP_CHAIN_CONFIG_PROTECTED_CONTENT) { + if (!isProtectedContentSupported()) { + utils::slog.w << "protected swapchain requested, but Vulkan does not support it" + << utils::io::endl; + } + } } void VulkanDriver::createSwapChainHeadlessR(Handle sch, uint32_t width, @@ -1236,6 +1248,9 @@ void VulkanDriver::beginRenderPass(Handle rth, const RenderPassP VkExtent2D const& extent = rt->getExtent(); assert_invariant(rt == mDefaultRenderTarget || extent.width > 0 && extent.height > 0); + VulkanCommandBuffer* commandBuffer = rt->isProtected() ? + &mCommands.getProtected() : &mCommands.get(); + // Filament has the expectation that the contents of the swap chain are not preserved on the // first render pass. Note however that its contents are often preserved on subsequent render // passes, due to multiple views. @@ -1260,8 +1275,7 @@ void VulkanDriver::beginRenderPass(Handle rth, const RenderPassP // If that's the case, we need to change the layout of the texture to DEPTH_SAMPLER, which is a // more general layout. Otherwise, we prefer the DEPTH_ATTACHMENT layout, which is optimal for // the non-sampling case. - VulkanCommandBuffer& commands = mCommands.get(); - VkCommandBuffer const cmdbuffer = commands.buffer(); + VkCommandBuffer const cmdbuffer = commandBuffer->buffer(); // Scissor is reset with each render pass // This also takes care of VUID-vkCmdDrawIndexed-None-07832. @@ -1296,7 +1310,7 @@ void VulkanDriver::beginRenderPass(Handle rth, const RenderPassP fbkey.renderPass = renderPass; fbkey.layers = 1; - rt->emitBarriersBeginRenderPass(commands); + rt->emitBarriersBeginRenderPass(*commandBuffer); VkFramebuffer vkfb = mFramebufferCache.getFramebuffer(fbkey); @@ -1310,7 +1324,7 @@ void VulkanDriver::beginRenderPass(Handle rth, const RenderPassP #endif // The current command buffer now has references to the render target and its attachments. - commands.acquire(rt); + commandBuffer->acquire(rt); // Populate the structures required for vkCmdBeginRenderPass. VkRenderPassBeginInfo renderPassInfo { @@ -1369,6 +1383,7 @@ void VulkanDriver::beginRenderPass(Handle rth, const RenderPassP vkCmdSetViewport(cmdbuffer, 0, 1, &viewport); mCurrentRenderPass = { + .commandBuffer = commandBuffer, .renderTarget = rt, .renderPass = renderPassInfo.renderPass, .params = params, @@ -1379,8 +1394,7 @@ void VulkanDriver::beginRenderPass(Handle rth, const RenderPassP void VulkanDriver::endRenderPass(int) { FVK_SYSTRACE_SCOPE(); - VulkanCommandBuffer& commands = mCommands.get(); - VkCommandBuffer cmdbuffer = commands.buffer(); + VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer(); vkCmdEndRenderPass(cmdbuffer); VulkanRenderTarget* rt = mCurrentRenderPass.renderTarget; @@ -1388,11 +1402,13 @@ void VulkanDriver::endRenderPass(int) { // Since we might soon be sampling from the render target that we just wrote to, we need a // pipeline barrier between framebuffer writes and shader reads. - rt->emitBarriersEndRenderPass(commands); + rt->emitBarriersEndRenderPass(*mCurrentRenderPass.commandBuffer); mRenderPassFboInfo = {}; mCurrentRenderPass.renderTarget = nullptr; mCurrentRenderPass.renderPass = VK_NULL_HANDLE; + + mCurrentRenderPass.commandBuffer = nullptr; } void VulkanDriver::nextSubpass(int) { @@ -1403,7 +1419,8 @@ void VulkanDriver::nextSubpass(int) { assert_invariant(renderTarget); assert_invariant(mCurrentRenderPass.params.subpassMask); - vkCmdNextSubpass(mCommands.get().buffer(), VK_SUBPASS_CONTENTS_INLINE); + vkCmdNextSubpass(mCurrentRenderPass.commandBuffer->buffer(), + VK_SUBPASS_CONTENTS_INLINE); mPipelineCache.bindRenderPass(mCurrentRenderPass.renderPass, ++mCurrentRenderPass.currentSubpass); @@ -1446,9 +1463,8 @@ void VulkanDriver::commit(Handle sch) { void VulkanDriver::setPushConstant(backend::ShaderStage stage, uint8_t index, backend::PushConstantVariant value) { assert_invariant(mBoundPipeline.program && "Expect a program when writing to push constants"); - VulkanCommands* commands = &mCommands; - mBoundPipeline.program->writePushConstant(commands, mBoundPipeline.pipelineLayout, stage, index, - value); + mBoundPipeline.program->writePushConstant(mCurrentRenderPass.commandBuffer, + mBoundPipeline.pipelineLayout, stage, index, value); } void VulkanDriver::insertEventMarker(char const* string) { @@ -1628,7 +1644,6 @@ void VulkanDriver::blitDEPRECATED(TargetBufferFlags buffers, void VulkanDriver::bindPipeline(PipelineState const& pipelineState) { FVK_SYSTRACE_SCOPE(); - VulkanCommandBuffer* commands = &mCommands.get(); const VulkanVertexBufferInfo& vbi = *mResourceAllocator.handle_cast(pipelineState.vertexBufferInfo); @@ -1637,7 +1652,7 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) { PolygonOffset const& depthOffset = pipelineState.polygonOffset; auto* program = mResourceAllocator.handle_cast(programHandle); - commands->acquire(program); + mCurrentRenderPass.commandBuffer->acquire(program); // Update the VK raster state. const VulkanRenderTarget* rt = mCurrentRenderPass.renderTarget; @@ -1701,17 +1716,16 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) { }; mPipelineCache.bindLayout(pipelineLayout); - mPipelineCache.bindPipeline(commands); + mPipelineCache.bindPipeline(mCurrentRenderPass.commandBuffer); } void VulkanDriver::bindRenderPrimitive(Handle rph) { FVK_SYSTRACE_SCOPE(); - VulkanCommandBuffer* commands = &mCommands.get(); - VkCommandBuffer cmdbuffer = commands->buffer(); + VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer(); const VulkanRenderPrimitive& prim = *mResourceAllocator.handle_cast(rph); - commands->acquire(prim.indexBuffer); - commands->acquire(prim.vertexBuffer); + mCurrentRenderPass.commandBuffer->acquire(prim.indexBuffer); + mCurrentRenderPass.commandBuffer->acquire(prim.vertexBuffer); // This *must* match the VulkanVertexBufferInfo that was bound in bindPipeline(). But we want // to allow to call this before bindPipeline(), so the validation can only happen in draw() @@ -1744,11 +1758,10 @@ void VulkanDriver::bindDescriptorSet( void VulkanDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) { FVK_SYSTRACE_SCOPE(); + VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer(); - VulkanCommandBuffer& commands = mCommands.get(); - VkCommandBuffer cmdbuffer = commands.buffer(); - - mDescriptorSetManager.commit(&commands, mBoundPipeline.pipelineLayout, + mDescriptorSetManager.commit(mCurrentRenderPass.commandBuffer, + mBoundPipeline.pipelineLayout, mBoundPipeline.descriptorSetMask); // Finally, make the actual draw call. TODO: support subranges @@ -1774,8 +1787,7 @@ void VulkanDriver::dispatchCompute(Handle program, math::uint3 workGr } void VulkanDriver::scissor(Viewport scissorBox) { - VulkanCommandBuffer& commands = mCommands.get(); - VkCommandBuffer cmdbuffer = commands.buffer(); + VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer(); // TODO: it's a common case that scissor() is called with (0, 0, maxint, maxint) // we should maybe have a fast path for this and avoid vkCmdSetScissor() if possible diff --git a/filament/backend/src/vulkan/VulkanHandles.cpp b/filament/backend/src/vulkan/VulkanHandles.cpp index 9fda018943b..a2df51edc29 100644 --- a/filament/backend/src/vulkan/VulkanHandles.cpp +++ b/filament/backend/src/vulkan/VulkanHandles.cpp @@ -164,9 +164,9 @@ PushConstantDescription::PushConstantDescription(backend::Program const& program } } -void PushConstantDescription::write(VulkanCommands* commands, VkPipelineLayout layout, +void PushConstantDescription::write(VulkanCommandBuffer* cmdbuf, VkPipelineLayout layout, backend::ShaderStage stage, uint8_t index, backend::PushConstantVariant const& value) { - VulkanCommandBuffer* cmdbuf = &(commands->get()); + uint32_t binaryValue = 0; UTILS_UNUSED_IN_RELEASE auto const& types = mTypes[(uint8_t) stage]; if (std::holds_alternative(value)) { @@ -340,6 +340,8 @@ VulkanRenderTarget::VulkanRenderTarget(VkDevice device, VkPhysicalDevice physica continue; } + mProtected |= texture->getIsProtected(); + attachments.push_back(attachment); mInfo->colors.set(index); diff --git a/filament/backend/src/vulkan/VulkanHandles.h b/filament/backend/src/vulkan/VulkanHandles.h index 1dc3141fd5a..4b573796c79 100644 --- a/filament/backend/src/vulkan/VulkanHandles.h +++ b/filament/backend/src/vulkan/VulkanHandles.h @@ -185,7 +185,7 @@ struct PushConstantDescription { uint32_t getVkRangeCount() const noexcept { return mRangeCount; } - void write(VulkanCommands* commands, VkPipelineLayout layout, backend::ShaderStage stage, + void write(VulkanCommandBuffer* cmdbuf, VkPipelineLayout layout, backend::ShaderStage stage, uint8_t index, backend::PushConstantVariant const& value); private: @@ -218,9 +218,9 @@ struct VulkanProgram : public HwProgram, VulkanResource { return mInfo->pushConstantDescription.getVkRanges(); } - inline void writePushConstant(VulkanCommands* commands, VkPipelineLayout layout, + inline void writePushConstant(VulkanCommandBuffer* cmdbuf, VkPipelineLayout layout, backend::ShaderStage stage, uint8_t index, backend::PushConstantVariant const& value) { - mInfo->pushConstantDescription.write(commands, layout, stage, index, value); + mInfo->pushConstantDescription.write(cmdbuf, layout, stage, index, value); } #if FVK_ENABLED_DEBUG_SAMPLER_NAME diff --git a/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp b/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp index 3037f64af74..ed9ba2281b9 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp @@ -29,7 +29,8 @@ namespace filament::backend { namespace { std::tuple createImageAndMemory(VulkanContext const& context, - VkDevice device, VkExtent2D extent, VkFormat format) { + VkDevice device, VkExtent2D extent, VkFormat format, + bool isProtected) { bool const isDepth = isVkDepthFormat(format); // Filament expects blit() to work with any texture, so we almost always set these usage flags // (see copyFrame() and readPixels()). @@ -38,6 +39,7 @@ std::tuple createImageAndMemory(VulkanContext const& co VkImageCreateInfo imageInfo { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .flags = isProtected ? VK_IMAGE_CREATE_PROTECTED_BIT : VkImageCreateFlags(0), .imageType = VK_IMAGE_TYPE_2D, .format = format, .extent = {extent.width, extent.height, 1}, @@ -58,8 +60,11 @@ std::tuple createImageAndMemory(VulkanContext const& co VkMemoryRequirements memReqs; vkGetImageMemoryRequirements(device, image, &memReqs); + const VkFlags requiredMemoryFlags = + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + (isProtected ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0U); uint32_t memoryTypeIndex - = context.selectMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + = context.selectMemoryType(memReqs.memoryTypeBits, requiredMemoryFlags); FILAMENT_CHECK_POSTCONDITION(memoryTypeIndex < VK_MAX_MEMORY_TYPES) << "VulkanPlatformSwapChainImpl: unable to find a memory type that meets requirements."; @@ -110,8 +115,9 @@ void VulkanPlatformSwapChainImpl::destroy() { mSwapChainBundle.colors.clear(); } -VkImage VulkanPlatformSwapChainImpl::createImage(VkExtent2D extent, VkFormat format) { - auto [image, memory] = createImageAndMemory(mContext, mDevice, extent, format); +VkImage VulkanPlatformSwapChainImpl::createImage(VkExtent2D extent, VkFormat format, + bool isProtected) { + auto [image, memory] = createImageAndMemory(mContext, mDevice, extent, format, isProtected); mMemory.insert({image, memory}); return image; } @@ -248,7 +254,8 @@ VkResult VulkanPlatformSurfaceSwapChain::create() { mSwapChainBundle.colorFormat = surfaceFormat.format; mSwapChainBundle.depthFormat = selectDepthFormat(mContext.getAttachmentDepthStencilFormats(), mHasStencil); - mSwapChainBundle.depth = createImage(mSwapChainBundle.extent, mSwapChainBundle.depthFormat); + mSwapChainBundle.depth = createImage(mSwapChainBundle.extent, + mSwapChainBundle.depthFormat, mIsProtected); mSwapChainBundle.isProtected = mIsProtected; FVK_LOGI << "vkCreateSwapchain" @@ -356,13 +363,13 @@ VulkanPlatformHeadlessSwapChain::VulkanPlatformHeadlessSwapChain(VulkanContext c images.reserve(HEADLESS_SWAPCHAIN_SIZE); images.resize(HEADLESS_SWAPCHAIN_SIZE); for (size_t i = 0; i < HEADLESS_SWAPCHAIN_SIZE; ++i) { - images[i] = createImage(extent, mSwapChainBundle.colorFormat); + images[i] = createImage(extent, mSwapChainBundle.colorFormat, false); } bool const hasStencil = (flags & backend::SWAP_CHAIN_HAS_STENCIL_BUFFER) != 0; mSwapChainBundle.depthFormat = selectDepthFormat(mContext.getAttachmentDepthStencilFormats(), hasStencil); - mSwapChainBundle.depth = createImage(extent, mSwapChainBundle.depthFormat); + mSwapChainBundle.depth = createImage(extent, mSwapChainBundle.depthFormat, false); } VulkanPlatformHeadlessSwapChain::~VulkanPlatformHeadlessSwapChain() { diff --git a/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.h b/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.h index 2a715a210c2..ff1179d4ec3 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.h +++ b/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.h @@ -73,7 +73,7 @@ struct VulkanPlatformSwapChainImpl : public Platform::SwapChain { // Non-virtual override-able method void destroy(); - VkImage createImage(VkExtent2D extent, VkFormat format); + VkImage createImage(VkExtent2D extent, VkFormat format, bool isProtected); VulkanContext const& mContext; VkDevice mDevice;