diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index d1eb6aefdf937..75de228f6a9be 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -40715,6 +40715,7 @@ ORIGIN: ../../../flutter/impeller/renderer/shader_key.cc + ../../../flutter/LICE ORIGIN: ../../../flutter/impeller/renderer/shader_key.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/shader_library.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/shader_library.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/shader_stage_compatibility_checker.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/snapshot.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/snapshot.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/stroke.comp + ../../../flutter/LICENSE @@ -43596,6 +43597,7 @@ FILE: ../../../flutter/impeller/renderer/shader_key.cc FILE: ../../../flutter/impeller/renderer/shader_key.h FILE: ../../../flutter/impeller/renderer/shader_library.cc FILE: ../../../flutter/impeller/renderer/shader_library.h +FILE: ../../../flutter/impeller/renderer/shader_stage_compatibility_checker.h FILE: ../../../flutter/impeller/renderer/snapshot.cc FILE: ../../../flutter/impeller/renderer/snapshot.h FILE: ../../../flutter/impeller/renderer/stroke.comp diff --git a/impeller/renderer/pipeline.h b/impeller/renderer/pipeline.h index eda23adebc5ff..7bed0902d2b48 100644 --- a/impeller/renderer/pipeline.h +++ b/impeller/renderer/pipeline.h @@ -13,6 +13,7 @@ #include "impeller/renderer/context.h" #include "impeller/renderer/pipeline_builder.h" #include "impeller/renderer/pipeline_descriptor.h" +#include "impeller/renderer/shader_stage_compatibility_checker.h" namespace impeller { @@ -89,6 +90,11 @@ PipelineFuture CreatePipelineFuture( template class RenderPipelineT { + static_assert( + ShaderStageCompatibilityChecker::Check(), + "The output slots for the fragment shader don't have matches in the " + "vertex shader's output slots. This will result in a linker error."); + public: using VertexShader = VertexShader_; using FragmentShader = FragmentShader_; diff --git a/impeller/renderer/shader_stage_compatibility_checker.h b/impeller/renderer/shader_stage_compatibility_checker.h new file mode 100644 index 0000000000000..5a16e64b6db03 --- /dev/null +++ b/impeller/renderer/shader_stage_compatibility_checker.h @@ -0,0 +1,76 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_IMPELLER_RENDERER_SHADER_STAGE_COMPATIBILITY_CHECKER_H_ +#define FLUTTER_IMPELLER_RENDERER_SHADER_STAGE_COMPATIBILITY_CHECKER_H_ + +namespace impeller { +/// This is a classed use to check that the input slots of fragment shaders +/// match the output slots of the vertex shaders. +/// If they don't match it will result in linker errors when creating the +/// pipeline. It's not used at runtime. +template +class ShaderStageCompatibilityChecker { + public: + static constexpr bool CompileTimeStrEqual(const char* str1, + const char* str2) { + return *str1 == *str2 && + (*str1 == '\0' || CompileTimeStrEqual(str1 + 1, str2 + 1)); + } + + /// Returns `true` if the shader input slots for the fragment shader match the + /// ones declared as outputs in the vertex shader. + static constexpr bool Check() { + constexpr size_t num_outputs = VertexShaderT::kAllShaderStageOutputs.size(); + constexpr size_t num_inputs = FragmentShaderT::kAllShaderStageInputs.size(); + + if (num_inputs > num_outputs) { + return false; + } + + for (size_t i = 0; i < num_inputs; ++i) { + const ShaderStageIOSlot* input_slot = + FragmentShaderT::kAllShaderStageInputs[i]; + for (size_t j = 0; j < num_outputs; ++j) { + const ShaderStageIOSlot* output_slot = + VertexShaderT::kAllShaderStageOutputs[j]; + if (input_slot->location == output_slot->location) { + if (!CompileTimeStrEqual(input_slot->name, output_slot->name) || + input_slot->set != output_slot->set || + input_slot->binding != output_slot->binding || + input_slot->type != output_slot->type || + input_slot->bit_width != output_slot->bit_width || + input_slot->vec_size != output_slot->vec_size || + input_slot->columns != output_slot->columns || + input_slot->offset != output_slot->offset) { + return false; + } + } + } + } + + return true; + } +}; + +// The following shaders don't define output slots. +// TODO(https://github.com/flutter/flutter/issues/146852): Make impellerc emit +// an empty array for output slots. +struct CheckerboardVertexShader; +struct ClipVertexShader; + +template +class ShaderStageCompatibilityChecker { + public: + static constexpr bool Check() { return true; } +}; + +template +class ShaderStageCompatibilityChecker { + public: + static constexpr bool Check() { return true; } +}; +} // namespace impeller +#endif // FLUTTER_IMPELLER_RENDERER_SHADER_STAGE_COMPATIBILITY_CHECKER_H_