blob: 49f18966a49aa2ae3cb35d2e0eaba278a27d0ac1 [file]
// 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_LIB_GPU_SHADER_H_
#define FLUTTER_LIB_GPU_SHADER_H_
#include <algorithm>
#include <memory>
#include <string>
#include "flutter/lib/gpu/context.h"
#include "flutter/lib/ui/dart_wrapper.h"
#include "fml/memory/ref_ptr.h"
#include "impeller/core/shader_types.h"
#include "impeller/renderer/shader_function.h"
#include "impeller/renderer/vertex_descriptor.h"
namespace flutter {
namespace gpu {
/// An immutable collection of shaders loaded from a shader bundle asset.
class Shader : public RefCountedDartWrappable<Shader> {
DEFINE_WRAPPERTYPEINFO();
FML_FRIEND_MAKE_REF_COUNTED(Shader);
public:
struct UniformBinding {
impeller::ShaderUniformSlot slot;
impeller::ShaderMetadata metadata;
size_t size_in_bytes = 0;
const impeller::ShaderStructMemberMetadata* GetMemberMetadata(
const std::string& name) const;
};
struct TextureBinding {
impeller::SampledImageSlot slot;
impeller::ShaderMetadata metadata;
};
~Shader() override;
static fml::RefPtr<Shader> Make(
std::string library_id,
std::string entrypoint,
impeller::ShaderStage stage,
std::shared_ptr<fml::Mapping> code_mapping,
std::vector<impeller::ShaderStageIOSlot> inputs,
std::vector<impeller::ShaderStageBufferLayout> layouts,
std::unordered_map<std::string, UniformBinding> uniform_structs,
std::unordered_map<std::string, TextureBinding> uniform_textures,
std::vector<impeller::DescriptorSetLayout> descriptor_set_layouts);
std::shared_ptr<const impeller::ShaderFunction> GetFunctionFromLibrary(
impeller::ShaderLibrary& library);
bool IsRegistered(Context& context);
bool RegisterSync(Context& context);
/// Whether this shader needs to be re-registered with the impeller shader
/// library on next use. Fresh shaders start dirty. Set back to false by
/// `RegisterSync` after registration completes, and back to true by
/// `ResetFrom` when the underlying asset is reloaded.
bool IsDirty() const;
void SetClean();
/// Replaces this shader's payload (code, layouts, uniforms) with the data
/// from `other`, preserving the library_id / entrypoint registry key and
/// marking this shader dirty. Used by `ShaderLibrary` to reload a shader
/// bundle in place without breaking existing Dart wrappers.
void ResetFrom(Shader& other);
std::shared_ptr<impeller::VertexDescriptor> CreateVertexDescriptor() const;
const std::vector<impeller::ShaderStageIOSlot>& GetStageInputs() const;
const std::vector<impeller::ShaderStageBufferLayout>& GetStageBufferLayouts()
const;
const std::vector<impeller::DescriptorSetLayout>& GetDescriptorSetLayouts()
const;
impeller::ShaderStage GetShaderStage() const;
/// The shader's entrypoint name, for identifying it in error messages.
const std::string& GetEntrypoint() const;
const Shader::UniformBinding* GetUniformStruct(const std::string& name) const;
const Shader::TextureBinding* GetUniformTexture(
const std::string& name) const;
/// The position of the named uniform struct in this shader's stable
/// binding order, or -1. Indices stay valid until the shader's payload
/// is replaced by a reload (`ResetFrom`); callers cache them to bind
/// without passing the name across the FFI boundary on every draw.
int GetUniformStructIndex(const std::string& name) const;
/// The uniform struct at `index` in the stable binding order, or nullptr
/// when the index is out of range.
const Shader::UniformBinding* GetUniformStructAt(int index) const;
/// The texture counterpart to `GetUniformStructIndex`.
int GetUniformTextureIndex(const std::string& name) const;
/// The texture counterpart to `GetUniformStructAt`.
const Shader::TextureBinding* GetUniformTextureAt(int index) const;
private:
Shader();
// Stable per-source identifier used to namespace this shader's entrypoint
// in the shared shader registry. Set by ShaderLibrary at construction, and
// shared by all shaders within the same library. Typically the asset path
// the bundle was loaded from.
std::string library_id_;
std::string entrypoint_;
impeller::ShaderStage stage_;
std::shared_ptr<fml::Mapping> code_mapping_;
std::vector<impeller::ShaderStageIOSlot> inputs_;
std::vector<impeller::ShaderStageBufferLayout> layouts_;
std::unordered_map<std::string, UniformBinding> uniform_structs_;
std::unordered_map<std::string, TextureBinding> uniform_textures_;
// The maps' entries in a stable order for index-based lookup. Entry
// pointers stay valid for the maps' lifetime (node-based containers);
// rebuilt whenever the maps are replaced (`Make`, `ResetFrom`).
std::vector<const UniformBinding*> uniform_struct_order_;
std::vector<const TextureBinding*> uniform_texture_order_;
std::vector<impeller::DescriptorSetLayout> descriptor_set_layouts_;
bool is_dirty_ = true;
void RebuildBindingOrder();
// Returns the scoped name to use when registering or looking up this
// shader's function in a shared impeller::ShaderLibrary.
std::string GetScopedName() const;
FML_DISALLOW_COPY_AND_ASSIGN(Shader);
};
} // namespace gpu
} // namespace flutter
//----------------------------------------------------------------------------
/// Exports
///
extern "C" {
FLUTTER_GPU_EXPORT
extern int InternalFlutterGpu_Shader_GetUniformStructSize(
flutter::gpu::Shader* wrapper,
Dart_Handle struct_name_handle);
FLUTTER_GPU_EXPORT
extern int InternalFlutterGpu_Shader_GetUniformMemberOffset(
flutter::gpu::Shader* wrapper,
Dart_Handle struct_name_handle,
Dart_Handle member_name_handle);
FLUTTER_GPU_EXPORT
extern int InternalFlutterGpu_Shader_GetUniformStructIndex(
flutter::gpu::Shader* wrapper,
Dart_Handle struct_name_handle);
FLUTTER_GPU_EXPORT
extern int InternalFlutterGpu_Shader_GetUniformTextureIndex(
flutter::gpu::Shader* wrapper,
Dart_Handle texture_name_handle);
// Test-only: exposes the per-shader dirty bit so tests can assert that
// reload deduplication keeps unchanged shaders clean.
FLUTTER_GPU_EXPORT
extern bool InternalFlutterGpu_Shader_DebugIsDirty(
flutter::gpu::Shader* wrapper);
} // extern "C"
#endif // FLUTTER_LIB_GPU_SHADER_H_