openMSX
GLUtil.cc
Go to the documentation of this file.
1#include "GLUtil.hh"
2#include "File.hh"
3#include "FileContext.hh"
4#include "FileException.hh"
5#include "InitException.hh"
6#include "vla.hh"
7#include "Version.hh"
8#include <iostream>
9#include <cstdio>
10
11using namespace openmsx;
12
13namespace gl {
14
15void checkGLError(std::string_view prefix)
16{
17 GLenum error = glGetError();
18 if (error != GL_NO_ERROR) {
19 // TODO this needs glu, but atm we don't link against glu (in windows)
20 //std::string err = (const char*)gluErrorString(error);
21 std::cerr << "GL error: " << prefix << ": " << int(error) << '\n';
22 assert(false);
23 }
24}
25
26
27// class Texture
28
29Texture::Texture(bool interpolation, bool wrap)
30{
31 allocate();
32 setInterpolation(interpolation);
33 setWrapMode(wrap);
34}
35
37{
38 glGenTextures(1, &textureId);
39}
40
42{
43 glDeleteTextures(1, &textureId); // ok to delete 0-texture
44 textureId = 0;
45}
46
47void Texture::setInterpolation(bool interpolation)
48{
49 bind();
50 int mode = interpolation ? GL_LINEAR : GL_NEAREST;
51 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mode);
52 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mode);
53}
54
55void Texture::setWrapMode(bool wrap)
56{
57 bind();
58 int mode = wrap ? GL_REPEAT : GL_CLAMP_TO_EDGE;
59 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode);
60 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode);
61}
62
63
64// class ColorTexture
65
66ColorTexture::ColorTexture(GLsizei width_, GLsizei height_)
67{
68 resize(width_, height_);
69}
70
71void ColorTexture::resize(GLsizei width_, GLsizei height_)
72{
73 width = width_;
74 height = height_;
75 bind();
76 glTexImage2D(
77 GL_TEXTURE_2D, // target
78 0, // level
79 GL_RGBA, // internal format
80 width, // width
81 height, // height
82 0, // border
83 GL_RGBA, // format
84 GL_UNSIGNED_BYTE, // type
85 nullptr); // data
86}
87
88
89// class FrameBufferObject
90
92{
93 glGenFramebuffers(1, &bufferId);
94 push();
95 glFramebufferTexture2D(GL_FRAMEBUFFER,
96 GL_COLOR_ATTACHMENT0,
97 GL_TEXTURE_2D, texture.textureId, 0);
98 bool success = glCheckFramebufferStatus(GL_FRAMEBUFFER) ==
99 GL_FRAMEBUFFER_COMPLETE;
100 pop();
101 if (!success) {
102 throw InitException(
103 "Your OpenGL implementation support for "
104 "framebuffer objects is too limited.");
105 }
106}
107
109{
110 pop();
111 glDeleteFramebuffers(1, &bufferId);
112}
113
115{
116 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &previousId);
117 glBindFramebuffer(GL_FRAMEBUFFER, bufferId);
118}
119
121{
122 glBindFramebuffer(GL_FRAMEBUFFER, GLuint(previousId));
123}
124
125
126// class Shader
127
128void Shader::init(GLenum type, std::string_view header, std::string_view filename)
129{
130 // Load shader source.
131 std::string source;
132 if constexpr (OPENGL_VERSION == OPENGL_ES_2_0) {
133 source += "#version 100\n";
134 if (type == GL_FRAGMENT_SHADER) {
135 source += "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
136 " precision highp float;\n"
137 "#else\n"
138 " precision mediump float;\n"
139 "#endif\n";
140 }
141 } else {
142 source += "#version 110\n";
143 }
144 source += header;
145 try {
146 File file(systemFileContext().resolve(tmpStrCat("shaders/", filename)));
147 auto mmap = file.mmap();
148 source.append(reinterpret_cast<const char*>(mmap.data()),
149 mmap.size());
150 } catch (FileException& e) {
151 std::cerr << "Cannot find shader: " << e.getMessage() << '\n';
152 handle = 0;
153 return;
154 }
155
156 // Allocate shader handle.
157 handle = glCreateShader(type);
158 if (handle == 0) {
159 std::cerr << "Failed to allocate shader\n";
160 return;
161 }
162
163 // Set shader source.
164 const char* sourcePtr = source.c_str();
165 glShaderSource(handle, 1, &sourcePtr, nullptr);
166
167 // Compile shader and print any errors and warnings.
168 glCompileShader(handle);
169 const bool ok = isOK();
170 GLint infoLogLength = 0;
171 glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &infoLogLength);
172 // note: the null terminator is included, so empty string has length 1
173 if (!ok || (!Version::RELEASE && infoLogLength > 1)) {
174 VLA(GLchar, infoLog, infoLogLength);
175 glGetShaderInfoLog(handle, infoLogLength, nullptr, infoLog.data());
176 std::cerr << (ok ? "Warning" : "Error") << "(s) compiling shader \""
177 << filename << "\":\n"
178 << (infoLogLength > 1 ? infoLog.data() : "(no details available)\n");
179 }
180}
181
183{
184 glDeleteShader(handle); // ok to delete '0'
185}
186
187bool Shader::isOK() const
188{
189 if (handle == 0) return false;
190 GLint compileStatus = GL_FALSE;
191 glGetShaderiv(handle, GL_COMPILE_STATUS, &compileStatus);
192 return compileStatus == GL_TRUE;
193}
194
195
196// class ShaderProgram
197
199{
200 handle = glCreateProgram();
201 if (handle == 0) {
202 std::cerr << "Failed to allocate program\n";
203 }
204}
205
207{
208 glDeleteProgram(handle); // ok to delete '0'
209 handle = 0;
210}
211
213{
214 if (handle == 0) return false;
215 GLint linkStatus = GL_FALSE;
216 glGetProgramiv(handle, GL_LINK_STATUS, &linkStatus);
217 return linkStatus == GL_TRUE;
218}
219
220void ShaderProgram::attach(const Shader& shader)
221{
222 // Sanity check on this program.
223 if (handle == 0) return;
224
225 // Sanity check on the shader.
226 if (!shader.isOK()) return;
227
228 // Attach it.
229 glAttachShader(handle, shader.handle);
230}
231
233{
234 // Sanity check on this program.
235 if (handle == 0) return;
236
237 // Link the program and print any errors and warnings.
238 glLinkProgram(handle);
239 const bool ok = isOK();
240 GLint infoLogLength = 0;
241 glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &infoLogLength);
242 // note: the null terminator is included, so empty string has length 1
243 if (!ok || (!Version::RELEASE && infoLogLength > 1)) {
244 VLA(GLchar, infoLog, infoLogLength);
245 glGetProgramInfoLog(handle, infoLogLength, nullptr, infoLog.data());
246 fprintf(stderr, "%s(s) linking shader program:\n%s\n",
247 ok ? "Warning" : "Error",
248 infoLogLength > 1 ? infoLog.data() : "(no details available)\n");
249 }
250}
251
252void ShaderProgram::bindAttribLocation(unsigned index, const char* name)
253{
254 glBindAttribLocation(handle, index, name);
255}
256
257GLint ShaderProgram::getUniformLocation(const char* name) const
258{
259 // Sanity check on this program.
260 if (!isOK()) return -1;
261
262 return glGetUniformLocation(handle, name);
263}
264
266{
267 glUseProgram(handle);
268}
269
270// only useful for debugging
272{
273 glValidateProgram(handle);
274 GLint validateStatus = GL_FALSE;
275 glGetProgramiv(handle, GL_VALIDATE_STATUS, &validateStatus);
276 GLint infoLogLength = 0;
277 glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &infoLogLength);
278 // note: the null terminator is included, so empty string has length 1
279 VLA(GLchar, infoLog, infoLogLength);
280 glGetProgramInfoLog(handle, infoLogLength, nullptr, infoLog.data());
281 std::cout << "Validate "
282 << ((validateStatus == GL_TRUE) ? "OK" : "FAIL")
283 << ": " << infoLog.data() << '\n';
284}
285
286
287// class BufferObject
288
290{
291 glGenBuffers(1, &bufferId);
292}
293
295{
296 glDeleteBuffers(1, &bufferId); // ok to delete 0-buffer
297}
298
299} // namespace gl
#define OPENGL_ES_2_0
Definition: GLUtil.hh:22
#define OPENGL_VERSION
Definition: GLUtil.hh:25
void resize(GLsizei width, GLsizei height)
Definition: GLUtil.cc:71
ColorTexture()=default
Default constructor, zero-sized texture.
FrameBufferObject()=default
void activate() const
Makes this program the active shader program.
Definition: GLUtil.cc:265
bool isOK() const
Returns true iff this program was linked without errors.
Definition: GLUtil.cc:212
void attach(const Shader &shader)
Adds a given shader to this program.
Definition: GLUtil.cc:220
void validate() const
Definition: GLUtil.cc:271
void allocate()
Allocate a shader program handle.
Definition: GLUtil.cc:198
void reset()
Release the shader program handle.
Definition: GLUtil.cc:206
void link()
Links all attached shaders together into one program.
Definition: GLUtil.cc:232
void bindAttribLocation(unsigned index, const char *name)
Bind the given name for a vertex shader attribute to the given location.
Definition: GLUtil.cc:252
GLint getUniformLocation(const char *name) const
Gets a reference to a uniform variable declared in the shader source.
Definition: GLUtil.cc:257
Wrapper around an OpenGL shader: a program executed on the GPU.
Definition: GLUtil.hh:323
bool isOK() const
Returns true iff this shader is loaded and compiled without errors.
Definition: GLUtil.cc:187
Most basic/generic texture: only contains a texture ID.
Definition: GLUtil.hh:40
void reset()
Release openGL texture name.
Definition: GLUtil.cc:41
Texture(const Texture &)=delete
void setWrapMode(bool wrap)
Definition: GLUtil.cc:55
void setInterpolation(bool interpolation)
Enable/disable bilinear interpolation for this texture.
Definition: GLUtil.cc:47
void bind()
Makes this texture the active GL texture.
Definition: GLUtil.hh:81
void allocate()
Allocate an openGL texture name.
Definition: GLUtil.cc:36
GLuint textureId
Definition: GLUtil.hh:93
Thrown when a subsystem initialisation fails.
constexpr double e
Definition: Math.hh:21
Definition: gl_mat.hh:23
void checkGLError(std::string_view prefix)
Definition: GLUtil.cc:15
This file implemented 3 utility functions:
Definition: Autofire.cc:9
const FileContext & systemFileContext()
Definition: FileContext.cc:155
TemporaryString tmpStrCat(Ts &&... ts)
Definition: strCat.hh:610
#define VLA(TYPE, NAME, LENGTH)
Definition: vla.hh:12