blob: 88397c5d682782650925965e21a0d2d498f9b4e2 [file] [log] [blame]
// 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_BACKEND_GLES_PROC_TABLE_GLES_H_
#define FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_PROC_TABLE_GLES_H_
#include <functional>
#include <string>
#include "flutter/fml/logging.h"
#include "flutter/fml/mapping.h"
#include "impeller/renderer/backend/gles/capabilities_gles.h"
#include "impeller/renderer/backend/gles/description_gles.h"
#include "impeller/renderer/backend/gles/gles.h"
namespace impeller {
const char* GLErrorToString(GLenum value);
bool GLErrorIsFatal(GLenum value);
struct AutoErrorCheck {
const PFNGLGETERRORPROC error_fn;
// TODO(matanlurey) Change to string_view.
// https://github.com/flutter/flutter/issues/135922
const char* name;
AutoErrorCheck(PFNGLGETERRORPROC error, const char* name)
: error_fn(error), name(name) {}
~AutoErrorCheck() {
if (error_fn) {
auto error = error_fn();
if (error == GL_NO_ERROR) {
return;
}
if (GLErrorIsFatal(error)) {
FML_LOG(FATAL) << "Fatal GL Error " << GLErrorToString(error) << "("
<< error << ")" << " encountered on call to " << name;
} else {
FML_LOG(ERROR) << "GL Error " << GLErrorToString(error) << "(" << error
<< ")" << " encountered on call to " << name;
}
}
}
};
template <class T>
struct GLProc {
using GLFunctionType = T;
// TODO(matanlurey) Change to string_view.
// https://github.com/flutter/flutter/issues/135922
//----------------------------------------------------------------------------
/// The name of the GL function.
///
const char* name = nullptr;
//----------------------------------------------------------------------------
/// The pointer to the GL function.
///
GLFunctionType* function = nullptr;
//----------------------------------------------------------------------------
/// An optional error function. If present, all calls will be followed by an
/// error check.
///
PFNGLGETERRORPROC error_fn = nullptr;
//----------------------------------------------------------------------------
/// @brief Call the GL function with the appropriate parameters. Lookup
/// the documentation for the GL function being called to
/// understand the arguments and return types. The arguments
/// types must match and will be type checked.
///
template <class... Args>
auto operator()(Args&&... args) const {
#ifdef IMPELLER_DEBUG
AutoErrorCheck error(error_fn, name);
// We check for the existence of extensions, and reset the function pointer
// but it's still called unconditionally below, and will segfault. This
// validation log will at least give us a hint as to what's going on.
FML_CHECK(IsAvailable()) << "GL function " << name << " is not available. "
<< "This is likely due to a missing extension.";
#endif // IMPELLER_DEBUG
#ifdef IMPELLER_TRACE_ALL_GL_CALLS
TRACE_EVENT0("impeller", name);
#endif // IMPELLER_TRACE_ALL_GL_CALLS
return function(std::forward<Args>(args)...);
}
constexpr bool IsAvailable() const { return function != nullptr; }
void Reset() {
function = nullptr;
error_fn = nullptr;
}
};
#define FOR_EACH_IMPELLER_PROC(PROC) \
PROC(ActiveTexture); \
PROC(AttachShader); \
PROC(BindAttribLocation); \
PROC(BindBuffer); \
PROC(BindFramebuffer); \
PROC(BindRenderbuffer); \
PROC(BindTexture); \
PROC(BlendEquationSeparate); \
PROC(BlendFuncSeparate); \
PROC(BufferData); \
PROC(CheckFramebufferStatus); \
PROC(Clear); \
PROC(ClearColor); \
PROC(ClearStencil); \
PROC(ColorMask); \
PROC(CompileShader); \
PROC(CreateProgram); \
PROC(CreateShader); \
PROC(CullFace); \
PROC(DeleteBuffers); \
PROC(DeleteFramebuffers); \
PROC(DeleteProgram); \
PROC(DeleteRenderbuffers); \
PROC(DeleteShader); \
PROC(DeleteTextures); \
PROC(DepthFunc); \
PROC(DepthMask); \
PROC(DetachShader); \
PROC(Disable); \
PROC(DisableVertexAttribArray); \
PROC(DrawArrays); \
PROC(DrawElements); \
PROC(Enable); \
PROC(EnableVertexAttribArray); \
PROC(Flush); \
PROC(FramebufferRenderbuffer); \
PROC(FramebufferTexture2D); \
PROC(FrontFace); \
PROC(GenBuffers); \
PROC(GenerateMipmap); \
PROC(GenFramebuffers); \
PROC(GenRenderbuffers); \
PROC(GenTextures); \
PROC(GetActiveUniform); \
PROC(GetBooleanv); \
PROC(GetFloatv); \
PROC(GetFramebufferAttachmentParameteriv); \
PROC(GetIntegerv); \
PROC(GetProgramInfoLog); \
PROC(GetProgramiv); \
PROC(GetShaderInfoLog); \
PROC(GetShaderiv); \
PROC(GetString); \
PROC(GetStringi); \
PROC(GetUniformLocation); \
PROC(IsBuffer); \
PROC(IsFramebuffer); \
PROC(IsProgram); \
PROC(IsRenderbuffer); \
PROC(IsShader); \
PROC(IsTexture); \
PROC(LinkProgram); \
PROC(RenderbufferStorage); \
PROC(Scissor); \
PROC(ShaderBinary); \
PROC(ShaderSource); \
PROC(StencilFuncSeparate); \
PROC(StencilMaskSeparate); \
PROC(StencilOpSeparate); \
PROC(TexImage2D); \
PROC(TexParameteri); \
PROC(TexParameterfv); \
PROC(Uniform1fv); \
PROC(Uniform1i); \
PROC(Uniform2fv); \
PROC(Uniform3fv); \
PROC(Uniform4fv); \
PROC(UniformMatrix4fv); \
PROC(UseProgram); \
PROC(VertexAttribPointer); \
PROC(Viewport); \
PROC(GetShaderSource); \
PROC(ReadPixels);
// Calls specific to OpenGLES.
void(glClearDepthf)(GLfloat depth);
void(glDepthRangef)(GLfloat n, GLfloat f);
#define FOR_EACH_IMPELLER_ES_ONLY_PROC(PROC) \
PROC(ClearDepthf); \
PROC(DepthRangef);
// Calls specific to desktop GL.
void(glClearDepth)(GLdouble depth);
void(glDepthRange)(GLdouble n, GLdouble f);
#define FOR_EACH_IMPELLER_DESKTOP_ONLY_PROC(PROC) \
PROC(ClearDepth); \
PROC(DepthRange);
#define FOR_EACH_IMPELLER_GLES3_PROC(PROC) PROC(BlitFramebuffer);
#define FOR_EACH_IMPELLER_EXT_PROC(PROC) \
PROC(DebugMessageControlKHR); \
PROC(DiscardFramebufferEXT); \
PROC(FramebufferTexture2DMultisampleEXT); \
PROC(PushDebugGroupKHR); \
PROC(PopDebugGroupKHR); \
PROC(ObjectLabelKHR); \
PROC(RenderbufferStorageMultisampleEXT); \
PROC(GenQueriesEXT); \
PROC(DeleteQueriesEXT); \
PROC(GetQueryObjectui64vEXT); \
PROC(BeginQueryEXT); \
PROC(EndQueryEXT); \
PROC(GetQueryObjectuivEXT);
enum class DebugResourceType {
kTexture,
kBuffer,
kProgram,
kShader,
kRenderBuffer,
kFrameBuffer,
};
class ProcTableGLES {
public:
using Resolver = std::function<void*(const char* function_name)>;
explicit ProcTableGLES(Resolver resolver);
ProcTableGLES(ProcTableGLES&& other) = default;
~ProcTableGLES();
#define IMPELLER_PROC(name) \
GLProc<decltype(gl##name)> name = {"gl" #name, nullptr};
FOR_EACH_IMPELLER_PROC(IMPELLER_PROC);
FOR_EACH_IMPELLER_ES_ONLY_PROC(IMPELLER_PROC);
FOR_EACH_IMPELLER_DESKTOP_ONLY_PROC(IMPELLER_PROC);
FOR_EACH_IMPELLER_GLES3_PROC(IMPELLER_PROC);
FOR_EACH_IMPELLER_EXT_PROC(IMPELLER_PROC);
#undef IMPELLER_PROC
bool IsValid() const;
/// @brief Set the source for the attached [shader].
///
/// Optionally, [defines] may contain a string value that will be
/// append to the shader source after the version marker. This can be used to
/// support static specialization. For example, setting "#define Foo 1".
void ShaderSourceMapping(GLuint shader,
const fml::Mapping& mapping,
const std::vector<Scalar>& defines = {}) const;
const DescriptionGLES* GetDescription() const;
const std::shared_ptr<const CapabilitiesGLES>& GetCapabilities() const;
std::string DescribeCurrentFramebuffer() const;
std::string GetProgramInfoLogString(GLuint program) const;
bool IsCurrentFramebufferComplete() const;
bool SetDebugLabel(DebugResourceType type,
GLint name,
const std::string& label) const;
void PushDebugGroup(const std::string& string) const;
void PopDebugGroup() const;
// Visible For testing.
std::optional<std::string> ComputeShaderWithDefines(
const fml::Mapping& mapping,
const std::vector<Scalar>& defines) const;
private:
bool is_valid_ = false;
std::unique_ptr<DescriptionGLES> description_;
std::shared_ptr<const CapabilitiesGLES> capabilities_;
GLint debug_label_max_length_ = 0;
ProcTableGLES(const ProcTableGLES&) = delete;
ProcTableGLES& operator=(const ProcTableGLES&) = delete;
};
} // namespace impeller
#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_PROC_TABLE_GLES_H_