[libcamera-devel,v3,2/6] pipeline: simple: Implements Shader Handling
diff mbox series

Message ID 20220814160747.52093-2-kunalagarwal1072002@gmail.com
State New
Headers show
Series
  • [libcamera-devel,v3,1/6] pipeline: simple: shader: Shaders for debayering
Related show

Commit Message

Kunal Agarwal Aug. 14, 2022, 4:07 p.m. UTC
Shader Class which includes functions for building,
activating, deleting and compiling shaders

Signed-off-by: Kunal Agarwal <kunalagarwal1072002@gmail.com>
---
 src/libcamera/pipeline/simple/shader.cpp | 110 +++++++++++++++++++++++
 src/libcamera/pipeline/simple/shader.h   |  34 +++++++
 2 files changed, 144 insertions(+)
 create mode 100644 src/libcamera/pipeline/simple/shader.cpp
 create mode 100644 src/libcamera/pipeline/simple/shader.h

Comments

Kieran Bingham Aug. 14, 2022, 5:12 p.m. UTC | #1
Hi Kunal,

Quoting Kunal Agarwal via libcamera-devel (2022-08-14 17:07:43)
> Shader Class which includes functions for building,
> activating, deleting and compiling shaders

Great, Thanks for working on this, I've been looking forwards to how we
can integrate shaders directly into pipelines!

> Signed-off-by: Kunal Agarwal <kunalagarwal1072002@gmail.com>
> ---
>  src/libcamera/pipeline/simple/shader.cpp | 110 +++++++++++++++++++++++
>  src/libcamera/pipeline/simple/shader.h   |  34 +++++++
>  2 files changed, 144 insertions(+)
>  create mode 100644 src/libcamera/pipeline/simple/shader.cpp
>  create mode 100644 src/libcamera/pipeline/simple/shader.h
> 
> diff --git a/src/libcamera/pipeline/simple/shader.cpp b/src/libcamera/pipeline/simple/shader.cpp
> new file mode 100644
> index 00000000..f0079618
> --- /dev/null
> +++ b/src/libcamera/pipeline/simple/shader.cpp
> @@ -0,0 +1,110 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2022, Kunal Agarwal
> + *
> + * shader.cpp - Shader Handling
> + */
> +
> +#include "shader.h"
> +
> +#include <libcamera/base/file.h>
> +#include <libcamera/base/log.h>
> +
> +#include <GLES3/gl3.h>
> +
> +namespace libcamera {
> +
> +LOG_DECLARE_CATEGORY(SimplePipeline)

It may depend on how the development goes, but I think I'd see the
'Shader' support classes in core libcamera, along with suitable tests
that load and test under test/, and 'used' by the Simple Pipeline
handler.


That said, it probably doesn't hurt for it to start here, and move to
core later if / when it gets expanded for it's use cases.


> +
> +/* Reads a text file and outputs a string with everything in the text file */
> +static std::string get_file_contents(const char *filename)
> +{
> +       std::string fullname = std::string("/home/pi/Desktop/compile/libcamera/src/libcamera/pipeline/simple/shader/") + filename;

Perhaps this needs to be a libcamera defined data path?

The path /home/pi/Desktop ... doesn't map to anything useful on my
machine...

> +
> +       File file(fullname);
> +       if (!file.open(File::OpenModeFlag::ReadOnly))
> +               return "";
> +
> +       Span<uint8_t> data = file.map();
> +       return std::string(reinterpret_cast<char *>(data.data()), data.size());

At the point this function returns, I think "File file" will destruct,
and close - and then from that point on - this data is an invalid
use-after-free.


> +}
> +
> +/* Constructor that build the Shader Program from 2 different shaders */
> +void ShaderProgram::callShader(const char *vertexFile, const char *fragmentFile)
> +{
> +       /* Read vertexFile and fragmentFile and store the strings */
> +       std::string vertexCode = get_file_contents(vertexFile);
> +       std::string fragmentCode = get_file_contents(fragmentFile);
> +       const char *vertexSource = vertexCode.c_str();
> +       const char *fragmentSource = fragmentCode.c_str();
> +
> +       /* Create the vertex shader, set its source code and compile it. */
> +       GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
> +       glShaderSource(vertexShader, 1, &vertexSource, NULL);
> +       glCompileShader(vertexShader);
> +       compileErrors(vertexShader, "VERTEX");
> +
> +       /* Create the fragment shader, set its source code and compile it. */
> +       GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
> +       glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
> +       glCompileShader(fragmentShader);
> +       compileErrors(fragmentShader, "FRAGMENT");
> +
> +       /* Create Shader Program Object and get its reference */
> +       id_ = glCreateProgram();
> +
> +       /* Attach and wrap-up/link the Vertex and Fragment Shaders to the Shader Program */
> +       glAttachShader(id_, vertexShader);
> +       glAttachShader(id_, fragmentShader);
> +       glLinkProgram(id_);
> +
> +       /* Checks if Shaders linked succesfully */
> +       compileErrors(id_, "PROGRAM");
> +
> +       /* Delete the Vertex and Fragment Shader objects. Here, they are flagged for deletion
> +          and will not be deleted until they are detached from the program object. This frees
> +          up the memory used to store the shader source. */

	/*
	 * Multiline comment style should look like
	 * this, and be wrapped at ~80 characters.
	 */

It sounds like the Vertex, and Fragment shader objects are reference
counted by OpenGL and so all we're really doing here is releasing our
reference, but they'll persist while they are in used by an active
shader/program?


> +       glDeleteShader(vertexShader);
> +       glDeleteShader(fragmentShader);
> +}
> +
> +/* Activates the Shader Program */
> +void ShaderProgram::activate()
> +{
> +       glUseProgram(id_);
> +}
> +
> +/* Deletes the Shader Program */
> +void ShaderProgram::deleteProgram()
> +{
> +       glDeleteProgram(id_);
> +}
> +
> +/* Checks if the different Shaders have compiled properly */
> +void ShaderProgram::compileErrors(unsigned int shader, const char *type)
> +{
> +       /* Stores status of compilation */
> +       GLint hasCompiled;
> +       GLint logLength;
> +       /* Character array to store error message in */
> +       glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
> +       char *infoLog = new char[logLength];
> +       if (strcmp(type, "PROGRAM") != 0) {
> +               glGetShaderiv(shader, GL_COMPILE_STATUS, &hasCompiled);
> +               if (hasCompiled == GL_FALSE) {
> +                       glGetShaderInfoLog(shader, logLength, NULL, infoLog);
> +                       LOG(SimplePipeline, Error) << "SHADER_COMPILATION_ERROR for:"
> +                                                  << type << "\t"
> +                                                  << infoLog;
> +               }
> +       } else {
> +               glGetProgramiv(shader, GL_LINK_STATUS, &hasCompiled);
> +               if (hasCompiled == GL_FALSE) {
> +                       glGetProgramInfoLog(shader, logLength, NULL, infoLog);
> +                       LOG(SimplePipeline, Error) << "SHADER_LINKING_ERROR for:"
> +                                                  << type << "\t"
> +                                                  << infoLog;
> +               }
> +       }
> +}
> +} /* namespace libcamera */
> diff --git a/src/libcamera/pipeline/simple/shader.h b/src/libcamera/pipeline/simple/shader.h
> new file mode 100644
> index 00000000..921e4040
> --- /dev/null
> +++ b/src/libcamera/pipeline/simple/shader.h
> @@ -0,0 +1,34 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2022, Kunal Agarwal
> + *
> + * shader.h - Shader Handling
> + */
> +
> +#pragma once
> +
> +#include <iostream>
> +#include <string.h>
> +
> +#include <GL/gl.h>
> +
> +namespace libcamera {
> +
> +class ShaderProgram
> +{
> +public:
> +       void callShader(const char *vertexFile, const char *fragmentFile);
> +
> +       void activate();
> +
> +       void deleteProgram();
> +
> +       int id() const { return id_; };
> +
> +private:
> +       /* Reference ID of the Shader Program */
> +       GLuint id_;
> +       void compileErrors(unsigned int shader, const char *type);
> +};
> +
> +} /* namespace libcamera */
> -- 
> 2.25.1
>

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/simple/shader.cpp b/src/libcamera/pipeline/simple/shader.cpp
new file mode 100644
index 00000000..f0079618
--- /dev/null
+++ b/src/libcamera/pipeline/simple/shader.cpp
@@ -0,0 +1,110 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022, Kunal Agarwal
+ *
+ * shader.cpp - Shader Handling
+ */
+
+#include "shader.h"
+
+#include <libcamera/base/file.h>
+#include <libcamera/base/log.h>
+
+#include <GLES3/gl3.h>
+
+namespace libcamera {
+
+LOG_DECLARE_CATEGORY(SimplePipeline)
+
+/* Reads a text file and outputs a string with everything in the text file */
+static std::string get_file_contents(const char *filename)
+{
+	std::string fullname = std::string("/home/pi/Desktop/compile/libcamera/src/libcamera/pipeline/simple/shader/") + filename;
+
+	File file(fullname);
+	if (!file.open(File::OpenModeFlag::ReadOnly))
+		return "";
+
+	Span<uint8_t> data = file.map();
+	return std::string(reinterpret_cast<char *>(data.data()), data.size());
+}
+
+/* Constructor that build the Shader Program from 2 different shaders */
+void ShaderProgram::callShader(const char *vertexFile, const char *fragmentFile)
+{
+	/* Read vertexFile and fragmentFile and store the strings */
+	std::string vertexCode = get_file_contents(vertexFile);
+	std::string fragmentCode = get_file_contents(fragmentFile);
+	const char *vertexSource = vertexCode.c_str();
+	const char *fragmentSource = fragmentCode.c_str();
+
+	/* Create the vertex shader, set its source code and compile it. */
+	GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
+	glShaderSource(vertexShader, 1, &vertexSource, NULL);
+	glCompileShader(vertexShader);
+	compileErrors(vertexShader, "VERTEX");
+
+	/* Create the fragment shader, set its source code and compile it. */
+	GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
+	glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
+	glCompileShader(fragmentShader);
+	compileErrors(fragmentShader, "FRAGMENT");
+
+	/* Create Shader Program Object and get its reference */
+	id_ = glCreateProgram();
+
+	/* Attach and wrap-up/link the Vertex and Fragment Shaders to the Shader Program */
+	glAttachShader(id_, vertexShader);
+	glAttachShader(id_, fragmentShader);
+	glLinkProgram(id_);
+
+	/* Checks if Shaders linked succesfully */
+	compileErrors(id_, "PROGRAM");
+
+	/* Delete the Vertex and Fragment Shader objects. Here, they are flagged for deletion
+	   and will not be deleted until they are detached from the program object. This frees
+	   up the memory used to store the shader source. */
+	glDeleteShader(vertexShader);
+	glDeleteShader(fragmentShader);
+}
+
+/* Activates the Shader Program */
+void ShaderProgram::activate()
+{
+	glUseProgram(id_);
+}
+
+/* Deletes the Shader Program */
+void ShaderProgram::deleteProgram()
+{
+	glDeleteProgram(id_);
+}
+
+/* Checks if the different Shaders have compiled properly */
+void ShaderProgram::compileErrors(unsigned int shader, const char *type)
+{
+	/* Stores status of compilation */
+	GLint hasCompiled;
+	GLint logLength;
+	/* Character array to store error message in */
+	glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
+	char *infoLog = new char[logLength];
+	if (strcmp(type, "PROGRAM") != 0) {
+		glGetShaderiv(shader, GL_COMPILE_STATUS, &hasCompiled);
+		if (hasCompiled == GL_FALSE) {
+			glGetShaderInfoLog(shader, logLength, NULL, infoLog);
+			LOG(SimplePipeline, Error) << "SHADER_COMPILATION_ERROR for:"
+						   << type << "\t"
+						   << infoLog;
+		}
+	} else {
+		glGetProgramiv(shader, GL_LINK_STATUS, &hasCompiled);
+		if (hasCompiled == GL_FALSE) {
+			glGetProgramInfoLog(shader, logLength, NULL, infoLog);
+			LOG(SimplePipeline, Error) << "SHADER_LINKING_ERROR for:"
+						   << type << "\t"
+						   << infoLog;
+		}
+	}
+}
+} /* namespace libcamera */
diff --git a/src/libcamera/pipeline/simple/shader.h b/src/libcamera/pipeline/simple/shader.h
new file mode 100644
index 00000000..921e4040
--- /dev/null
+++ b/src/libcamera/pipeline/simple/shader.h
@@ -0,0 +1,34 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022, Kunal Agarwal
+ *
+ * shader.h - Shader Handling
+ */
+
+#pragma once
+
+#include <iostream>
+#include <string.h>
+
+#include <GL/gl.h>
+
+namespace libcamera {
+
+class ShaderProgram
+{
+public:
+	void callShader(const char *vertexFile, const char *fragmentFile);
+
+	void activate();
+
+	void deleteProgram();
+
+	int id() const { return id_; };
+
+private:
+	/* Reference ID of the Shader Program */
+	GLuint id_;
+	void compileErrors(unsigned int shader, const char *type);
+};
+
+} /* namespace libcamera */