Flutter Impeller
shader_stage_compatibility_checker.h
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef FLUTTER_IMPELLER_RENDERER_SHADER_STAGE_COMPATIBILITY_CHECKER_H_
6 #define FLUTTER_IMPELLER_RENDERER_SHADER_STAGE_COMPATIBILITY_CHECKER_H_
7 
8 #include <cstddef>
9 
11 
12 namespace impeller {
13 
14 //------------------------------------------------------------------------------
15 /// @brief Checks, at C++ compile-time, if the two pipeline stages are
16 /// compatible.
17 ///
18 /// Stages may be incompatible if the outputs declared in the vertex
19 /// stage don't line up with the inputs declared in the fragment
20 /// stage. Additionally, the types of the inputs and outputs need to
21 /// be identical. Some drivers like the one on the PowerVR GE8320
22 /// also have bugs the require the precision qualifier of the stage
23 /// interfaces to match exactly.
24 ///
25 /// Not ensuring stage compatibility will cause pipeline creation
26 /// errors that will only be caught at runtime. In addition to the
27 /// bugs discovered related to precision qualifier, some errors may
28 /// only manifest at runtime on some devices.
29 ///
30 /// This static compile-time C++ check ensures that all the possible
31 /// runtime errors will be caught at build time.
32 ///
33 /// There is no runtime overhead to using this class.
34 ///
35 /// @tparam VertexShaderT The vertex shader stage metadata.
36 /// @tparam FragmentShaderT The fragment shader stage metadata.
37 ///
38 template <typename VertexShaderT, typename FragmentShaderT>
40  public:
41  static constexpr bool CompileTimeStrEqual(const char* str1,
42  const char* str2) {
43  return *str1 == *str2 &&
44  (*str1 == '\0' || CompileTimeStrEqual(str1 + 1, str2 + 1));
45  }
46 
47  /// Returns `true` if the shader input slots for the fragment shader match the
48  /// ones declared as outputs in the vertex shader.
49  static constexpr bool Check() {
50  constexpr size_t num_outputs = VertexShaderT::kAllShaderStageOutputs.size();
51  constexpr size_t num_inputs = FragmentShaderT::kAllShaderStageInputs.size();
52 
53  if (num_inputs > num_outputs) {
54  return false;
55  }
56 
57  for (size_t i = 0; i < num_inputs; ++i) {
58  const ShaderStageIOSlot* input_slot =
59  FragmentShaderT::kAllShaderStageInputs[i];
60  for (size_t j = 0; j < num_outputs; ++j) {
61  const ShaderStageIOSlot* output_slot =
62  VertexShaderT::kAllShaderStageOutputs[j];
63  if (input_slot->location == output_slot->location) {
64  if (!CompileTimeStrEqual(input_slot->name, output_slot->name) ||
65  input_slot->set != output_slot->set ||
66  input_slot->binding != output_slot->binding ||
67  input_slot->type != output_slot->type ||
68  input_slot->bit_width != output_slot->bit_width ||
69  input_slot->vec_size != output_slot->vec_size ||
70  input_slot->columns != output_slot->columns ||
71  input_slot->offset != output_slot->offset ||
72  input_slot->relaxed_precision != output_slot->relaxed_precision) {
73  return false;
74  }
75  }
76  }
77  }
78 
79  return true;
80  }
81 };
82 
83 } // namespace impeller
84 
85 #endif // FLUTTER_IMPELLER_RENDERER_SHADER_STAGE_COMPATIBILITY_CHECKER_H_
Checks, at C++ compile-time, if the two pipeline stages are compatible.
static constexpr bool CompileTimeStrEqual(const char *str1, const char *str2)