File: GLShader.cpp

package info (click to toggle)
jazz2-native 3.5.0-2
  • links: PTS, VCS
  • area: contrib
  • in suites: forky, sid
  • size: 16,912 kB
  • sloc: cpp: 172,557; xml: 113; python: 36; makefile: 5; sh: 2
file content (160 lines) | stat: -rw-r--r-- 4,344 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include "GLShader.h"
#include "GLDebug.h"
#include "../RenderResources.h"
#include "../../Application.h"
#include "../../../Main.h"

#include <string>

#include <IO/FileSystem.h>

using namespace Death::Containers::Literals;
using namespace Death::IO;

namespace nCine
{
	namespace
	{
#if (defined(WITH_OPENGLES) && GL_ES_VERSION_3_0) || defined(DEATH_TARGET_EMSCRIPTEN)
		static constexpr StringView CommonShaderVersion = "#version 300 es\n"_s;
#else
		static constexpr StringView CommonShaderVersion = "#version 330\n"_s;
#endif

#if defined(DEATH_TARGET_EMSCRIPTEN)
		static constexpr StringView CommonShaderDefines = "#define DEATH_TARGET_EMSCRIPTEN\n#line 0\n"_s;
#elif defined(DEATH_TARGET_ANDROID)
		static constexpr StringView CommonShaderDefines = "#define DEATH_TARGET_ANDROID\n#line 0\n"_s;
#elif defined(WITH_ANGLE)
		static constexpr StringView CommonShaderDefines = "#define WITH_ANGLE\n#line 0\n"_s;
#else
		static constexpr StringView CommonShaderDefines = "#line 0\n"_s;
#endif
	}

	GLShader::GLShader(GLenum type)
		: glHandle_(0), status_(Status::NotCompiled)
	{
		glHandle_ = glCreateShader(type);
	}

	GLShader::GLShader(GLenum type, StringView filename)
		: GLShader(type)
	{
		LoadFromFile(filename);
	}

	GLShader::~GLShader()
	{
		glDeleteShader(glHandle_);
	}

	bool GLShader::LoadFromString(StringView string)
	{
		return LoadFromStringsAndFile(arrayView({ string }), {});
	}
	
	bool GLShader::LoadFromStringAndFile(StringView string, StringView filename)
	{
		return LoadFromStringsAndFile(arrayView({ string }), filename);
	}

	bool GLShader::LoadFromStrings(ArrayView<const StringView> strings)
	{
		return LoadFromStringsAndFile(strings, {});
	}

	bool GLShader::LoadFromStringsAndFile(ArrayView<const StringView> strings, StringView filename)
	{
		if (strings.empty() && filename.empty()) {
			return false;
		}
		
		SmallVector<const char*, 10> sourceStrings;
		SmallVector<GLint, 10> sourceLengths;

		sourceStrings.push_back(CommonShaderVersion.data());
		sourceLengths.push_back(static_cast<GLint>(CommonShaderVersion.size()));
		sourceStrings.push_back(CommonShaderDefines.data());
		sourceLengths.push_back(static_cast<GLint>(CommonShaderDefines.size()));

		for (auto string : strings) {
			sourceStrings.push_back(string.data());
			sourceLengths.push_back(static_cast<GLint>(string.size()));
		}

		String fileSource;
		if (!filename.empty()) {
			std::unique_ptr<Stream> fileHandle = fs::Open(filename, FileAccess::Read);
			if (!fileHandle->IsValid()) {
				return false;
			}
			
			const GLint fileLength = static_cast<int>(fileHandle->GetSize());
			fileSource = String{NoInit, static_cast<std::size_t>(fileLength)};
			fileHandle->Read(fileSource.data(), fileLength);
			
			sourceStrings.push_back(fileSource.data());
			sourceLengths.push_back(static_cast<GLint>(fileLength));

			SetObjectLabel(filename.data());
		}

		std::size_t count = sourceStrings.size();
		glShaderSource(glHandle_, GLsizei(count), sourceStrings.data(), sourceLengths.data());
		return (count > 1);
	}
	
	bool GLShader::LoadFromFile(StringView filename)
	{
		return LoadFromStringsAndFile({}, filename);
	}

	bool GLShader::Compile(ErrorChecking errorChecking, bool logOnErrors)
	{
		glCompileShader(glHandle_);

		if (errorChecking == ErrorChecking::Immediate) {
			return CheckCompilation(logOnErrors);
		} else {
			status_ = Status::CompiledWithDeferredChecks;
			return true;
		}
	}

	bool GLShader::CheckCompilation(bool logOnErrors)
	{
		if (status_ == Status::Compiled) {
			return true;
		}

		GLint status = GL_FALSE;
		glGetShaderiv(glHandle_, GL_COMPILE_STATUS, &status);
		if (status == GL_FALSE) {
#if defined(DEATH_TRACE)
			if (logOnErrors) {
				GLint length = 0;
				glGetShaderiv(glHandle_, GL_INFO_LOG_LENGTH, &length);
				if (length > 0) {
					static char buffer[2048];
					glGetShaderInfoLog(glHandle_, sizeof(buffer), &length, buffer);
					// Trim whitespace - driver messages usually contain newline(s) at the end
					*(MutableStringView(buffer).trimmed().end()) = '\0';
					LOGW("Shader: {}", buffer);
				}
				DEATH_ASSERT_BREAK();
			}
#endif
			status_ = Status::CompilationFailed;
			return false;
		}

		status_ = Status::Compiled;
		return true;
	}

	void GLShader::SetObjectLabel(StringView label)
	{
		GLDebug::SetObjectLabel(GLDebug::LabelTypes::Shader, glHandle_, label);
	}
}