17#include "third_party/abseil-cpp/absl/status/status.h"
18#include "third_party/abseil-cpp/absl/status/statusor.h"
19#include "third_party/abseil-cpp/absl/strings/str_cat.h"
30 std::shared_ptr<impeller::VertexDescriptor> vertex_descriptor)
31 : vertex_shader_(
std::move(vertex_shader)),
32 fragment_shader_(
std::move(fragment_shader)),
33 vertex_descriptor_(
std::move(vertex_descriptor)) {
38 vertex_descriptor_->RegisterDescriptorSetLayouts(
41 vertex_descriptor_->RegisterDescriptorSetLayouts(
63struct VertexFormatInfo {
70constexpr std::array<VertexFormatInfo, 12> kVertexFormatTable = {{
89constexpr size_t kBufferLayoutInts = 3;
97constexpr size_t kAttributeInts = 3;
111absl::StatusOr<std::shared_ptr<impeller::VertexDescriptor>>
113 std::span<const int32_t> buffer_layouts,
114 std::span<const int32_t> attributes,
115 std::span<const char> attribute_names) {
116 const size_t buffer_layout_count = buffer_layouts.size() / kBufferLayoutInts;
117 const size_t attribute_count = attributes.size() / kAttributeInts;
120 std::vector<impeller::ShaderStageBufferLayout> stage_layouts;
121 stage_layouts.reserve(buffer_layout_count);
122 std::vector<impeller::ShaderStageIOSlot> stage_inputs;
123 stage_inputs.reserve(attribute_count);
125 size_t attr_cursor = 0;
126 size_t name_cursor = 0;
127 for (
size_t buffer_index = 0; buffer_index < buffer_layout_count;
129 const int32_t stride = buffer_layouts[buffer_index * kBufferLayoutInts + 0];
130 const int32_t attr_count_in_buffer =
131 buffer_layouts[buffer_index * kBufferLayoutInts + 1];
132 const int32_t step_mode =
133 buffer_layouts[buffer_index * kBufferLayoutInts + 2];
135 return absl::InvalidArgumentError(
136 absl::StrCat(
"VertexBuffer.strideInBytes must be positive (got ",
137 stride,
") on buffer at index ", buffer_index,
"."));
139 if (step_mode < 0 || step_mode > 1) {
140 return absl::InvalidArgumentError(
141 absl::StrCat(
"VertexBuffer.stepMode is out of range (got ", step_mode,
142 ") on buffer at index ", buffer_index,
"."));
144 if (attr_count_in_buffer < 0 ||
145 attr_cursor +
static_cast<size_t>(attr_count_in_buffer) >
147 return absl::InvalidArgumentError(
148 "Internal error: attribute count overruns the packed attributes "
151 stage_layouts.push_back({
static_cast<size_t>(stride), buffer_index,
163 std::vector<AttrRange> ranges_in_buffer;
164 ranges_in_buffer.reserve(attr_count_in_buffer);
166 for (
size_t a = 0; a < static_cast<size_t>(attr_count_in_buffer); ++a) {
167 const int32_t offset = attributes[attr_cursor * kAttributeInts + 0];
168 const int32_t format_index = attributes[attr_cursor * kAttributeInts + 1];
169 const int32_t name_byte_length =
170 attributes[attr_cursor * kAttributeInts + 2];
173 if (name_byte_length <= 0 ||
174 name_cursor +
static_cast<size_t>(name_byte_length) >
175 attribute_names.size()) {
176 return absl::InvalidArgumentError(
177 "Internal error: attribute name overruns the packed names blob.");
179 const std::string_view
name(attribute_names.data() + name_cursor,
180 static_cast<size_t>(name_byte_length));
181 name_cursor +=
static_cast<size_t>(name_byte_length);
184 return absl::InvalidArgumentError(absl::StrCat(
185 "VertexAttribute '",
name,
186 "' offsetInBytes must be non-negative (got ", offset,
")."));
188 if (format_index < 0 ||
189 static_cast<size_t>(format_index) >= kVertexFormatTable.size()) {
190 return absl::InvalidArgumentError(
191 absl::StrCat(
"VertexAttribute '",
name,
"' format index ",
192 format_index,
" is out of range."));
194 const VertexFormatInfo&
format = kVertexFormatTable[format_index];
196 if (
static_cast<size_t>(offset) +
format.bytes_per_element >
197 static_cast<size_t>(stride)) {
198 return absl::InvalidArgumentError(absl::StrCat(
199 "VertexAttribute '",
name,
"' (offset ", offset,
" + ",
200 format.bytes_per_element,
" bytes) overruns stride of ", stride,
201 " on buffer at index ", buffer_index,
"."));
207 const size_t begin =
static_cast<size_t>(offset);
208 const size_t end = begin +
format.bytes_per_element;
209 const std::string name_owned(
name);
210 for (
const auto& other : ranges_in_buffer) {
211 if (begin < other.end && other.begin <
end) {
212 return absl::InvalidArgumentError(
213 absl::StrCat(
"VertexAttribute '",
name,
"' (bytes [", begin,
", ",
214 end,
")) overlaps VertexAttribute '", other.name,
215 "' (bytes [", other.begin,
", ", other.end,
216 ")) on buffer at index ", buffer_index,
"."));
219 ranges_in_buffer.push_back({name_owned, begin,
end});
229 for (
const auto& slot : shader_inputs) {
230 if (slot.name !=
nullptr &&
231 std::strcmp(slot.name, name_owned.c_str()) == 0) {
236 if (shader_slot ==
nullptr) {
237 return absl::InvalidArgumentError(absl::StrCat(
238 "VertexAttribute name '",
name,
239 "' does not match any input declared by the bound vertex "
255 return absl::InvalidArgumentError(absl::StrCat(
256 "VertexAttribute '",
name,
257 "' format does not match the vertex shader's declared input "
263 built.
offset =
static_cast<size_t>(offset);
264 stage_inputs.push_back(built);
268 if (attr_cursor != attribute_count) {
269 return absl::InvalidArgumentError(
270 "Internal error: attributes blob has trailing rows not consumed "
273 if (name_cursor != attribute_names.size()) {
274 return absl::InvalidArgumentError(
275 "Internal error: attribute names blob has trailing bytes.");
278 auto descriptor = std::make_shared<impeller::VertexDescriptor>();
279 descriptor->SetStageInputs(stage_inputs, stage_layouts);
297 Dart_Handle buffer_layouts_handle,
298 Dart_Handle attributes_handle,
299 Dart_Handle attribute_names_handle) {
304 std::shared_ptr<impeller::VertexDescriptor> vertex_descriptor;
306 const bool buffer_layouts_provided = !Dart_IsNull(buffer_layouts_handle);
307 const bool attributes_provided = !Dart_IsNull(attributes_handle);
308 const bool attribute_names_provided = !Dart_IsNull(attribute_names_handle);
309 if (buffer_layouts_provided != attributes_provided ||
310 attributes_provided != attribute_names_provided) {
312 "VertexLayout requires buffer layouts, attributes, and attribute "
313 "names to be provided together.");
316 if (buffer_layouts_provided) {
324 std::vector<int32_t> buffer_layouts_ints;
325 std::vector<int32_t> attribute_ints;
326 std::vector<char> attribute_names_bytes;
327 std::string copy_error;
333 (flutter::gpu::kBufferLayoutInts *
sizeof(int32_t)) !=
336 "Internal error: buffer layouts ByteData has invalid length.";
338 (flutter::gpu::kAttributeInts *
sizeof(int32_t)) !=
340 copy_error =
"Internal error: attributes ByteData has invalid length.";
342 const auto* buffer_layouts_src =
343 static_cast<const int32_t*
>(buffer_layouts_data.
data());
344 const auto* attributes_src =
345 static_cast<const int32_t*
>(attributes_data.
data());
346 const auto* names_src =
347 static_cast<const char*
>(attribute_names_data.
data());
348 buffer_layouts_ints.assign(
352 attribute_ints.assign(
355 attribute_names_bytes.assign(
359 if (!copy_error.empty()) {
363 absl::StatusOr<std::shared_ptr<impeller::VertexDescriptor>> built =
364 flutter::gpu::BuildCustomVertexDescriptor(
366 std::span<const int32_t>(buffer_layouts_ints.data(),
367 buffer_layouts_ints.size()),
368 std::span<const int32_t>(attribute_ints.data(),
369 attribute_ints.size()),
370 std::span<const char>(attribute_names_bytes.data(),
371 attribute_names_bytes.size()));
375 vertex_descriptor = *std::move(built);
380 auto res = fml::MakeRefCounted<flutter::gpu::RenderPipeline>(
383 std::move(vertex_descriptor));
384 res->AssociateWithDartWrapper(wrapper);
~RenderPipeline() override
void BindToPipelineDescriptor(impeller::ShaderLibrary &library, impeller::PipelineDescriptor &desc)
RenderPipeline(fml::RefPtr< flutter::gpu::Shader > vertex_shader, fml::RefPtr< flutter::gpu::Shader > fragment_shader, std::shared_ptr< impeller::VertexDescriptor > vertex_descriptor)
An immutable collection of shaders loaded from a shader bundle asset.
bool RegisterSync(Context &context)
const std::vector< impeller::ShaderStageIOSlot > & GetStageInputs() const
std::shared_ptr< impeller::VertexDescriptor > CreateVertexDescriptor() const
const std::vector< impeller::DescriptorSetLayout > & GetDescriptorSetLayouts() const
std::shared_ptr< const impeller::ShaderFunction > GetFunctionFromLibrary(impeller::ShaderLibrary &library)
PipelineDescriptor & SetVertexDescriptor(std::shared_ptr< VertexDescriptor > vertex_descriptor)
PipelineDescriptor & AddStageEntrypoint(std::shared_ptr< const ShaderFunction > function)
const void * data() const
size_t length_in_bytes() const
#define IMPLEMENT_WRAPPERTYPEINFO(LibraryName, ClassName)
uint32_t uint32_t * format
DEF_SWITCHES_START aot vmservice shared library name
VertexInputRate
Whether a vertex buffer binding advances its read position once per vertex or once per instance.
@ kInstance
The binding is read once per instance.
@ kVertex
The binding is read once per vertex. This is the default.
Dart_Handle ToDart(const T &object)
Dart_Handle InternalFlutterGpu_RenderPipeline_Initialize(Dart_Handle wrapper, flutter::gpu::Context *gpu_context, flutter::gpu::Shader *vertex_shader, flutter::gpu::Shader *fragment_shader, Dart_Handle buffer_layouts_handle, Dart_Handle attributes_handle, Dart_Handle attribute_names_handle)
impeller::ShaderType type