diff --git a/src/rendering/vulkan/renderer/vk_renderpass.cpp b/src/rendering/vulkan/renderer/vk_renderpass.cpp index 17186e3ab7..a5d1d9c80f 100644 --- a/src/rendering/vulkan/renderer/vk_renderpass.cpp +++ b/src/rendering/vulkan/renderer/vk_renderpass.cpp @@ -23,6 +23,7 @@ #include "vk_renderpass.h" #include "vk_renderbuffers.h" #include "vk_renderstate.h" +#include "vulkan/textures/vk_samplers.h" #include "vulkan/shaders/vk_shader.h" #include "vulkan/system/vk_builders.h" #include "vulkan/system/vk_framebuffer.h" @@ -45,6 +46,7 @@ void VkRenderPassManager::Init() CreateDynamicSetLayout(); CreateDescriptorPool(); CreateDynamicSet(); + CreateNullTexture(); } void VkRenderPassManager::RenderBuffersReset() @@ -63,6 +65,7 @@ void VkRenderPassManager::TextureSetPoolReset() deleteList.DescriptorPools.push_back(std::move(desc)); } } + NullTextureDescriptorSet.reset(); TextureDescriptorPools.clear(); TextureDescriptorSetsLeft = 0; TextureDescriptorsLeft = 0; @@ -187,6 +190,42 @@ void VkRenderPassManager::CreateDynamicSet() I_FatalError("CreateDynamicSet failed.\n"); } +void VkRenderPassManager::CreateNullTexture() +{ + auto fb = GetVulkanFrameBuffer(); + + ImageBuilder imgbuilder; + imgbuilder.setFormat(VK_FORMAT_R8G8B8A8_UNORM); + imgbuilder.setSize(1, 1); + imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT); + NullTexture = imgbuilder.create(fb->device); + NullTexture->SetDebugName("VkRenderPassManager.NullTexture"); + + ImageViewBuilder viewbuilder; + viewbuilder.setImage(NullTexture.get(), VK_FORMAT_R8G8B8A8_UNORM); + NullTextureView = viewbuilder.create(fb->device); + NullTextureView->SetDebugName("VkRenderPassManager.NullTextureView"); + + PipelineBarrier barrier; + barrier.addImage(NullTexture.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT); + barrier.execute(fb->GetTransferCommands(), VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); +} + +VulkanDescriptorSet* VkRenderPassManager::GetNullTextureDescriptorSet() +{ + if (!NullTextureDescriptorSet) + { + NullTextureDescriptorSet = AllocateTextureDescriptorSet(1); + + auto fb = GetVulkanFrameBuffer(); + WriteDescriptors update; + update.addCombinedImageSampler(NullTextureDescriptorSet.get(), 0, NullTextureView.get(), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + update.updateSets(fb->device); + } + + return NullTextureDescriptorSet.get(); +} + void VkRenderPassManager::UpdateDynamicSet() { auto fb = GetVulkanFrameBuffer(); diff --git a/src/rendering/vulkan/renderer/vk_renderpass.h b/src/rendering/vulkan/renderer/vk_renderpass.h index 85c89266d7..47b21769a0 100644 --- a/src/rendering/vulkan/renderer/vk_renderpass.h +++ b/src/rendering/vulkan/renderer/vk_renderpass.h @@ -93,6 +93,8 @@ public: std::unique_ptr AllocateTextureDescriptorSet(int numLayers); VulkanPipelineLayout* GetPipelineLayout(int numLayers); + VulkanDescriptorSet* GetNullTextureDescriptorSet(); + std::unique_ptr DynamicSetLayout; std::map> RenderPassSetup; @@ -102,6 +104,7 @@ private: void CreateDynamicSetLayout(); void CreateDescriptorPool(); void CreateDynamicSet(); + void CreateNullTexture(); VulkanDescriptorSetLayout *GetTextureSetLayout(int numLayers); @@ -112,4 +115,8 @@ private: std::vector> TextureSetLayouts; std::vector> PipelineLayouts; std::vector VertexFormats; + + std::unique_ptr NullTexture; + std::unique_ptr NullTextureView; + std::unique_ptr NullTextureDescriptorSet; }; diff --git a/src/rendering/vulkan/renderer/vk_renderstate.cpp b/src/rendering/vulkan/renderer/vk_renderstate.cpp index 3581862e89..abf2ba12a6 100644 --- a/src/rendering/vulkan/renderer/vk_renderstate.cpp +++ b/src/rendering/vulkan/renderer/vk_renderstate.cpp @@ -228,7 +228,7 @@ void VkRenderState::ApplyRenderPass(int dt) pipelineKey.StencilPassOp = mStencilOp; pipelineKey.ColorMask = mColorMask; pipelineKey.CullMode = mCullMode; - pipelineKey.NumTextureLayers = mMaterial.mMaterial ? mMaterial.mMaterial->GetLayers() : 0; + pipelineKey.NumTextureLayers = mMaterial.mMaterial ? mMaterial.mMaterial->GetLayers() : 1; // Always force minimum 1 texture as the shader requires it if (mSpecialEffect > EFF_NONE) { pipelineKey.SpecialEffect = mSpecialEffect; @@ -423,16 +423,15 @@ void VkRenderState::ApplyVertexBuffers() void VkRenderState::ApplyMaterial() { - if (mMaterial.mChanged && mMaterial.mMaterial) + if (mMaterial.mChanged) { - auto base = static_cast(mMaterial.mMaterial->GetLayer(0, mMaterial.mTranslation)); - if (base) - { - auto fb = GetVulkanFrameBuffer(); - auto passManager = fb->GetRenderPassManager(); - mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 1, base->GetDescriptorSet(mMaterial)); - } + auto fb = GetVulkanFrameBuffer(); + auto passManager = fb->GetRenderPassManager(); + VkHardwareTexture* base = mMaterial.mMaterial ? static_cast(mMaterial.mMaterial->GetLayer(0, mMaterial.mTranslation)) : nullptr; + VulkanDescriptorSet* descriptorset = base ? base->GetDescriptorSet(mMaterial) : passManager->GetNullTextureDescriptorSet(); + + mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 1, descriptorset); mMaterial.mChanged = false; } }