[Impeller] Store Buffer/Texture bindings in vector instead of map. (flutter/engine#48719)

Places the binding data in a vector, since they key was only meaningful on metal but not used anywhere. I don't think that we need to specificially handle the case where our own contents bind the same contents multiple times, but interested to discuss if folks disagree.
This commit is contained in:
Jonah Williams 2023-12-06 11:32:41 -08:00 committed by GitHub
parent a75c76e6ec
commit 8b54eb6bf5
27 changed files with 88 additions and 99 deletions

View File

@ -120,10 +120,9 @@ struct {{camel_case(shader_name)}}{{camel_case(shader_stage)}}Shader {
static constexpr auto kResource{{camel_case(sampled_image.name)}} = SampledImageSlot { // {{sampled_image.name}}
"{{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.ext_res_0}}u, // ext_res_0
{{sampled_image.set}}u, // set
{{sampled_image.binding}}u, // binding
};
static ShaderMetadata kMetadata{{camel_case(sampled_image.name)}};
{% endfor %}

View File

@ -4,12 +4,8 @@
#pragma once
#include <map>
#include <memory>
#include <optional>
#include <string>
#include "flutter/fml/logging.h"
#include "impeller/core/buffer_view.h"
#include "impeller/core/formats.h"
#include "impeller/core/sampler.h"

View File

@ -90,6 +90,23 @@ struct ShaderUniformSlot {
size_t binding;
};
/// @brief Metadata required to bind a combined texture and sampler.
///
/// OpenGL binding requires the usage of the separate shader metadata struct.
struct SampledImageSlot {
/// @brief The name of the uniform slot.
const char* name;
/// @brief `ext_res_0` is the Metal binding value.
size_t texture_index;
/// @brief The Vulkan descriptor set index.
size_t set;
/// @brief The Vulkan binding value.
size_t binding;
};
struct ShaderStageIOSlot {
const char* name;
size_t location;
@ -131,32 +148,6 @@ struct ShaderStageBufferLayout {
}
};
/// @brief Metadata required to bind a texture and sampler.
///
/// OpenGL binding requires the usage of the separate shader metadata struct.
struct SampledImageSlot {
/// @brief The name of the texture slot.
const char* name;
/// @brief This value is `ext_res_0`, the Metal binding value for the texture.
size_t texture_index;
/// @brief This value is `ext_res_1`, the Metal binding value for the sampler.
///
/// Since only combined texture and samplers are used, this index is unused.
size_t sampler_index;
/// @brief The Vulkan binding value for a combined texture and sampler.
size_t binding;
/// @brief The Vulkan descriptor set index.
size_t set;
constexpr bool HasTexture() const { return texture_index < 32u; }
constexpr bool HasSampler() const { return sampler_index < 32u; }
};
enum class DescriptorType {
kUniformBuffer,
kStorageBuffer,

View File

@ -10,6 +10,7 @@
#include "impeller/entity/contents/content_context.h"
#include "impeller/renderer/command.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/vertex_buffer_builder.h"
namespace impeller {

View File

@ -9,6 +9,7 @@
#include "impeller/entity/contents/contents.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/sampler_library.h"
#include "impeller/renderer/vertex_buffer_builder.h"
namespace impeller {

View File

@ -14,6 +14,7 @@
#include "impeller/geometry/vector.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/sampler_library.h"
#include "impeller/renderer/vertex_buffer_builder.h"
namespace impeller {

View File

@ -20,6 +20,7 @@
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/render_target.h"
#include "impeller/renderer/sampler_library.h"
#include "impeller/renderer/vertex_buffer_builder.h"
namespace impeller {

View File

@ -10,6 +10,7 @@
#include "impeller/renderer/command.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/sampler_library.h"
#include "impeller/renderer/vertex_buffer_builder.h"
namespace impeller {

View File

@ -11,6 +11,7 @@
#include "impeller/geometry/vector.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/sampler_library.h"
#include "impeller/renderer/vertex_buffer_builder.h"
namespace impeller {

View File

@ -11,6 +11,7 @@
#include "impeller/entity/contents/contents.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/sampler_library.h"
#include "impeller/renderer/vertex_buffer_builder.h"
namespace impeller {

View File

@ -11,6 +11,7 @@
#include "impeller/geometry/vector.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/sampler_library.h"
#include "impeller/renderer/vertex_buffer_builder.h"
namespace impeller {

View File

@ -10,6 +10,7 @@
#include "impeller/geometry/matrix.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/sampler_library.h"
#include "impeller/renderer/vertex_buffer_builder.h"
namespace impeller {

View File

@ -241,7 +241,6 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer,
SampledImageSlot image_slot;
image_slot.name = uniform.name.c_str();
image_slot.texture_index = uniform.location - minimum_sampler_index;
image_slot.sampler_index = uniform.location - minimum_sampler_index;
cmd.BindResource(ShaderStage::kFragment, image_slot, metadata,
input.texture, sampler);

View File

@ -11,26 +11,34 @@ namespace impeller {
/// @brief Retrieve the [VertInfo] struct data from the provided [command].
template <typename T>
typename T::VertInfo* GetVertInfo(const Command& command) {
auto resource = command.vertex_bindings.buffers.find(0u);
auto resource = std::find_if(command.vertex_bindings.buffers.begin(),
command.vertex_bindings.buffers.end(),
[](const BufferAndUniformSlot& data) {
return data.slot.ext_res_0 == 0u;
});
if (resource == command.vertex_bindings.buffers.end()) {
return nullptr;
}
auto data = (resource->second.view.resource.contents +
resource->second.view.resource.range.offset);
auto data =
(resource->view.resource.contents + resource->view.resource.range.offset);
return reinterpret_cast<typename T::VertInfo*>(data);
}
/// @brief Retrieve the [FragInfo] struct data from the provided [command].
template <typename T>
typename T::FragInfo* GetFragInfo(const Command& command) {
auto resource = command.fragment_bindings.buffers.find(0u);
auto resource = std::find_if(command.fragment_bindings.buffers.begin(),
command.fragment_bindings.buffers.end(),
[](const BufferAndUniformSlot& data) {
return data.slot.ext_res_0 == 0u;
});
if (resource == command.fragment_bindings.buffers.end()) {
return nullptr;
}
auto data = (resource->second.view.resource.contents +
resource->second.view.resource.range.offset);
auto data =
(resource->view.resource.contents + resource->view.resource.range.offset);
return reinterpret_cast<typename T::FragInfo*>(data);
}

View File

@ -15,9 +15,9 @@
#include "impeller/entity/texture_fill.vert.h"
#include "impeller/entity/texture_fill_external.frag.h"
#include "impeller/geometry/constants.h"
#include "impeller/geometry/path_builder.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/sampler_library.h"
#include "impeller/renderer/vertex_buffer_builder.h"
namespace impeller {

View File

@ -10,6 +10,7 @@
#include "impeller/entity/entity.h"
#include "impeller/entity/texture_fill.vert.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/vertex_buffer_builder.h"
namespace impeller {

View File

@ -145,12 +145,12 @@ bool BufferBindingsGLES::BindUniformData(const ProcTableGLES& gl,
const Bindings& vertex_bindings,
const Bindings& fragment_bindings) {
for (const auto& buffer : vertex_bindings.buffers) {
if (!BindUniformBuffer(gl, transients_allocator, buffer.second.view)) {
if (!BindUniformBuffer(gl, transients_allocator, buffer.view)) {
return false;
}
}
for (const auto& buffer : fragment_bindings.buffers) {
if (!BindUniformBuffer(gl, transients_allocator, buffer.second.view)) {
if (!BindUniformBuffer(gl, transients_allocator, buffer.view)) {
return false;
}
}
@ -345,13 +345,13 @@ std::optional<size_t> BufferBindingsGLES::BindTextures(
size_t unit_start_index) {
size_t active_index = unit_start_index;
for (const auto& data : bindings.sampled_images) {
const auto& texture_gles = TextureGLES::Cast(*data.second.texture.resource);
if (data.second.texture.GetMetadata() == nullptr) {
const auto& texture_gles = TextureGLES::Cast(*data.texture.resource);
if (data.texture.GetMetadata() == nullptr) {
VALIDATION_LOG << "No metadata found for texture binding.";
return std::nullopt;
}
auto location = ComputeTextureLocation(data.second.texture.GetMetadata());
auto location = ComputeTextureLocation(data.texture.GetMetadata());
if (location == -1) {
return std::nullopt;
}
@ -377,7 +377,7 @@ std::optional<size_t> BufferBindingsGLES::BindTextures(
/// If there is a sampler for the texture at the same index, configure the
/// bound texture using that sampler.
///
const auto& sampler_gles = SamplerGLES::Cast(*data.second.sampler);
const auto& sampler_gles = SamplerGLES::Cast(*data.sampler);
if (!sampler_gles.ConfigureBoundTexture(texture_gles, gl)) {
return std::nullopt;
}

View File

@ -21,6 +21,7 @@
#include "impeller/renderer/backend/metal/formats_mtl.h"
#include "impeller/renderer/backend/metal/sampler_mtl.h"
#include "impeller/renderer/backend/metal/texture_mtl.h"
#include "impeller/renderer/command.h"
#include "impeller/renderer/compute_command.h"
namespace impeller {
@ -209,7 +210,7 @@ bool ComputePassMTL::EncodeCommands(const std::shared_ptr<Allocator>& allocator,
ComputePassBindingsCache pass_bindings(encoder);
fml::closure pop_debug_marker = [encoder]() { [encoder popDebugGroup]; };
for (const auto& command : commands_) {
for (const ComputeCommand& command : commands_) {
#ifdef IMPELLER_DEBUG
fml::ScopedCleanupClosure auto_pop_debug_marker(pop_debug_marker);
if (!command.label.empty()) {
@ -223,16 +224,16 @@ bool ComputePassMTL::EncodeCommands(const std::shared_ptr<Allocator>& allocator,
ComputePipelineMTL::Cast(*command.pipeline)
.GetMTLComputePipelineState());
for (const auto& buffer : command.bindings.buffers) {
if (!Bind(pass_bindings, *allocator, buffer.first,
buffer.second.view.resource)) {
for (const BufferAndUniformSlot& buffer : command.bindings.buffers) {
if (!Bind(pass_bindings, *allocator, buffer.slot.ext_res_0,
buffer.view.resource)) {
return false;
}
}
for (const auto& data : command.bindings.sampled_images) {
if (!Bind(pass_bindings, data.first, *data.second.sampler,
*data.second.texture.resource)) {
for (const TextureAndSampler& data : command.bindings.sampled_images) {
if (!Bind(pass_bindings, data.slot.texture_index, *data.sampler,
*data.texture.resource)) {
return false;
}
}

View File

@ -18,6 +18,7 @@
#include "impeller/renderer/backend/metal/pipeline_mtl.h"
#include "impeller/renderer/backend/metal/sampler_mtl.h"
#include "impeller/renderer/backend/metal/texture_mtl.h"
#include "impeller/renderer/command.h"
#include "impeller/renderer/vertex_descriptor.h"
namespace impeller {
@ -408,15 +409,15 @@ bool RenderPassMTL::EncodeCommands(const std::shared_ptr<Allocator>& allocator,
auto bind_stage_resources = [&allocator, &pass_bindings](
const Bindings& bindings,
ShaderStage stage) -> bool {
for (const auto& buffer : bindings.buffers) {
if (!Bind(pass_bindings, *allocator, stage, buffer.first,
buffer.second.view.resource)) {
for (const BufferAndUniformSlot& buffer : bindings.buffers) {
if (!Bind(pass_bindings, *allocator, stage, buffer.slot.ext_res_0,
buffer.view.resource)) {
return false;
}
}
for (const auto& data : bindings.sampled_images) {
if (!Bind(pass_bindings, stage, data.first, *data.second.sampler,
*data.second.texture.resource)) {
for (const TextureAndSampler& data : bindings.sampled_images) {
if (!Bind(pass_bindings, stage, data.slot.texture_index, *data.sampler,
*data.texture.resource)) {
return false;
}
}

View File

@ -4,6 +4,7 @@
#include "impeller/renderer/backend/vulkan/binding_helpers_vk.h"
#include "fml/status.h"
#include "impeller/core/shader_types.h"
#include "impeller/renderer/backend/vulkan/command_buffer_vk.h"
#include "impeller/renderer/backend/vulkan/command_encoder_vk.h"
#include "impeller/renderer/backend/vulkan/command_pool_vk.h"
@ -28,7 +29,7 @@ static bool BindImages(const Bindings& bindings,
vk::DescriptorSet& vk_desc_set,
std::vector<vk::DescriptorImageInfo>& images,
std::vector<vk::WriteDescriptorSet>& writes) {
for (const auto& [index, data] : bindings.sampled_images) {
for (const TextureAndSampler& data : bindings.sampled_images) {
auto texture = data.texture.resource;
const auto& texture_vk = TextureVK::Cast(*texture);
const SamplerVK& sampler = SamplerVK::Cast(*data.sampler);
@ -66,7 +67,7 @@ static bool BindBuffers(const Bindings& bindings,
const std::vector<DescriptorSetLayout>& desc_set,
std::vector<vk::DescriptorBufferInfo>& buffers,
std::vector<vk::WriteDescriptorSet>& writes) {
for (const auto& [buffer_index, data] : bindings.buffers) {
for (const BufferAndUniformSlot& data : bindings.buffers) {
const auto& buffer_view = data.view.resource.buffer;
auto device_buffer = buffer_view->GetDeviceBuffer(allocator);

View File

@ -9,6 +9,7 @@
#include "impeller/renderer/backend/vulkan/command_buffer_vk.h"
#include "impeller/renderer/backend/vulkan/compute_pipeline_vk.h"
#include "impeller/renderer/backend/vulkan/texture_vk.h"
#include "impeller/renderer/command.h"
namespace impeller {
@ -43,7 +44,7 @@ static bool UpdateBindingLayouts(const Bindings& bindings,
barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal;
for (const auto& [_, data] : bindings.sampled_images) {
for (const TextureAndSampler& data : bindings.sampled_images) {
if (!TextureVK::Cast(*data.texture.resource).SetLayout(barrier)) {
return false;
}
@ -58,7 +59,7 @@ static bool UpdateBindingLayouts(const ComputeCommand& command,
static bool UpdateBindingLayouts(const std::vector<ComputeCommand>& commands,
const vk::CommandBuffer& buffer) {
for (const auto& command : commands) {
for (const ComputeCommand& command : commands) {
if (!UpdateBindingLayouts(command, buffer)) {
return false;
}

View File

@ -21,6 +21,7 @@
#include "impeller/renderer/backend/vulkan/pipeline_vk.h"
#include "impeller/renderer/backend/vulkan/shared_object_vk.h"
#include "impeller/renderer/backend/vulkan/texture_vk.h"
#include "impeller/renderer/command.h"
#include "vulkan/vulkan_enums.hpp"
#include "vulkan/vulkan_handles.hpp"
#include "vulkan/vulkan_to_string.hpp"
@ -315,7 +316,7 @@ static bool UpdateBindingLayouts(const Bindings& bindings,
barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal;
for (const auto& [_, data] : bindings.sampled_images) {
for (const TextureAndSampler& data : bindings.sampled_images) {
if (!TextureVK::Cast(*data.texture.resource).SetLayout(barrier)) {
return false;
}
@ -331,7 +332,7 @@ static bool UpdateBindingLayouts(const Command& command,
static bool UpdateBindingLayouts(const std::vector<Command>& commands,
const vk::CommandBuffer& buffer) {
for (const auto& command : commands) {
for (const Command& command : commands) {
if (!UpdateBindingLayouts(command, buffer)) {
return false;
}

View File

@ -49,12 +49,12 @@ bool Command::DoBindResource(ShaderStage stage,
switch (stage) {
case ShaderStage::kVertex:
vertex_bindings.buffers[slot.ext_res_0] = {
.slot = slot, .view = BufferResource(metadata, std::move(view))};
vertex_bindings.buffers.emplace_back(BufferAndUniformSlot{
.slot = slot, .view = BufferResource(metadata, std::move(view))});
return true;
case ShaderStage::kFragment:
fragment_bindings.buffers[slot.ext_res_0] = {
.slot = slot, .view = BufferResource(metadata, std::move(view))};
fragment_bindings.buffers.emplace_back(BufferAndUniformSlot{
.slot = slot, .view = BufferResource(metadata, std::move(view))});
return true;
case ShaderStage::kCompute:
VALIDATION_LOG << "Use ComputeCommands for compute shader stages.";
@ -76,24 +76,21 @@ bool Command::BindResource(ShaderStage stage,
if (!texture || !texture->IsValid()) {
return false;
}
if (!slot.HasSampler() || !slot.HasTexture()) {
return true;
}
switch (stage) {
case ShaderStage::kVertex:
vertex_bindings.sampled_images[slot.sampler_index] = TextureAndSampler{
vertex_bindings.sampled_images.emplace_back(TextureAndSampler{
.slot = slot,
.texture = {&metadata, std::move(texture)},
.sampler = std::move(sampler),
};
});
return true;
case ShaderStage::kFragment:
fragment_bindings.sampled_images[slot.sampler_index] = TextureAndSampler{
fragment_bindings.sampled_images.emplace_back(TextureAndSampler{
.slot = slot,
.texture = {&metadata, std::move(texture)},
.sampler = std::move(sampler),
};
});
return true;
case ShaderStage::kCompute:
VALIDATION_LOG << "Use ComputeCommands for compute shader stages.";

View File

@ -10,8 +10,6 @@
#include <optional>
#include <string>
#include "flutter/fml/logging.h"
#include "flutter/fml/macros.h"
#include "impeller/core/buffer_view.h"
#include "impeller/core/formats.h"
#include "impeller/core/resource_binder.h"
@ -21,8 +19,6 @@
#include "impeller/core/vertex_buffer.h"
#include "impeller/geometry/rect.h"
#include "impeller/renderer/pipeline.h"
#include "impeller/renderer/vertex_buffer_builder.h"
#include "impeller/tessellator/tessellator.h"
namespace impeller {
@ -75,8 +71,8 @@ struct BufferAndUniformSlot {
};
struct Bindings {
std::map<size_t, TextureAndSampler> sampled_images;
std::map<size_t, BufferAndUniformSlot> buffers;
std::vector<TextureAndSampler> sampled_images;
std::vector<BufferAndUniformSlot> buffers;
};
//------------------------------------------------------------------------------

View File

@ -23,8 +23,8 @@ bool ComputeCommand::BindResource(ShaderStage stage,
return false;
}
bindings.buffers[slot.ext_res_0] = {.slot = slot,
.view = {&metadata, std::move(view)}};
bindings.buffers.emplace_back(
BufferAndUniformSlot{.slot = slot, .view = {&metadata, std::move(view)}});
return true;
}
@ -43,15 +43,12 @@ bool ComputeCommand::BindResource(ShaderStage stage,
if (!texture || !texture->IsValid()) {
return false;
}
if (!slot.HasSampler() || !slot.HasTexture()) {
return true;
}
bindings.sampled_images[slot.sampler_index] = TextureAndSampler{
bindings.sampled_images.emplace_back(TextureAndSampler{
.slot = slot,
.texture = {&metadata, std::move(texture)},
.sampler = std::move(sampler),
};
});
return false;
}

View File

@ -4,26 +4,18 @@
#pragma once
#include <map>
#include <memory>
#include <optional>
#include <string>
#include "flutter/fml/logging.h"
#include "flutter/fml/macros.h"
#include "impeller/core/buffer_view.h"
#include "impeller/core/formats.h"
#include "impeller/core/resource_binder.h"
#include "impeller/core/sampler.h"
#include "impeller/core/shader_types.h"
#include "impeller/core/texture.h"
#include "impeller/core/vertex_buffer.h"
#include "impeller/geometry/rect.h"
#include "impeller/renderer/command.h"
#include "impeller/renderer/compute_pipeline_descriptor.h"
#include "impeller/renderer/pipeline.h"
#include "impeller/renderer/vertex_buffer_builder.h"
#include "impeller/tessellator/tessellator.h"
namespace impeller {

View File

@ -386,7 +386,6 @@ bool InternalFlutterGpu_RenderPass_BindTexture(
impeller::SampledImageSlot image_slot;
image_slot.texture_index = slot_id;
image_slot.sampler_index = slot_id;
return command.BindResource(flutter::gpu::ToImpellerShaderStage(stage),
image_slot, metadata, texture->GetTexture(),
sampler);