[Impeller] Wire image sampler descriptors for Vulkan (#36641)
diff --git a/impeller/compiler/code_gen_template.h b/impeller/compiler/code_gen_template.h
index 2de845d..f399084 100644
--- a/impeller/compiler/code_gen_template.h
+++ b/impeller/compiler/code_gen_template.h
@@ -107,6 +107,8 @@
"{{sampled_image.name}}", // name
{{sampled_image.ext_res_0}}u, // texture
{{sampled_image.ext_res_1}}u, // sampler
+ {{sampled_image.binding}}u, // binding
+ {{sampled_image.set}}u, // set
};
static ShaderMetadata kMetadata{{camel_case(sampled_image.name)}};
{% endfor %}
diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc
index 720c310..de0d338 100644
--- a/impeller/renderer/backend/vulkan/allocator_vk.cc
+++ b/impeller/renderer/backend/vulkan/allocator_vk.cc
@@ -26,7 +26,7 @@
const vk::Instance& instance,
PFN_vkGetInstanceProcAddr get_instance_proc_address,
PFN_vkGetDeviceProcAddr get_device_proc_address)
- : context_(context) {
+ : context_(context), device_(logical_device) {
VmaVulkanFunctions proc_table = {};
proc_table.vkGetInstanceProcAddr = get_instance_proc_address;
proc_table.vkGetDeviceProcAddr = get_device_proc_address;
@@ -100,6 +100,22 @@
return nullptr;
}
+ vk::ImageViewCreateInfo view_create_info = {};
+ view_create_info.image = img;
+ view_create_info.viewType = vk::ImageViewType::e2D;
+ view_create_info.format = image_create_info.format;
+ view_create_info.subresourceRange.aspectMask =
+ vk::ImageAspectFlagBits::eColor;
+ view_create_info.subresourceRange.levelCount = image_create_info.mipLevels;
+ view_create_info.subresourceRange.layerCount = image_create_info.arrayLayers;
+
+ auto img_view_res = device_.createImageView(view_create_info);
+ if (img_view_res.result != vk::Result::eSuccess) {
+ VALIDATION_LOG << "Unable to create an image view: "
+ << vk::to_string(img_view_res.result);
+ return nullptr;
+ }
+
auto texture_info = std::make_unique<TextureInfoVK>(TextureInfoVK{
.backing_type = TextureBackingTypeVK::kAllocatedTexture,
.allocated_texture =
@@ -108,6 +124,7 @@
.allocation = allocation,
.allocation_info = allocation_info,
.image = img,
+ .image_view = img_view_res.value,
},
});
return std::make_shared<TextureVK>(desc, &context_, std::move(texture_info));
diff --git a/impeller/renderer/backend/vulkan/allocator_vk.h b/impeller/renderer/backend/vulkan/allocator_vk.h
index a5ac445..5225845 100644
--- a/impeller/renderer/backend/vulkan/allocator_vk.h
+++ b/impeller/renderer/backend/vulkan/allocator_vk.h
@@ -23,6 +23,7 @@
VmaAllocator allocator_ = {};
ContextVK& context_;
+ vk::Device device_;
bool is_valid_ = false;
AllocatorVK(ContextVK& context,
diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.cc b/impeller/renderer/backend/vulkan/render_pass_vk.cc
index 4beb8c1..1179f2d 100644
--- a/impeller/renderer/backend/vulkan/render_pass_vk.cc
+++ b/impeller/renderer/backend/vulkan/render_pass_vk.cc
@@ -13,9 +13,13 @@
#include "impeller/renderer/backend/vulkan/device_buffer_vk.h"
#include "impeller/renderer/backend/vulkan/formats_vk.h"
#include "impeller/renderer/backend/vulkan/pipeline_vk.h"
+#include "impeller/renderer/backend/vulkan/sampler_vk.h"
#include "impeller/renderer/backend/vulkan/surface_producer_vk.h"
#include "impeller/renderer/backend/vulkan/texture_vk.h"
+#include "impeller/renderer/sampler.h"
#include "impeller/renderer/shader_types.h"
+#include "vulkan/vulkan_enums.hpp"
+#include "vulkan/vulkan_structs.hpp"
namespace impeller {
@@ -77,52 +81,10 @@
const uint32_t frame_num = tex_info.frame_num;
// layout transition.
- {
- auto pool = command_buffer_.getPool();
- vk::CommandBufferAllocateInfo alloc_info =
- vk::CommandBufferAllocateInfo()
- .setCommandPool(pool)
- .setLevel(vk::CommandBufferLevel::ePrimary)
- .setCommandBufferCount(1);
- auto cmd_buf_res = device_.allocateCommandBuffersUnique(alloc_info);
- if (cmd_buf_res.result != vk::Result::eSuccess) {
- VALIDATION_LOG << "Failed to allocate command buffer: "
- << vk::to_string(cmd_buf_res.result);
- return false;
- }
- auto transition_cmd = std::move(cmd_buf_res.value[0]);
-
- vk::CommandBufferBeginInfo begin_info;
- auto res = transition_cmd->begin(begin_info);
-
- vk::ImageMemoryBarrier barrier =
- vk::ImageMemoryBarrier()
- .setSrcAccessMask(vk::AccessFlagBits::eColorAttachmentRead)
- .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentWrite)
- .setOldLayout(vk::ImageLayout::eUndefined)
- .setNewLayout(vk::ImageLayout::eColorAttachmentOptimal)
- .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
- .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
- .setImage(tex_info.swapchain_image->GetImage())
- .setSubresourceRange(
- vk::ImageSubresourceRange()
- .setAspectMask(vk::ImageAspectFlagBits::eColor)
- .setBaseMipLevel(0)
- .setLevelCount(1)
- .setBaseArrayLayer(0)
- .setLayerCount(1));
- transition_cmd->pipelineBarrier(
- vk::PipelineStageFlagBits::eColorAttachmentOutput,
- vk::PipelineStageFlagBits::eColorAttachmentOutput, {}, nullptr, nullptr,
- barrier);
-
- res = transition_cmd->end();
- if (res != vk::Result::eSuccess) {
- VALIDATION_LOG << "Failed to end command buffer: " << vk::to_string(res);
- return false;
- }
-
- surface_producer_->QueueCommandBuffer(frame_num, std::move(transition_cmd));
+ if (!TransitionImageLayout(frame_num, tex_info.swapchain_image->GetImage(),
+ vk::ImageLayout::eUndefined,
+ vk::ImageLayout::eColorAttachmentOptimal)) {
+ return false;
}
vk::ClearValue clear_value;
@@ -162,7 +124,7 @@
continue;
}
- if (!EncodeCommand(context, command)) {
+ if (!EncodeCommand(frame_num, context, command)) {
return false;
}
}
@@ -188,14 +150,16 @@
return false;
}
-bool RenderPassVK::EncodeCommand(const Context& context,
+bool RenderPassVK::EncodeCommand(uint32_t frame_num,
+ const Context& context,
const Command& command) const {
SetViewportAndScissor(command);
auto& pipeline_vk = PipelineVK::Cast(*command.pipeline);
PipelineCreateInfoVK* pipeline_create_info = pipeline_vk.GetCreateInfo();
- if (!AllocateAndBindDescriptorSets(context, command, pipeline_create_info)) {
+ if (!AllocateAndBindDescriptorSets(frame_num, context, command,
+ pipeline_create_info)) {
return false;
}
@@ -243,6 +207,7 @@
}
bool RenderPassVK::AllocateAndBindDescriptorSets(
+ uint32_t frame_num,
const Context& context,
const Command& command,
PipelineCreateInfoVK* pipeline_create_info) const {
@@ -269,13 +234,15 @@
}
auto desc_sets = desc_sets_res.value;
- bool update_vertex_descriptors = UpdateDescriptorSets(
- "vertex_bindings", command.vertex_bindings, allocator, desc_sets[0]);
+ bool update_vertex_descriptors =
+ UpdateDescriptorSets(frame_num, "vertex_bindings",
+ command.vertex_bindings, allocator, desc_sets[0]);
if (!update_vertex_descriptors) {
return false;
}
- bool update_frag_descriptors = UpdateDescriptorSets(
- "fragment_bindings", command.fragment_bindings, allocator, desc_sets[0]);
+ bool update_frag_descriptors =
+ UpdateDescriptorSets(frame_num, "fragment_bindings",
+ command.fragment_bindings, allocator, desc_sets[0]);
if (!update_frag_descriptors) {
return false;
}
@@ -285,12 +252,15 @@
return true;
}
-bool RenderPassVK::UpdateDescriptorSets(const char* label,
+bool RenderPassVK::UpdateDescriptorSets(uint32_t frame_num,
+ const char* label,
const Bindings& bindings,
Allocator& allocator,
vk::DescriptorSet desc_set) const {
std::vector<vk::WriteDescriptorSet> writes;
std::vector<vk::DescriptorBufferInfo> buffer_infos;
+ std::vector<vk::DescriptorImageInfo> image_infos;
+
for (const auto& [buffer_index, view] : bindings.buffers) {
const auto& buffer_view = view.resource.buffer;
@@ -330,6 +300,42 @@
writes.push_back(setWrite);
}
+ for (const auto& [index, sampler_handle] : bindings.samplers) {
+ if (bindings.textures.find(index) == bindings.textures.end()) {
+ VALIDATION_LOG << "Missing texture for sampler: " << index;
+ return false;
+ }
+
+ const auto& texture_vk =
+ TextureVK::Cast(*bindings.textures.at(index).resource);
+
+ const Sampler& sampler = *sampler_handle.resource;
+ const SamplerVK& sampler_vk = SamplerVK::Cast(sampler);
+
+ const SampledImageSlot& slot = bindings.sampled_images.at(index);
+
+ if (!TransitionImageLayout(frame_num, texture_vk.GetImage(),
+ vk::ImageLayout::eUndefined,
+ vk::ImageLayout::eGeneral)) {
+ return false;
+ }
+
+ vk::DescriptorImageInfo desc_image_info;
+ desc_image_info.setImageLayout(vk::ImageLayout::eGeneral);
+ desc_image_info.setSampler(sampler_vk.GetSamplerVK());
+ desc_image_info.setImageView(texture_vk.GetImageView());
+ image_infos.push_back(desc_image_info);
+
+ vk::WriteDescriptorSet setWrite;
+ setWrite.setDstSet(desc_set);
+ setWrite.setDstBinding(slot.binding);
+ setWrite.setDescriptorCount(1);
+ setWrite.setDescriptorType(vk::DescriptorType::eCombinedImageSampler);
+ setWrite.setPImageInfo(&image_infos.back());
+
+ writes.push_back(setWrite);
+ }
+
std::array<vk::CopyDescriptorSet, 0> copies;
device_.updateDescriptorSets(writes, copies);
@@ -374,4 +380,56 @@
return std::move(res.value);
}
+bool RenderPassVK::TransitionImageLayout(uint32_t frame_num,
+ vk::Image image,
+ vk::ImageLayout layout_old,
+ vk::ImageLayout layout_new) const {
+ auto pool = command_buffer_.getPool();
+ vk::CommandBufferAllocateInfo alloc_info =
+ vk::CommandBufferAllocateInfo()
+ .setCommandPool(pool)
+ .setLevel(vk::CommandBufferLevel::ePrimary)
+ .setCommandBufferCount(1);
+ auto cmd_buf_res = device_.allocateCommandBuffersUnique(alloc_info);
+ if (cmd_buf_res.result != vk::Result::eSuccess) {
+ VALIDATION_LOG << "Failed to allocate command buffer: "
+ << vk::to_string(cmd_buf_res.result);
+ return false;
+ }
+ auto transition_cmd = std::move(cmd_buf_res.value[0]);
+
+ vk::CommandBufferBeginInfo begin_info;
+ auto res = transition_cmd->begin(begin_info);
+
+ vk::ImageMemoryBarrier barrier =
+ vk::ImageMemoryBarrier()
+ .setSrcAccessMask(vk::AccessFlagBits::eColorAttachmentRead)
+ .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentWrite)
+ .setOldLayout(layout_old)
+ .setNewLayout(layout_new)
+ .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
+ .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
+ .setImage(image)
+ .setSubresourceRange(
+ vk::ImageSubresourceRange()
+ .setAspectMask(vk::ImageAspectFlagBits::eColor)
+ .setBaseMipLevel(0)
+ .setLevelCount(1)
+ .setBaseArrayLayer(0)
+ .setLayerCount(1));
+ transition_cmd->pipelineBarrier(
+ vk::PipelineStageFlagBits::eColorAttachmentOutput,
+ vk::PipelineStageFlagBits::eColorAttachmentOutput, {}, nullptr, nullptr,
+ barrier);
+
+ res = transition_cmd->end();
+ if (res != vk::Result::eSuccess) {
+ VALIDATION_LOG << "Failed to end command buffer: " << vk::to_string(res);
+ return false;
+ }
+
+ surface_producer_->QueueCommandBuffer(frame_num, std::move(transition_cmd));
+ return true;
+}
+
} // namespace impeller
diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.h b/impeller/renderer/backend/vulkan/render_pass_vk.h
index c6c551d..3530cbb 100644
--- a/impeller/renderer/backend/vulkan/render_pass_vk.h
+++ b/impeller/renderer/backend/vulkan/render_pass_vk.h
@@ -12,6 +12,7 @@
#include "impeller/renderer/command.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/render_target.h"
+#include "vulkan/vulkan_enums.hpp"
#include "vulkan/vulkan_structs.hpp"
namespace impeller {
@@ -48,16 +49,20 @@
// |RenderPass|
bool OnEncodeCommands(const Context& context) const override;
- bool EncodeCommand(const Context& context, const Command& command) const;
+ bool EncodeCommand(uint32_t frame_num,
+ const Context& context,
+ const Command& command) const;
bool AllocateAndBindDescriptorSets(
+ uint32_t frame_num,
const Context& context,
const Command& command,
PipelineCreateInfoVK* pipeline_create_info) const;
bool EndCommandBuffer(uint32_t frame_num);
- bool UpdateDescriptorSets(const char* label,
+ bool UpdateDescriptorSets(uint32_t frame_num,
+ const char* label,
const Bindings& bindings,
Allocator& allocator,
vk::DescriptorSet desc_set) const;
@@ -67,6 +72,11 @@
vk::Framebuffer CreateFrameBuffer(
const WrappedTextureInfoVK& wrapped_texture_info) const;
+ bool TransitionImageLayout(uint32_t frame_num,
+ vk::Image image,
+ vk::ImageLayout layout_old,
+ vk::ImageLayout layout_new) const;
+
FML_DISALLOW_COPY_AND_ASSIGN(RenderPassVK);
};
diff --git a/impeller/renderer/backend/vulkan/sampler_vk.cc b/impeller/renderer/backend/vulkan/sampler_vk.cc
index 161fa57..6212bed 100644
--- a/impeller/renderer/backend/vulkan/sampler_vk.cc
+++ b/impeller/renderer/backend/vulkan/sampler_vk.cc
@@ -7,8 +7,12 @@
namespace impeller {
SamplerVK::~SamplerVK() {}
+vk::Sampler SamplerVK::GetSamplerVK() const {
+ return sampler_.get();
+}
+
SamplerVK::SamplerVK(SamplerDescriptor desc, vk::UniqueSampler sampler)
- : Sampler(desc), sampler_(std::move(sampler)) {
+ : Sampler(std::move(desc)), sampler_(std::move(sampler)) {
is_valid_ = true;
}
diff --git a/impeller/renderer/backend/vulkan/sampler_vk.h b/impeller/renderer/backend/vulkan/sampler_vk.h
index 15d0820..4c11bd3 100644
--- a/impeller/renderer/backend/vulkan/sampler_vk.h
+++ b/impeller/renderer/backend/vulkan/sampler_vk.h
@@ -21,6 +21,8 @@
// |Sampler|
~SamplerVK() override;
+ vk::Sampler GetSamplerVK() const;
+
private:
friend SamplerLibraryVK;
diff --git a/impeller/renderer/backend/vulkan/texture_vk.cc b/impeller/renderer/backend/vulkan/texture_vk.cc
index 66ad2cf..829cef6 100644
--- a/impeller/renderer/backend/vulkan/texture_vk.cc
+++ b/impeller/renderer/backend/vulkan/texture_vk.cc
@@ -81,6 +81,17 @@
return texture_info_->backing_type == TextureBackingTypeVK::kWrappedTexture;
}
+vk::ImageView TextureVK::GetImageView() const {
+ switch (texture_info_->backing_type) {
+ case TextureBackingTypeVK::kUnknownType:
+ return nullptr;
+ case TextureBackingTypeVK::kAllocatedTexture:
+ return texture_info_->allocated_texture.image_view;
+ case TextureBackingTypeVK::kWrappedTexture:
+ return texture_info_->wrapped_texture.swapchain_image->GetImageView();
+ }
+}
+
vk::Image TextureVK::GetImage() const {
switch (texture_info_->backing_type) {
case TextureBackingTypeVK::kUnknownType:
diff --git a/impeller/renderer/backend/vulkan/texture_vk.h b/impeller/renderer/backend/vulkan/texture_vk.h
index 632e9e7..918ed5f 100644
--- a/impeller/renderer/backend/vulkan/texture_vk.h
+++ b/impeller/renderer/backend/vulkan/texture_vk.h
@@ -29,6 +29,7 @@
VmaAllocation allocation = nullptr;
VmaAllocationInfo allocation_info = {};
VkImage image = nullptr;
+ VkImageView image_view = nullptr;
};
struct TextureInfoVK {
@@ -52,6 +53,8 @@
vk::Image GetImage() const;
+ vk::ImageView GetImageView() const;
+
TextureInfoVK* GetTextureInfo() const;
private:
diff --git a/impeller/renderer/command.cc b/impeller/renderer/command.cc
index cac5108..e5380a8 100644
--- a/impeller/renderer/command.cc
+++ b/impeller/renderer/command.cc
@@ -108,9 +108,11 @@
switch (stage) {
case ShaderStage::kVertex:
vertex_bindings.samplers[slot.sampler_index] = {&metadata, sampler};
+ vertex_bindings.sampled_images[slot.sampler_index] = slot;
return true;
case ShaderStage::kFragment:
fragment_bindings.samplers[slot.sampler_index] = {&metadata, sampler};
+ fragment_bindings.sampled_images[slot.sampler_index] = slot;
return true;
case ShaderStage::kCompute:
VALIDATION_LOG << "Use ComputeCommands for compute shader stages.";
diff --git a/impeller/renderer/command.h b/impeller/renderer/command.h
index c804c0e..3b3d1c0 100644
--- a/impeller/renderer/command.h
+++ b/impeller/renderer/command.h
@@ -42,6 +42,7 @@
struct Bindings {
std::map<size_t, ShaderUniformSlot> uniforms;
+ std::map<size_t, SampledImageSlot> sampled_images;
std::map<size_t, BufferResource> buffers;
std::map<size_t, TextureResource> textures;
std::map<size_t, SamplerResource> samplers;
diff --git a/impeller/renderer/shader_types.h b/impeller/renderer/shader_types.h
index 3afb01b..3a9bab2 100644
--- a/impeller/renderer/shader_types.h
+++ b/impeller/renderer/shader_types.h
@@ -114,6 +114,8 @@
const char* name;
size_t texture_index;
size_t sampler_index;
+ size_t binding;
+ size_t set;
constexpr bool HasTexture() const { return texture_index < 32u; }