Gamp v0.0.7-54-gccdc599
Gamp: Graphics, Audio, Multimedia and Processing
Loading...
Searching...
No Matches
ShaderCode.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright Gothel Software e.K.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * This Source Code Form is subject to the terms of the MIT License
8 * If a copy of the MIT was not distributed with this file,
9 * you can obtain one at https://opensource.org/license/mit/.
10 */
11
12#ifndef GAMP_GLSLSHADERCODE_HPP_
13#define GAMP_GLSLSHADERCODE_HPP_
14
15#include <fstream>
16
17#include <jau/basic_types.hpp>
18#include <jau/debug.hpp>
19#include <jau/io/file_util.hpp>
20#include <jau/io/io_util.hpp>
21#include <jau/string_util.hpp>
22
23#include <gamp/Gamp.hpp>
25
26namespace gamp::render::gl::glsl {
27 using namespace gamp::render::gl;
28
29 /** @defgroup Gamp_GLSL Gamp GL Shader Support
30 * OpenGL Shading Language types and functionality.
31 *
32 * @{
33 */
34
35 class ShaderCode;
36 typedef std::shared_ptr<ShaderCode> ShaderCodeRef;
37
38 /**
39 * Convenient shader code class to use and instantiate vertex or fragment programs.
40 * <p>
41 * A documented example of how to use this code is available
42 * {@link #create(GL2ES2, int, Class, String, String, String, boolean) here} and
43 * {@link #create(GL2ES2, int, int, Class, String, String[], String, String) here}.
44 * </p>
45 * <p>
46 * Support for {@link GL4#GL_TESS_CONTROL_SHADER} and {@link GL4#GL_TESS_EVALUATION_SHADER}
47 * was added since 2.2.1.
48 * </p>
49 */
50 class ShaderCode {
51 public:
52 static bool DEBUG_CODE;
53
54 /** Unique resource suffix for {@link GL2ES2#GL_VERTEX_SHADER} in source code: <code>{@value}</code> */
55 static constexpr std::string_view SUFFIX_VERTEX_SOURCE = "vp" ;
56
57 /** Unique resource suffix for {@link GL2ES2#GL_VERTEX_SHADER} in binary: <code>{@value}</code> */
58 static constexpr std::string_view SUFFIX_VERTEX_BINARY = "bvp" ;
59
60 /** Unique resource suffix for {@link GL3#GL_GEOMETRY_SHADER} in source code: <code>{@value}</code> */
61 static constexpr std::string_view SUFFIX_GEOMETRY_SOURCE = "gp" ;
62
63 /** Unique resource suffix for {@link GL3#GL_GEOMETRY_SHADER} in binary: <code>{@value}</code> */
64 static constexpr std::string_view SUFFIX_GEOMETRY_BINARY = "bgp" ;
65
66 /**
67 * Unique resource suffix for {@link GL3ES3#GL_COMPUTE_SHADER} in source code: <code>{@value}</code>
68 * @since 2.3.2
69 */
70 static constexpr std::string_view SUFFIX_COMPUTE_SOURCE = "cp" ;
71
72 /**
73 * Unique resource suffix for {@link GL3ES3#GL_COMPUTE_SHADER} in binary: <code>{@value}</code>
74 * @since 2.3.2
75 */
76 static constexpr std::string_view SUFFIX_COMPUTE_BINARY = "bcp" ;
77
78 /**
79 * Unique resource suffix for {@link GL4#GL_TESS_CONTROL_SHADER} in source code: <code>{@value}</code>
80 * @since 2.2.1
81 */
82 static constexpr std::string_view SUFFIX_TESS_CONTROL_SOURCE = "tcp" ;
83
84 /**
85 * Unique resource suffix for {@link GL4#GL_TESS_CONTROL_SHADER} in binary: <code>{@value}</code>
86 * @since 2.2.1
87 */
88 static constexpr std::string_view SUFFIX_TESS_CONTROL_BINARY = "btcp" ;
89
90 /**
91 * Unique resource suffix for {@link GL4#GL_TESS_EVALUATION_SHADER} in source code: <code>{@value}</code>
92 * @since 2.2.1
93 */
94 static constexpr std::string_view SUFFIX_TESS_EVALUATION_SOURCE = "tep" ;
95
96 /**
97 * Unique resource suffix for {@link GL4#GL_TESS_EVALUATION_SHADER} in binary: <code>{@value}</code>
98 * @since 2.2.1
99 */
100 static constexpr std::string_view SUFFIX_TESS_EVALUATION_BINARY = "btep" ;
101
102 /** Unique resource suffix for {@link GL2ES2#GL_FRAGMENT_SHADER} in source code: <code>{@value}</code> */
103 static constexpr std::string_view SUFFIX_FRAGMENT_SOURCE = "fp" ;
104
105 /** Unique resource suffix for {@link GL2ES2#GL_FRAGMENT_SHADER} in binary: <code>{@value}</code> */
106 static constexpr std::string_view SUFFIX_FRAGMENT_BINARY = "bfp" ;
107
108 /** Unique relative path for binary shader resources for {@link GLES2#GL_NVIDIA_PLATFORM_BINARY_NV NVIDIA}: <code>{@value}</code> */
109 static constexpr std::string_view SUB_PATH_NVIDIA = "nvidia" ;
110
111 private:
112 struct Private{ explicit Private() = default; };
113
114 public:
115
116 /** Private ctor for `ShaderCodeRef create(...). */
117 ShaderCode(Private, GLenum type, size_t count, const source_list_t& sources) noexcept
118 : m_shaderBinaryFormat(0), m_shaderType(0), m_id(0), m_compiled(false)
119 {
120 if(sources.size() != count) {
121 ERR_PRINT("shader number (%zu) and sourceFiles array (%zu) of different length.", count, sources.size());
122 return;
123 }
124 if( !isValidShaderType(type) ) {
125 ERR_PRINT("Invalid shader type: %u", type);
126 return;
127 }
128 m_shaderSource = sources;
129 // m_shaderBinary = null;
130 m_shaderType = type;
131 m_shader.reserve(count);
132 m_shader.resize(count, 0);
133 m_id = nextID();
134 }
135 /**
136 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
137 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
138 * @param count number of shaders
139 * @param sources shader sources, organized as <code>source[count][strings-per-shader]</code>.
140 * @return successfully created valid ShaderCodeRef or nullptr on failure
141 */
142 static ShaderCodeRef create(GLenum type, size_t count, const source_list_t& sources) noexcept {
143 ShaderCodeRef res = std::make_shared<ShaderCode>(Private(), type, count, sources);
144 if( res->isValid() ) {
145 return res;
146 }
147 return nullptr;
148 }
149
150 /** Private ctor for `ShaderCodeRef create(...). */
151 ShaderCode(Private, GLenum type, size_t count, GLenum binFormat, const bytes_t& binary) noexcept
152 : m_shaderBinaryFormat(0), m_shaderType(0), m_id(0), m_compiled(false)
153 {
154 if( !isValidShaderType(type) ) {
155 ERR_PRINT("Invalid shader type: %u", type);
156 return;
157 }
158 // shaderSource = null;
159 m_shaderBinaryFormat = binFormat;
160 m_shaderBinary = binary;
161 m_shaderType = type;
162 m_shader.reserve(count);
163 m_shader.resize(count, 0);
164 m_id = nextID();
165 }
166 /**
167 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
168 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
169 * @param count number of shaders
170 * @param binary binary buffer containing the shader binaries,
171 * @return successfully created valid ShaderCodeRef or nullptr on failure
172 */
173 static ShaderCodeRef create(GLenum type, size_t count, GLenum binFormat, const bytes_t& binary) noexcept {
174 ShaderCodeRef res = std::make_shared<ShaderCode>(Private(), type, count, binFormat, binary);
175 if( res->isValid() ) {
176 return res;
177 }
178 return nullptr;
179 }
180
181 /**
182 * Creates a complete {@link ShaderCode} object while reading all shader source of <code>sourceFiles</code>,
183 * which location is resolved using the <code>context</code> class, see readShaderSource().
184 *
185 * @param gl current GL object to determine whether a shader compiler is available. If null, no validation is performed.
186 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
187 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
188 * @param count number of shaders
189 * @param context class used to help resolving the source location
190 * @param sourceFiles array of source locations, organized as <code>sourceFiles[count]</code> -> <code>shaderSources[count][1]</code>
191 * @return successfully created valid ShaderCodeRef or nullptr on failure
192 *
193 * @see #readShaderSource()
194 */
195 static ShaderCodeRef create(GL& gl, GLenum type, size_t count, const string_list_t& sourceFiles) noexcept {
197 ERR_PRINT("No shader compiler available for %s", gl.toString().c_str());
198 return nullptr;
199 }
200 if( !isValidShaderType(type) ) {
201 ERR_PRINT("Invalid shader type: %u", type);
202 return nullptr;
203 }
204 string_list_t one_string;
205 one_string.reserve(1);
206 one_string.resize(1, "");
207 const size_t sourceFileCount = sourceFiles.size();
208 source_list_t shaderSources;
209 bool ok = true;
210 if(sourceFileCount > 0) {
211 // sourceFiles.length and count is validated in ctor
212 shaderSources.reserve(sourceFileCount);
213 shaderSources.resize(sourceFileCount, one_string);
214 for(size_t i=0; i<sourceFileCount && ok; ++i) {
215 ok = readShaderSource(sourceFiles[i], shaderSources[i][0]);
216 }
217 }
218 if( ok ) {
219 ShaderCodeRef res = create(type, count, shaderSources);
220 if( res->isValid() ) {
221 return res;
222 }
223 }
224 return nullptr;
225 }
226
227#if 0
228// FIXME JAU COMPLETE
229
230 /**
231 * Creates a complete {@link ShaderCode} object while reading all shader sources from {@link Uri} <code>sourceLocations</code>
232 * via {@link #readShaderSource(Uri, boolean)}.
233 *
234 * @param gl current GL object to determine whether a shader compiler is available. If null, no validation is performed.
235 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
236 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
237 * @param count number of shaders
238 * @param sourceLocations array of {@link Uri} source locations, organized as <code>sourceFiles[count]</code> -> <code>shaderSources[count][1]</code>
239 * @return successfully created valid ShaderCodeRef or nullptr on failure
240 *
241 * @see #readShaderSource(Uri, boolean)
242 * @since 2.3.2
243 */
244 static ShaderCodeRef create(GL& gl, GLenum type, size_t count,
245 const std::vector<Uri>& sourceLocations, bool mutableStringBuilder) noexcept {
246 if(null != gl && !ShaderUtil.isShaderCompilerAvailable(gl)) {
247 return null;
248 }
249
250 CharSequence[][] shaderSources = null;
251 if(null!=sourceLocations) {
252 // sourceFiles.length and count is validated in ctor
253 shaderSources = new CharSequence[sourceLocations.length][1];
254 for(int i=0; i<sourceLocations.length; i++) {
255 try {
256 shaderSources[i][0] = readShaderSource(sourceLocations[i], mutableStringBuilder);
257 } catch (final IOException ioe) {
258 throw RuntimeException("readShaderSource("+sourceLocations[i]+") error: ", ioe);
259 }
260 if(null == shaderSources[i][0]) {
261 shaderSources = null;
262 }
263 }
264 }
265 if(null==shaderSources) {
266 return null;
267 }
268 return new ShaderCode(type, count, shaderSources);
269 }
270
271 /**
272 * Creates a complete {@link ShaderCode} object while reading the shader binary of <code>binaryFile</code>,
273 * which location is resolved using the <code>context</code> class, see {@link #readShaderBinary(Class, String)}.
274 *
275 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
276 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
277 * @param count number of shaders
278 * @param context class used to help resolving the source location
279 * @param binFormat a valid native binary format as they can be queried by {@link ShaderUtil#getShaderBinaryFormats(GL)}.
280 * @param sourceFiles array of source locations, organized as <code>sourceFiles[count]</code>
281 * @return successfully created valid ShaderCodeRef or nullptr on failure
282 *
283 * @see #readShaderBinary(Class, String)
284 * @see ShaderUtil#getShaderBinaryFormats(GL)
285 */
286 public static ShaderCode create(final int type, final int count, final Class<?> context, int binFormat, final String binaryFile) noexcept {
287 ByteBuffer shaderBinary = null;
288 if(null!=binaryFile && 0<=binFormat) {
289 try {
290 shaderBinary = readShaderBinary(context, binaryFile);
291 } catch (final IOException ioe) {
292 throw RuntimeException("readShaderBinary("+binaryFile+") error: ", ioe);
293 }
294 if(null == shaderBinary) {
295 binFormat = -1;
296 }
297 }
298 if(null==shaderBinary) {
299 return null;
300 }
301 return new ShaderCode(type, count, binFormat, shaderBinary);
302 }
303
304#endif
305
306 /**
307 * Returns a unique suffix for shader resources as follows:
308 * <ul>
309 * <li>Source<ul>
310 * <li>{@link GL2ES2#GL_VERTEX_SHADER vertex}: {@link #SUFFIX_VERTEX_SOURCE}</li>
311 * <li>{@link GL2ES2#GL_FRAGMENT_SHADER fragment}: {@link #SUFFIX_FRAGMENT_SOURCE}</li>
312 * <li>{@link GL3#GL_GEOMETRY_SHADER geometry}: {@link #SUFFIX_GEOMETRY_SOURCE}</li>
313 * <li>{@link GL4#GL_TESS_CONTROL_SHADER tess-ctrl}: {@link #SUFFIX_TESS_CONTROL_SOURCE}</li>
314 * <li>{@link GL4#GL_TESS_EVALUATION_SHADER tess-eval}: {@link #SUFFIX_TESS_EVALUATION_SOURCE}</li>
315 * <li>{@link GL3ES3#GL_COMPUTE_SHADER}: {@link #SUFFIX_COMPUTE_SOURCE}</li>
316 * </ul></li>
317 * <li>Binary<ul>
318 * <li>{@link GL2ES2#GL_VERTEX_SHADER vertex}: {@link #SUFFIX_VERTEX_BINARY}</li>
319 * <li>{@link GL2ES2#GL_FRAGMENT_SHADER fragment}: {@link #SUFFIX_FRAGMENT_BINARY}</li>
320 * <li>{@link GL3#GL_GEOMETRY_SHADER geometry}: {@link #SUFFIX_GEOMETRY_BINARY}</li>
321 * <li>{@link GL4#GL_TESS_CONTROL_SHADER tess-ctrl}: {@link #SUFFIX_TESS_CONTROL_BINARY}</li>
322 * <li>{@link GL4#GL_TESS_EVALUATION_SHADER tess-eval}: {@link #SUFFIX_TESS_EVALUATION_BINARY}</li>
323 * <li>{@link GL3ES3#GL_COMPUTE_SHADER}: {@link #SUFFIX_COMPUTE_BINARY}</li>
324 * </ul></li>
325 * </ul>
326 * @param binary true for a binary resource, false for a source resource
327 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
328 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
329 * @return suffix for valid shader type or zero sized view if invalid
330 *
331 * @see #create(GL2ES2, int, Class, String, String, String, boolean)
332 */
333 static std::string_view getFileSuffix(bool binary, GLenum type) noexcept {
334 switch (type) {
335 case GL_VERTEX_SHADER: // GL2ES2
337 case GL_FRAGMENT_SHADER: // GL2ES2
339 case GL_GEOMETRY_SHADER: // GL3ES3
341 case GL_TESS_CONTROL_SHADER: // GL3ES3
343 case GL_TESS_EVALUATION_SHADER: // GL3ES3
345 case GL_COMPUTE_SHADER: // GL3ES3
347 default:
348 return "";
349 }
350 }
351
352 /**
353 * Returns a unique relative path for binary shader resources as follows:
354 * <ul>
355 * <li>{@link GLES2#GL_NVIDIA_PLATFORM_BINARY_NV NVIDIA}: {@link #SUB_PATH_NVIDIA}</li>
356 * </ul>
357 * @return path for valid binary shader types or zero sized view if invalid
358 *
359 * @see #create(GL2ES2, int, Class, String, String, String, boolean)
360 */
361 static std::string_view getBinarySubPath(GLenum binFormat) noexcept {
362 switch (binFormat) {
363 case GL_NVIDIA_PLATFORM_BINARY_NV: // GLES2
364 return SUB_PATH_NVIDIA;
365 default:
366 return "";
367 }
368 }
369
370 /**
371 * Convenient creation method for instantiating a complete {@link ShaderCode} object
372 * either from source code using {@link #create(GL2ES2, int, int, Class, String[])},
373 * or from a binary code using {@link #create(int, int, Class, int, String)},
374 * whatever is available first.
375 * <p>
376 * The source and binary location names are expected w/o suffixes which are
377 * resolved and appended using the given {@code srcSuffixOpt} and {@code binSuffixOpt}
378 * if not {@code null}, otherwise {@link #getFileSuffix(boolean, int)} determines the suffixes.
379 * </p>
380 * <p>
381 * Additionally, the binary resource is expected within a subfolder of <code>binRoot</code>
382 * which reflects the vendor specific binary format, see {@link #getBinarySubPath(int)}.
383 * All {@link ShaderUtil#getShaderBinaryFormats(GL)} are being iterated
384 * using the binary subfolder, the first existing resource is being used.
385 * </p>
386 *
387 * Example:
388 * <pre>
389 * Your std JVM layout (plain or within a JAR):
390 *
391 * org/test/glsl/MyShaderTest.class
392 * org/test/glsl/shader/vertex.vp
393 * org/test/glsl/shader/fragment.fp
394 * org/test/glsl/shader/bin/nvidia/vertex.bvp
395 * org/test/glsl/shader/bin/nvidia/fragment.bfp
396 *
397 * Your Android APK layout:
398 *
399 * classes.dex
400 * assets/org/test/glsl/shader/vertex.vp
401 * assets/org/test/glsl/shader/fragment.fp
402 * assets/org/test/glsl/shader/bin/nvidia/vertex.bvp
403 * assets/org/test/glsl/shader/bin/nvidia/fragment.bfp
404 * ...
405 *
406 * Your invocation in org/test/glsl/MyShaderTest.java:
407 *
408 * ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, this.getClass(),
409 * "shader", new String[] { "vertex" }, null,
410 * "shader/bin", "vertex", null, true);
411 * ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, this.getClass(),
412 * "shader", new String[] { "vertex" }, null,
413 * "shader/bin", "fragment", null, true);
414 * ShaderProgram sp0 = new ShaderProgram();
415 * sp0.add(gl, vp0, System.err);
416 * sp0.add(gl, fp0, System.err);
417 * st.attachShaderProgram(gl, sp0, true);
418 * </pre>
419 * A simplified entry point is {@link #create(GL, int, String, String, String, boolean)}.
420 *
421 * <p>
422 * The location is finally being resolved using the <code>context</code> class, see {@link #readShaderBinary(Class, String)}.
423 * </p>
424 *
425 * @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used),
426 * or to determine the shader binary format (if <code>binary</code> is used).
427 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
428 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
429 * @param count number of shaders
430 * @param context class used to help resolving the source and binary location
431 * @param srcRoot relative <i>root</i> path for <code>srcBasenames</code> optional
432 * @param srcBasenames basenames w/o path or suffix relative to <code>srcRoot</code> for the shader's source code
433 * @param srcSuffixOpt optional custom suffix for shader's source file,
434 * if {@code null} {@link #getFileSuffix(boolean, int)} is being used.
435 * @param binRoot relative <i>root</i> path for <code>binBasenames</code>
436 * @param binBasename basename w/o path or suffix relative to <code>binRoot</code> for the shader's binary code
437 * @param binSuffixOpt optional custom suffix for shader's binary file,
438 * if {@code null} {@link #getFileSuffix(boolean, int)} is being used.
439 * @return successfully created valid ShaderCodeRef or nullptr on failure
440 *
441 * @see #create(GL2ES2, int, int, Class, String[])
442 * @see #create(int, int, Class, int, String)
443 * @see #readShaderSource(Class, String)
444 * @see #getFileSuffix(boolean, int)
445 * @see ShaderUtil#getShaderBinaryFormats(GL)
446 * @see #getBinarySubPath(int)
447 *
448 * @since 2.3.2
449 */
450 static ShaderCodeRef create(GL& gl, GLenum type, size_t count,
451 stringview_t srcRoot, const string_list_t& srcBasenames, stringview_t srcSuffixOpt,
452 stringview_t binRoot, stringview_t binBasename, stringview_t binSuffixOpt) noexcept {
453 ShaderCodeRef res;
454 string_t srcPathsString;
455 string_t binFileName;
456
457 if( !srcBasenames.empty() && ShaderUtil::isShaderCompilerAvailable(gl) ) {
458 string_list_t srcPaths;
459 srcPaths.resize(srcBasenames.size());
460 stringview_t srcSuffix = !srcSuffixOpt.empty() ? srcSuffixOpt : getFileSuffix(false, type);
461 if( !srcRoot.empty() ) {
462 for(size_t i=0; i<srcPaths.size(); ++i) {
463 srcPaths[i] = string_t(srcRoot).append("/").append(srcBasenames[i]).append(".").append(srcSuffix);
464 }
465 } else {
466 for(size_t i=0; i<srcPaths.size(); ++i) {
467 srcPaths[i] = string_t(srcBasenames[i]).append(".").append(srcSuffix);
468 }
469 }
470 res = create(gl, type, count, srcPaths);
471 if(res && res->isValid()) {
472 return res;
473 }
474 for(const string_t& s : srcPaths) {
475 if( !srcPathsString.empty() ) {
476 srcPathsString.append(";");
477 }
478 srcPathsString.append(s);
479 }
480 }
481 if( !binBasename.empty() ) {
483 stringview_t binSuffix = !binSuffixOpt.empty() ? binSuffixOpt : getFileSuffix(true, type);
484 for(GLenum bFmt : binFmts) {
485 string_t bFmtPath = string_t(getBinarySubPath(bFmt));
486 if(bFmtPath.empty()) continue;
487 binFileName = string_t(binRoot).append("/").append(bFmtPath).append("/").append(binBasename).append(".").append(binSuffix);
488 // res = create(type, count, bFmt, binFileName);
489 if(res && res->isValid()) {
490 return res;
491 }
492 }
493 }
494 return nullptr;
495 }
496
497 /**
498 * Simplified variation of {@link #create(GL2ES2, int, int, Class, String, String[], String, String, String, String, boolean)}.
499 * <p>
500 * Convenient creation method for instantiating a complete {@link ShaderCode} object
501 * either from source code using {@link #create(GL2ES2, int, int, Class, String[])},
502 * or from a binary code using {@link #create(int, int, Class, int, String)},
503 * whatever is available first.
504 * </p>
505 * <p>
506 * The source and binary location names are expected w/o suffixes which are
507 * resolved and appended using {@link #getFileSuffix(boolean, int)}.
508 * </p>
509 * <p>
510 * Additionally, the binary resource is expected within a subfolder of <code>binRoot</code>
511 * which reflects the vendor specific binary format, see {@link #getBinarySubPath(int)}.
512 * All {@link ShaderUtil#getShaderBinaryFormats(GL)} are being iterated
513 * using the binary subfolder, the first existing resource is being used.
514 * </p>
515 *
516 * Example:
517 * <pre>
518 * Your std JVM layout (plain or within a JAR):
519 *
520 * org/test/glsl/MyShaderTest.class
521 * org/test/glsl/shader/vertex.vp
522 * org/test/glsl/shader/fragment.fp
523 * org/test/glsl/shader/bin/nvidia/vertex.bvp
524 * org/test/glsl/shader/bin/nvidia/fragment.bfp
525 *
526 * Your Android APK layout:
527 *
528 * classes.dex
529 * assets/org/test/glsl/shader/vertex.vp
530 * assets/org/test/glsl/shader/fragment.fp
531 * assets/org/test/glsl/shader/bin/nvidia/vertex.bvp
532 * assets/org/test/glsl/shader/bin/nvidia/fragment.bfp
533 * ...
534 *
535 * Your invocation in org/test/glsl/MyShaderTest.java:
536 *
537 * ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, this.getClass(),
538 * "shader", new String[] { "vertex" }, "shader/bin", "vertex", true);
539 * ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, this.getClass(),
540 * "shader", new String[] { "vertex" }, "shader/bin", "fragment", true);
541 * ShaderProgram sp0 = new ShaderProgram();
542 * sp0.add(gl, vp0, System.err);
543 * sp0.add(gl, fp0, System.err);
544 * st.attachShaderProgram(gl, sp0, true);
545 * </pre>
546 * A simplified entry point is {@link #create(GL2ES2, int, Class, String, String, String, boolean)}.
547 *
548 * <p>
549 * The location is finally being resolved using the <code>context</code> class, see {@link #readShaderBinary(Class, String)}.
550 * </p>
551 *
552 * @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used),
553 * or to determine the shader binary format (if <code>binary</code> is used).
554 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
555 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
556 * @param count number of shaders
557 * @param context class used to help resolving the source and binary location
558 * @param srcRoot relative <i>root</i> path for <code>srcBasenames</code> optional
559 * @param srcBasenames basenames w/o path or suffix relative to <code>srcRoot</code> for the shader's source code
560 * @param binRoot relative <i>root</i> path for <code>binBasenames</code>
561 * @param binBasename basename w/o path or suffix relative to <code>binRoot</code> for the shader's binary code
562 * @return successfully created valid ShaderCodeRef or nullptr on failure
563 *
564 * @see #create(GL2ES2, int, int, Class, String, String[], String, String, String, String, boolean)
565 * @see #readShaderSource(Class, String)
566 * @see #getFileSuffix(boolean, int)
567 * @see ShaderUtil#getShaderBinaryFormats(GL)
568 * @see #getBinarySubPath(int)
569 */
570 static ShaderCodeRef create(GL& gl, GLenum type, size_t count,
571 stringview_t srcRoot, const string_list_t& srcBasenames,
572 stringview_t binRoot, stringview_t binBasename) noexcept {
573 return create(gl, type, count, srcRoot, srcBasenames, "", binRoot, binBasename, "");
574 }
575
576 /**
577 * Simplified variation of {@link #create(GL2ES2, int, int, Class, String, String[], String, String, String, String, boolean)}.
578 * <p>
579 * Example:
580 * <pre>
581 * Your std JVM layout (plain or within a JAR):
582 *
583 * org/test/glsl/MyShaderTest.class
584 * org/test/glsl/shader/vertex.vp
585 * org/test/glsl/shader/fragment.fp
586 * org/test/glsl/shader/bin/nvidia/vertex.bvp
587 * org/test/glsl/shader/bin/nvidia/fragment.bfp
588 *
589 * Your Android APK layout:
590 *
591 * classes.dex
592 * assets/org/test/glsl/shader/vertex.vp
593 * assets/org/test/glsl/shader/fragment.fp
594 * assets/org/test/glsl/shader/bin/nvidia/vertex.bvp
595 * assets/org/test/glsl/shader/bin/nvidia/fragment.bfp
596 * ...
597 *
598 * Your invocation in org/test/glsl/MyShaderTest.java:
599 *
600 * ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass(),
601 * "shader", "shader/bin", "vertex", null, null, true);
602 * ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass(),
603 * "shader", "shader/bin", "fragment", null, null, true);
604 * ShaderProgram sp0 = new ShaderProgram();
605 * sp0.add(gl, vp0, System.err);
606 * sp0.add(gl, fp0, System.err);
607 * st.attachShaderProgram(gl, sp0, true);
608 * </pre>
609 * </p>
610 *
611 * @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used),
612 * or to determine the shader binary format (if <code>binary</code> is used).
613 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
614 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
615 * @param context class used to help resolving the source and binary location
616 * @param srcRoot relative <i>root</i> path for <code>basename</code> optional
617 * @param binRoot relative <i>root</i> path for <code>basename</code>
618 * @param basename basename w/o path or suffix relative to <code>srcRoot</code> and <code>binRoot</code>
619 * for the shader's source and binary code.
620 * @param srcSuffixOpt optional custom suffix for shader's source file,
621 * if {@code null} {@link #getFileSuffix(boolean, int)} is being used.
622 * @param binSuffixOpt optional custom suffix for shader's binary file,
623 * if {@code null} {@link #getFileSuffix(boolean, int)} is being used.
624 * @return successfully created valid ShaderCodeRef or nullptr on failure
625 *
626 * @see #create(GL2ES2, int, int, Class, String, String[], String, String, String, String, boolean)
627 * @since 2.3.2
628 */
629 static ShaderCodeRef create(GL& gl, GLenum type, stringview_t srcRoot, stringview_t binRoot,
630 stringview_t basename, stringview_t srcSuffixOpt, stringview_t binSuffixOpt) noexcept {
631 string_list_t srcBasenames = { string_t(basename) };
632 return create(gl, type, 1, srcRoot, srcBasenames, srcSuffixOpt, binRoot, basename, binSuffixOpt);
633 }
634
635 /**
636 * Simplified variation of {@link #create(GL2ES2, int, Class, String, String, String, String, String, boolean)}.
637 * <p>
638 * Example:
639 * <pre>
640 * Your std JVM layout (plain or within a JAR):
641 *
642 * org/test/glsl/MyShaderTest.class
643 * org/test/glsl/shader/vertex.vp
644 * org/test/glsl/shader/fragment.fp
645 * org/test/glsl/shader/bin/nvidia/vertex.bvp
646 * org/test/glsl/shader/bin/nvidia/fragment.bfp
647 *
648 * Your Android APK layout:
649 *
650 * classes.dex
651 * assets/org/test/glsl/shader/vertex.vp
652 * assets/org/test/glsl/shader/fragment.fp
653 * assets/org/test/glsl/shader/bin/nvidia/vertex.bvp
654 * assets/org/test/glsl/shader/bin/nvidia/fragment.bfp
655 * ...
656 *
657 * Your invocation in org/test/glsl/MyShaderTest.java:
658 *
659 * ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass(),
660 * "shader", "shader/bin", "vertex", true);
661 * ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass(),
662 * "shader", "shader/bin", "fragment", true);
663 * ShaderProgram sp0 = new ShaderProgram();
664 * sp0.add(gl, vp0, System.err);
665 * sp0.add(gl, fp0, System.err);
666 * st.attachShaderProgram(gl, sp0, true);
667 * </pre>
668 * </p>
669 *
670 * @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used),
671 * or to determine the shader binary format (if <code>binary</code> is used).
672 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
673 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
674 * @param context class used to help resolving the source and binary location
675 * @param srcRoot relative <i>root</i> path for <code>basename</code> optional
676 * @param binRoot relative <i>root</i> path for <code>basename</code>
677 * @param basenames basename w/o path or suffix relative to <code>srcRoot</code> and <code>binRoot</code>
678 * for the shader's source and binary code.
679 * @return successfully created valid ShaderCodeRef or nullptr on failure
680 */
681 static ShaderCodeRef create(GL& gl, GLenum type,
682 stringview_t srcRoot, stringview_t binRoot, stringview_t basename) noexcept {
683 return create(gl, type, srcRoot, binRoot, basename, "", "");
684 }
685
686 /** Returns the unique shader id for successfully created instances, zero if instance creation failed. */
687 constexpr size_t id() const noexcept { return m_id; }
688
689 /** Returns true if this instance is valid, i.e. 0 != id() */
690 constexpr bool isValid() const noexcept { return 0 != m_id; }
691
692 /** Returns true if this instance is valid and compiled. */
693 constexpr bool isCompiled() const noexcept { return m_compiled; }
694
695 GLenum shaderType() const noexcept { return m_shaderType; }
696 string_t shaderTypeStr() const noexcept { return string_t(shaderTypeString(m_shaderType)); }
697
698 GLenum shaderBinaryFormat() const noexcept { return m_shaderBinaryFormat; }
699 const bytes_t& shaderBinary() const noexcept { return m_shaderBinary; }
700 const source_list_t& shaderSource() const noexcept { return m_shaderSource; }
701
702 const shader_list_t& shader() const noexcept { return m_shader; }
703
704 bool compile(GL& gl, bool verbose=false) {
705 if(!isValid()) return false;
706 if(isCompiled()) return true;
707
708 // Create & Compile the vertex/fragment shader objects
709 if(!m_shaderSource.empty()) {
710 if(DEBUG_CODE) {
711 jau::PLAIN_PRINT(true, "ShaderCode.compile");
712 dumpSource(); // NOLINT(bugprone-exception-escape)
713 }
714 m_compiled=ShaderUtil::createAndCompileShader(gl, m_shader, m_shaderType,
715 m_shaderSource, verbose);
716 } else if(!m_shaderBinary.empty()) {
717 m_compiled=ShaderUtil::createAndLoadShader(gl, m_shader, m_shaderType,
718 m_shaderBinaryFormat, m_shaderBinary, verbose);
719 } else if(DEBUG_CODE) {
720 jau::PLAIN_PRINT(true, "ShaderCode.compile: No code");
721 dumpSource(); // NOLINT(bugprone-exception-escape)
722 }
723 return m_compiled;
724 }
725
726 void destroy(GL& gl) noexcept {
727 if(isCompiled()) {
729 m_compiled=false;
730 }
731 if(!m_shaderBinary.empty()) {
732 m_shaderBinary.clear();
733 }
734 m_shaderSource.clear();
735 m_shaderBinaryFormat=0;
736 m_shaderType=0;
737 }
738
739 constexpr bool operator==(const ShaderCode& rhs) const noexcept {
740 if(this==&rhs) { return true; }
741 return m_id == rhs.m_id;
742 }
743 constexpr std::size_t hash_code() const noexcept { return m_id; }
744
746 string_t r("ShaderCode[id=");
747 r.append(std::to_string(m_id)).append(", type=").append(shaderTypeStr())
748 .append(", valid=").append(std::to_string(isValid())).append(", compiled=").append(std::to_string(m_compiled))
749 .append(", ").append(std::to_string(m_shader.size())).append(" shader: ");
750 for(GLuint s : m_shader) {
751 r.append(" ").append(std::to_string(s));
752 }
753 if(!m_shaderSource.empty()) {
754 r.append(", source]");
755 } else if(!m_shaderBinary.empty()) {
756 r.append(", binary]");
757 }
758 return r;
759 }
760
761
762 void dumpSource() {
763 if(m_shaderSource.empty()) {
764 jau::PLAIN_PRINT(true, "<no shader source>");
765 return;
766 }
767 const size_t sourceCount = m_shaderSource.size();
768 const size_t shaderCount = m_shader.size();
769 jau::PLAIN_PRINT(true, "");
770 jau::PLAIN_PRINT(true, "ShaderCode[id=%d, type=%s, valid=%d, compiled=%d, %zu/%zu shader:",
771 m_id, shaderTypeStr().c_str(), isValid(), m_compiled, m_shader.size(), shaderCount);
772 if( 0 == shaderCount ) {
773 jau::PLAIN_PRINT(true, "none]");
774 }
775 for(size_t i=0; i<shaderCount; ++i) {
776 jau::PLAIN_PRINT(true, "");
777 jau::PLAIN_PRINT(true, "Shader #%zu/%zu name %u", i, shaderCount, m_shader[i]);
778 jau::PLAIN_PRINT(true, "--------------------------------------------------------------");
779 if(i>=sourceCount) {
780 jau::PLAIN_PRINT(true, "<no shader source>");
781 } else {
782 const string_list_t& src = m_shaderSource[i];
783 int lineno=0;
784
785 for(size_t j=0; j<src.size(); j++) {
786 jau::PLAIN_PRINT(false, "%4d: // Segment %d/%d:", lineno, j, src.size());
787 std::istringstream reader(src[j]);
788 string_t line;
789 while (std::getline(reader, line)) {
790 ++lineno;
791 jau::PLAIN_PRINT(false, "%4d: %s", lineno, line.c_str());
792 }
793 }
794 }
795 jau::PLAIN_PRINT(true, "--------------------------------------------------------------");
796 }
797 jau::PLAIN_PRINT(true, "]");
798 }
799
800 /**
801 * Adds <code>data</code> after the line containing <code>tag</code>.
802 *
803 * @param shaderIdx the shader index to be used.
804 * @param tag search string
805 * @param fromIndex start search <code>tag</code> begininig with this index
806 * @param data the text to be inserted. Shall end with an EOL '\n' character.
807 * @return index after the inserted <code>data</code> or std::string::npos if tag wasn't found or on error
808 */
809 size_t insertShaderSource(size_t shaderIdx, stringview_t tag, size_t fromIndex, stringview_t data) noexcept {
810 if(m_shaderSource.empty()) {
811 ERR_PRINT("no shader source");
812 return string_t::npos;
813 }
814 const size_t shaderCount = m_shader.size();
815 if(shaderIdx>=shaderCount) {
816 ERR_PRINT("shaderIdx %zu not within shader bounds %zu", shaderIdx, shaderCount);
817 return string_t::npos;
818 }
819 const size_t sourceCount = m_shaderSource.size();
820 if(shaderIdx>=sourceCount) {
821 ERR_PRINT("shaderIdx %zu not within source bounds %zu", shaderIdx, shaderCount);
822 return string_t::npos;
823 }
824 string_list_t& src = m_shaderSource[shaderIdx];
825 if(src.empty()) {
826 ERR_PRINT("no shader source at for shader index %zu", shaderIdx);
827 return string_t::npos;
828 }
829 size_t curEndIndex = 0;
830 for(auto & sb : src) {
831 curEndIndex += sb.length();
832 if(fromIndex < curEndIndex) {
833 size_t insertIdx = sb.find(tag, fromIndex);
834 if(string_t::npos != insertIdx) {
835 insertIdx += tag.length();
836 size_t eol = sb.find('\n', insertIdx); // eol: covers \n and \r\n
837 if(string_t::npos == eol) {
838 eol = sb.find('\r', insertIdx); // eol: covers \r 'only'
839 }
840 if(string_t::npos != eol) {
841 insertIdx = eol+1; // eol found
842 } else {
843 sb.insert(insertIdx, "\n"); // add eol
844 ++insertIdx;
845 }
846 sb.insert(insertIdx, data);
847 return insertIdx+data.length();
848 }
849 }
850 }
851 return string_t::npos;
852 }
853
854 /**
855 * Adds <code>data</code> at <code>position</code> in shader source for shader <code>shaderIdx</code>.
856 *
857 * @param shaderIdx the shader index to be used.
858 * @param position in shader source segments of shader <code>shaderIdx</code>, if exceeding source length (like std::string::npos or) data will be appended
859 * @param data the text to be inserted. Shall end with an EOL '\n' character
860 * @return index after the inserted `data` or std::string::npos on error
861 */
862 size_t insertShaderSource(size_t shaderIdx, size_t position, stringview_t data) noexcept {
863 if(m_shaderSource.empty()) {
864 ERR_PRINT("no shader source");
865 return string_t::npos;
866 }
867 const size_t shaderCount = m_shader.size();
868 if(shaderIdx>=shaderCount) {
869 ERR_PRINT("shaderIdx %zu not within shader bounds %zu", shaderIdx, shaderCount);
870 return string_t::npos;
871 }
872 const size_t sourceCount = m_shaderSource.size();
873 if(shaderIdx>=sourceCount) {
874 ERR_PRINT("shaderIdx %zu not within source bounds %zu", shaderIdx, shaderCount);
875 return string_t::npos;
876 }
877 string_list_t& src = m_shaderSource[shaderIdx];
878 if(src.empty()) {
879 ERR_PRINT("no shader source at for shader index %zu", shaderIdx);
880 return string_t::npos;
881 }
882 size_t curEndIndex = 0;
883 size_t j=0;
884 for(; j<src.size()-1 && position > curEndIndex; ++j) {
885 curEndIndex += src[j].length();
886 }
887 string_t& sb = src[j];
888 const size_t lastEndIndex = curEndIndex;
889 curEndIndex += src[j].length();
890 if( position > curEndIndex ) {
891 position = curEndIndex;
892 }
893 sb.insert(position - lastEndIndex, data);
894 return position+data.length();
895 }
896
897 /**
898 * Adds shader source located in <code>path</code>,
899 * either relative to the <code>location</code> or absolute <i>as-is</i>
900 * at <code>position</code> in shader source for shader <code>shaderIdx</code>.
901 *
902 * @param shaderIdx the shader index to be used.
903 * @param position in shader source segments of shader <code>shaderIdx</code>, -1 will append data
904 * @param path location of shader source
905 * @return index after the inserted code or std::string::npos on error
906 */
907 size_t insertShaderSourceFile(size_t shaderIdx, size_t position, const string_t& path) noexcept {
909 if( !readShaderSource(path, data) ) {
910 return string_t::npos;
911 }
912 return insertShaderSource(shaderIdx, position, data);
913 }
914
915 /**
916 * Replaces <code>oldName</code> with <code>newName</code> in all shader sources.
917 * <p>
918 * In case <code>oldName</code> and <code>newName</code> are equal, no action is performed.
919 * </p>
920 *
921 * @param oldName the to be replace string
922 * @param newName the replacement string
923 * @return the number of replacements, zero on error or no replacement
924 */
925 size_t replaceInShaderSource(const string_t& oldName, const string_t& newName) noexcept {
926 if(m_shaderSource.empty() || oldName == newName) {
927 return 0;
928 }
929 const size_t oldNameLen = oldName.length();
930 const size_t newNameLen = newName.length();
931 size_t num = 0;
932 const size_t sourceCount = m_shaderSource.size();
933 for(size_t shaderIdx = 0; shaderIdx<sourceCount; ++shaderIdx) {
934 string_list_t& src = m_shaderSource[shaderIdx];
935 for(auto & sb : src) {
936 size_t curPos = 0;
937 while(curPos<sb.length()-oldNameLen+1) {
938 const size_t startIdx = sb.find(oldName, curPos);
939 if(string_t::npos != startIdx) {
940 sb.replace(startIdx, oldNameLen, newName);
941 curPos = startIdx + newNameLen;
942 ++num;
943 } else {
944 curPos = sb.length();
945 }
946 }
947 }
948 }
949 return num;
950 }
951
952 private:
953 /** Returns true if successful, otherwise false. */
954 static bool readShaderSource(const string_t& conn, string_t& result, int& lineno) noexcept {
955 if(DEBUG_CODE) {
956 if(0 == lineno) {
957 result.append("// '"+conn+"'\n"); // conn.getURL().toExternalForm()
958 } else {
959 result.append("// included @ line "+std::to_string(lineno)+": '"+conn+"'\n"); // conn.getURL().toExternalForm()
960 }
961 }
962 std::ifstream reader(conn);
963 string_t line;
964 while ( std::getline(reader, line) ) {
965 ++lineno;
966 if (line.starts_with("#include ")) {
967 string_t includeFile;
968 {
969 string_t s = line.substr(9);
970 jau::trimInPlace( s );
971 // Bug 1283: Remove shader include filename quotes if exists at start and end only
972 if( s.starts_with("\"") && s.ends_with("\"")) {
973 s = s.substr(1, s.length()-2);
974 }
975 includeFile = s;
976 }
977 string_t nextConn = gamp::resolve_asset(includeFile);
978
979 if( nextConn.empty() && !jau::io::fs::isAbsolute(includeFile) ) {
980 // Try relative of current shader location
981 includeFile = jau::io::fs::dirname(conn).append("/").append(includeFile);
982 if( jau::io::fs::exists(includeFile) ) {
983 nextConn = includeFile;
984 }
985 }
986 if( nextConn.empty() ) {
987 return false;
988 }
989 if( DEBUG_CODE ) {
990 jau::PLAIN_PRINT(true, "readShaderSource: including '%s' -> '%s'", includeFile.c_str(), nextConn.c_str());
991 }
992 lineno = readShaderSource(nextConn, result, lineno);
993 } else {
994 result.append(line + "\n");
995 }
996 }
997 return true;
998 }
999
1000 public:
1001 /**
1002 * Reads shader source from file located in `path` and appends it to result.
1003 *
1004 * @param path location of shader source
1005 * @param result storage to appends the source code
1006 * @return true if successful, otherwise false
1007 */
1008 static bool readShaderSource(stringview_t path0, string_t& result) noexcept {
1009 const string_t path(path0);
1010 const string_t conn = gamp::resolve_asset(path);
1011 if( DEBUG_CODE ) {
1012 jau::PLAIN_PRINT(true, "readShaderSource: %s -> %s", path.c_str(), conn.c_str());
1013 }
1014 if (!conn.empty()) {
1015 int lineno=0;
1016 return readShaderSource(conn, result, lineno);
1017 }
1018 return false;
1019 }
1020
1021 /**
1022 * Reads shader source from file located in `path`, returning the string.
1023 *
1024 * Final location lookup is performed via `gamp::resolve_asset(path)`.
1025 *
1026 * @param path location of shader source
1027 * @return a non empty string containing the source code if successful, otherwise an empty string
1028 * @see gamp::resolve_asset
1029 */
1031 string_t result;
1032 if( !readShaderSource(path, result) ) {
1033 result.clear();
1034 }
1035 return result;
1036 }
1037
1038#if 0
1039// FIXME JAU COMPLETE
1040
1041 /**
1042 * Reads shader binary located in <code>path</code>,
1043 * either relative to the <code>context</code> class or absolute <i>as-is</i>.
1044 * <p>
1045 * Final location lookup is perfomed via {@link ClassLoader#getResource(String)} and {@link ClassLoader#getSystemResource(String)},
1046 * see {@link IOUtil#getResource(Class, String)}.
1047 * </p>
1048 *
1049 * @param context class used to help resolve the source location
1050 * @param path location of shader binary
1051 *
1052 * @see IOUtil#getResource(Class, String)
1053 */
1054 public static ByteBuffer readShaderBinary(final Class<?> context, final String path) noexcept {
1055 final URLConnection conn = IOUtil.getResource(path, context.getClassLoader(), context);
1056 if (conn == null) {
1057 return null;
1058 }
1059 final BufferedInputStream bis = new BufferedInputStream( conn.getInputStream() );
1060 try {
1061 return IOUtil.copyStream2ByteBuffer( bis );
1062 } finally {
1063 IOUtil.close(bis, false);
1064 }
1065 }
1066
1067 /**
1068 * Reads shader binary located from {@link Uri#absolute} {@link Uri} <code>binLocation</code>.
1069 * @param binLocation {@link Uri} location of shader binary
1070 * @since 2.3.2
1071 */
1072 public static ByteBuffer readShaderBinary(final Uri binLocation) noexcept {
1073 final URLConnection conn = IOUtil.openURL(binLocation.toURL(), "ShaderCode ");
1074 if (conn == null) {
1075 return null;
1076 }
1077 final BufferedInputStream bis = new BufferedInputStream( conn.getInputStream() );
1078 try {
1079 return IOUtil.copyStream2ByteBuffer( bis );
1080 } finally {
1081 IOUtil.close(bis, false);
1082 }
1083 }
1084#endif
1085
1086 // Shall we use: #ifdef GL_FRAGMENT_PRECISION_HIGH .. #endif for using highp in fragment shader if avail ?
1087 /** Default precision of {@link GL#isGLES2() ES2} for {@link GL2ES2#GL_VERTEX_SHADER vertex-shader}: {@value #es2_default_precision_vp} */
1088 constexpr static std::string_view es2_default_precision_vp = "\nprecision highp float;\nprecision highp int;\n/*precision lowp sampler2D;*/\n/*precision lowp samplerCube;*/\n";
1089 /** Default precision of {@link GL#isGLES2() ES2} for {@link GL2ES2#GL_FRAGMENT_SHADER fragment-shader}: {@value #es2_default_precision_fp} */
1090 constexpr static std::string_view es2_default_precision_fp = "\nprecision mediump float;\nprecision mediump int;\n/*precision lowp sampler2D;*/\n/*precision lowp samplerCube;*/\n";
1091
1092 /** Default precision of {@link GL#isGLES3() ES3} for {@link GL2ES2#GL_VERTEX_SHADER vertex-shader}: {@value #es3_default_precision_vp} */
1093 constexpr static std::string_view es3_default_precision_vp = es2_default_precision_vp;
1094 /**
1095 * Default precision of {@link GL#isGLES3() ES3} for {@link GL2ES2#GL_FRAGMENT_SHADER fragment-shader}: {@value #es3_default_precision_fp},
1096 * same as for {@link GL2ES2#GL_VERTEX_SHADER vertex-shader}, i.e {@link #es3_default_precision_vp},
1097 * due to ES 3.x requirements of using same precision for uniforms!
1098 */
1099 constexpr static std::string_view es3_default_precision_fp = es3_default_precision_vp;
1100
1101 /** Default precision of GLSL &ge; 1.30 as required until &lt; 1.50 for {@link GL2ES2#GL_VERTEX_SHADER vertex-shader} or {@link GL3#GL_GEOMETRY_SHADER geometry-shader}: {@value #gl3_default_precision_vp_gp}. See GLSL Spec 1.30-1.50 Section 4.5.3. */
1102 constexpr static std::string_view gl3_default_precision_vp_gp = "\nprecision highp float;\nprecision highp int;\n";
1103 /** Default precision of GLSL &ge; 1.30 as required until &lt; 1.50 for {@link GL2ES2#GL_FRAGMENT_SHADER fragment-shader}: {@value #gl3_default_precision_fp}. See GLSL Spec 1.30-1.50 Section 4.5.3. */
1104 constexpr static std::string_view gl3_default_precision_fp = "\nprecision highp float;\nprecision mediump int;\n/*precision mediump sampler2D;*/\n";
1105
1106 /** <i>Behavior</i> for GLSL extension directive, see {@link #createExtensionDirective(String, String)}, value {@value}. */
1107 constexpr static std::string_view REQUIRE = "require";
1108 /** <i>Behavior</i> for GLSL extension directive, see {@link #createExtensionDirective(String, String)}, value {@value}. */
1109 constexpr static std::string_view ENABLE = "enable";
1110 /** <i>Behavior</i> for GLSL extension directive, see {@link #createExtensionDirective(String, String)}, value {@value}. */
1111 constexpr static std::string_view DISABLE = "disable";
1112 /** <i>Behavior</i> for GLSL extension directive, see {@link #createExtensionDirective(String, String)}, value {@value}. */
1113 constexpr static std::string_view WARN = "warn";
1114
1115 private:
1116 constexpr static std::string_view vp_130_defines =
1117 "#define attribute in\n"
1118 "#define varying out\n"
1119 "#define IN in\n";
1120 constexpr static std::string_view vp_100_defines =
1121 "#define IN\n";
1122 constexpr static std::string_view fp_130_defines =
1123 "#define varying in\n"
1124 "#define IN in\n"
1125 "out vec4 mgl_FragColor;\n"
1126 "#define texture2D texture\n";
1127
1128 constexpr static std::string_view fp_100_defines =
1129 "#define IN\n"
1130 "#define mgl_FragColor gl_FragColor\n";
1131 public:
1132 /**
1133 * Creates a GLSL extension directive.
1134 * <p>
1135 * Prefer {@link #ENABLE} over {@link #REQUIRE}, since the latter will force a failure if not supported.
1136 * </p>
1137 *
1138 * @param extensionName
1139 * @param behavior shall be either {@link #REQUIRE}, {@link #ENABLE}, {@link #DISABLE} or {@link #WARN}
1140 * @return the complete extension directive
1141 */
1142 static string_t createExtensionDirective(const string_t& extensionName, const string_t& behavior) {
1143 return "#extension " + extensionName + " : " + behavior + "\n";
1144 }
1145
1146 /**
1147 * Add GLSL version at the head of this shader source code.
1148 * @param gl a GL context, which must have been made current once
1149 * @return the index after the inserted data, maybe 0 if nothing has be inserted.
1150 */
1151 size_t addGLSLVersion(const GL& gl) noexcept {
1152 return insertShaderSource(0, 0, gl.glProfile().getGLSLVersionString());
1153 }
1154
1155 /**
1156 * Adds default precision to source code at given position if required, i.e.
1157 * {@link #es2_default_precision_vp}, {@link #es2_default_precision_fp},
1158 * {@link #gl3_default_precision_vp_gp}, {@link #gl3_default_precision_fp} or none,
1159 * depending on the {@link GLContext#getGLSLVersionNumber() GLSL version} being used.
1160 * @param gl a GL context, which must have been made current once
1161 * @param pos position within this mutable shader source.
1162 * @return the index after the inserted data, maybe unchanged pos if nothing has be inserted.
1163 */
1164 size_t addDefaultShaderPrecision(const GL& gl, size_t pos) {
1165 std::string_view defaultPrecision;
1166 if( gl.glProfile().nativeGLES3() ) {
1167 switch ( m_shaderType ) {
1168 case GL_VERTEX_SHADER:
1169 defaultPrecision = es3_default_precision_vp; break;
1170 case GL_FRAGMENT_SHADER:
1171 defaultPrecision = es3_default_precision_fp; break;
1172 case GL_COMPUTE_SHADER:
1173 defaultPrecision = es3_default_precision_fp; break;
1174 default:
1175 defaultPrecision = "";
1176 break;
1177 }
1178 } else if( gl.glProfile().nativeGLES2() ) {
1179 switch ( m_shaderType ) {
1180 case GL_VERTEX_SHADER:
1181 defaultPrecision = es2_default_precision_vp; break;
1182 case GL_FRAGMENT_SHADER:
1183 defaultPrecision = es2_default_precision_fp; break;
1184 default:
1185 defaultPrecision = "";
1186 break;
1187 }
1188 } else if( requiresGL3DefaultPrecision(gl) ) {
1189 // GLSL [ 1.30 .. 1.50 [ needs at least fragement float default precision!
1190 switch ( m_shaderType ) {
1191 case GL_VERTEX_SHADER:
1192 case GL_GEOMETRY_SHADER:
1193 case GL_TESS_CONTROL_SHADER:
1194 case GL_TESS_EVALUATION_SHADER:
1195 defaultPrecision = gl3_default_precision_vp_gp; break;
1196 case GL_FRAGMENT_SHADER:
1197 defaultPrecision = gl3_default_precision_fp; break;
1198 case GL_COMPUTE_SHADER:
1199 defaultPrecision = gl3_default_precision_fp; break;
1200 default:
1201 defaultPrecision = "";
1202 break;
1203 }
1204 } else {
1205 defaultPrecision = "";
1206 }
1207 if( defaultPrecision.length() > 0 ) {
1208 pos = insertShaderSource(0, pos, string_t(defaultPrecision));
1209 }
1210 return pos;
1211 }
1212
1213 /** Returns true, if GLSL version requires default precision, i.e. ES2 or GLSL [1.30 .. 1.50[. */
1214 constexpr static bool requiresDefaultPrecision(const GL& gl) noexcept {
1215 if( gl.glProfile().nativeGLES() ) {
1216 return true;
1217 }
1219 }
1220
1221 /** Returns true, if GL3 GLSL version requires default precision, i.e. GLSL [1.30 .. 1.50[. */
1222 constexpr static bool requiresGL3DefaultPrecision(const GL& gl) noexcept {
1223 if( !gl.glProfile().nativeGLES() ) {
1224 const jau::util::VersionNumber& glslVersion = gl.glProfile().glslVersion();
1225 return glslVersion >= Version1_30 && glslVersion < Version1_50;
1226 } else {
1227 return false;
1228 }
1229 }
1230
1231 /**
1232 * Add GLSL version and shader-type dependent defines of this shader source code.
1233 * @param gl a GL context, which must have been made current once
1234 * @param pos position within this mutable shader source.
1235 * @return the index after the inserted data, maybe unchanged pos if nothing has be inserted.
1236 */
1237 size_t addGLSLDefines(const GL& gl, size_t pos) noexcept {
1238 const jau::util::VersionNumber& glslVersion = gl.glProfile().glslVersion();
1239 if ( GL_VERTEX_SHADER == m_shaderType ) {
1240 pos = insertShaderSource(0, pos, "\n");
1241 if( glslVersion >= Version1_30 ) {
1242 pos = insertShaderSource(0, pos, vp_130_defines);
1243 } else {
1244 pos = insertShaderSource(0, pos, vp_100_defines);
1245 }
1246 pos = insertShaderSource(0, pos, "\n");
1247 } else if ( GL_FRAGMENT_SHADER == m_shaderType ) {
1248 pos = insertShaderSource(0, pos, "\n");
1249 if( glslVersion >= Version1_30 ) {
1250 pos = insertShaderSource(0, pos, fp_130_defines);
1251 } else {
1252 pos = insertShaderSource(0, pos, fp_100_defines);
1253 }
1254 pos = insertShaderSource(0, pos, "\n");
1255 }
1256 return pos;
1257 }
1258
1259 /**
1260 * Default customization of this shader source code.
1261 * @param gl a GL context, which must have been made current once
1262 * @param preludeVersion if true {@link GLContext#getGLSLVersionString()} is preluded, otherwise not. Defaults to true.
1263 * @param addDefaultPrecision if <code>true</code> default precision source code line(s) are added, i.e.
1264 * {@link #es2_default_precision_vp}, {@link #es2_default_precision_fp},
1265 * {@link #gl3_default_precision_vp_gp}, {@link #gl3_default_precision_fp} or none,
1266 * depending on the {@link GLContext#getGLSLVersionNumber() GLSL version} being used.
1267 * Defaults to true.
1268 * @param addDefaultDefines if true addGLSLDefines() is used to prelude common defines, defaults to true
1269 * @return the index after the inserted data, maybe 0 if nothing has be inserted.
1270 * @see #addGLSLVersion(GL2ES2)
1271 * @see #addDefaultShaderPrecision(GL2ES2, i, size_tnt)
1272 * @see #addGLSLDefines(GL2ES2, size_t)
1273 */
1274 size_t defaultShaderCustomization(const GL& gl, bool preludeVersion=true, bool addDefaultPrecision=true, bool addDefaultDefines=true) {
1275 size_t pos;
1276 if( preludeVersion ) {
1277 pos = addGLSLVersion(gl);
1278 } else {
1279 pos = 0;
1280 }
1281 if( addDefaultPrecision ) {
1282 pos = addDefaultShaderPrecision(gl, pos);
1283 }
1284 if( addDefaultDefines ) {
1285 pos = addGLSLDefines(gl, pos);
1286 }
1287 return pos;
1288 }
1289
1290 /**
1291 * Default customization of this shader source code.
1292 * @param gl a GL context, which must have been made current once
1293 * @param preludeVersion if true {@link GLContext#getGLSLVersionString()} is preluded, otherwise not.
1294 * @param esDefaultPrecision optional default precision source code line(s) preluded if not null and if {@link GL#isGLES()}.
1295 * You may use {@link #es2_default_precision_fp} for fragment shader and {@link #es2_default_precision_vp} for vertex shader.
1296 * @param addDefaultDefines if true addGLSLDefines() is used to prelude common defines, defaults to true
1297 * @return the index after the inserted data, maybe 0 if nothing has be inserted.
1298 * @see #addGLSLVersion(GL2ES2)
1299 * @see #addDefaultShaderPrecision(GL2ES2, size_t)
1300 * @see #addGLSLDefines(GL2ES2, size_t)
1301 */
1302 size_t defaultShaderCustomization(const GL& gl, bool preludeVersion, const string_t& esDefaultPrecision, bool addDefaultDefines=true) {
1303 size_t pos;
1304 if( preludeVersion ) {
1305 pos = addGLSLVersion(gl);
1306 } else {
1307 pos = 0;
1308 }
1309 if( gl.glProfile().nativeGLES() && esDefaultPrecision.length()>0 ) {
1310 pos = insertShaderSource(0, pos, esDefaultPrecision);
1311 } else {
1312 pos = addDefaultShaderPrecision(gl, pos);
1313 }
1314 if( addDefaultDefines ) {
1315 pos = addGLSLDefines(gl, pos);
1316 }
1317 return pos;
1318 }
1319
1320 //----------------------------------------------------------------------
1321 // Internals only below this point
1322 //
1323
1324 private:
1325 source_list_t m_shaderSource;
1326 bytes_t m_shaderBinary;
1327 GLenum m_shaderBinaryFormat;
1328 shader_list_t m_shader;
1329 GLenum m_shaderType;
1330 size_t m_id;
1331 bool m_compiled;
1332
1333 static size_t nextID() { return m_nextID++; }
1334 static std::atomic<size_t> m_nextID;
1335 };
1336
1337 inline std::ostream& operator<<(std::ostream& out, const ShaderCode& v) {
1338 return out << v.toString();
1339 }
1340
1341 /**@}*/
1342}
1343
1344// injecting specialization of std::hash to namespace std of our types above
1345namespace std
1346{
1347 /** \addtogroup Gamp_GLSL
1348 *
1349 */
1350
1351 template<> struct hash<gamp::render::gl::glsl::ShaderCode> {
1352 std::size_t operator()(gamp::render::gl::glsl::ShaderCode const& a) const noexcept {
1353 return a.hash_code();
1354 }
1355 };
1356 template<> struct hash<gamp::render::gl::glsl::ShaderCodeRef> {
1357 std::size_t operator()(gamp::render::gl::glsl::ShaderCodeRef const& a) const noexcept {
1358 return a->hash_code();
1359 }
1360 };
1361
1362 /**@}*/
1363}
1364
1365#endif // GAMP_GLSLSHADERCODE_HPP_
Convenient shader code class to use and instantiate vertex or fragment programs.
size_t insertShaderSource(size_t shaderIdx, size_t position, stringview_t data) noexcept
Adds data at position in shader source for shader shaderIdx.
ShaderCode(Private, GLenum type, size_t count, const source_list_t &sources) noexcept
Private ctor for `ShaderCodeRef create(...).
static ShaderCodeRef create(GL &gl, GLenum type, size_t count, stringview_t srcRoot, const string_list_t &srcBasenames, stringview_t binRoot, stringview_t binBasename) noexcept
Simplified variation of create(GL2ES2, int, int, Class, String, String[], String, String,...
static constexpr bool requiresGL3DefaultPrecision(const GL &gl) noexcept
Returns true, if GL3 GLSL version requires default precision, i.e.
static constexpr std::string_view gl3_default_precision_fp
Default precision of GLSL ≥ 1.30 as required until < 1.50 for fragment-shader: {@value gl3_default_pr...
static constexpr std::string_view SUFFIX_TESS_CONTROL_BINARY
Unique resource suffix for GL4#GL_TESS_CONTROL_SHADER in binary: {@value}
GLenum shaderType() const noexcept
constexpr bool operator==(const ShaderCode &rhs) const noexcept
constexpr std::size_t hash_code() const noexcept
constexpr size_t id() const noexcept
Returns the unique shader id for successfully created instances, zero if instance creation failed.
static string_t createExtensionDirective(const string_t &extensionName, const string_t &behavior)
Creates a GLSL extension directive.
size_t defaultShaderCustomization(const GL &gl, bool preludeVersion, const string_t &esDefaultPrecision, bool addDefaultDefines=true)
Default customization of this shader source code.
static ShaderCodeRef create(GL &gl, GLenum type, size_t count, const string_list_t &sourceFiles) noexcept
Creates a complete ShaderCode object while reading all shader source of sourceFiles,...
size_t replaceInShaderSource(const string_t &oldName, const string_t &newName) noexcept
Replaces oldName with newName in all shader sources.
static ShaderCodeRef create(GL &gl, GLenum type, size_t count, stringview_t srcRoot, const string_list_t &srcBasenames, stringview_t srcSuffixOpt, stringview_t binRoot, stringview_t binBasename, stringview_t binSuffixOpt) noexcept
Convenient creation method for instantiating a complete ShaderCode object either from source code usi...
static constexpr std::string_view SUFFIX_FRAGMENT_SOURCE
Unique resource suffix for GL2ES2#GL_FRAGMENT_SHADER in source code: {@value}
static constexpr std::string_view WARN
Behavior for GLSL extension directive, see createExtensionDirective(String, String),...
static constexpr std::string_view SUFFIX_COMPUTE_BINARY
Unique resource suffix for GL3ES3#GL_COMPUTE_SHADER in binary: {@value}
static constexpr std::string_view SUFFIX_TESS_EVALUATION_BINARY
Unique resource suffix for GL4#GL_TESS_EVALUATION_SHADER in binary: {@value}
static constexpr std::string_view SUFFIX_TESS_EVALUATION_SOURCE
Unique resource suffix for GL4#GL_TESS_EVALUATION_SHADER in source code: {@value}
static constexpr std::string_view SUFFIX_VERTEX_SOURCE
Unique resource suffix for GL2ES2#GL_VERTEX_SHADER in source code: {@value}
size_t defaultShaderCustomization(const GL &gl, bool preludeVersion=true, bool addDefaultPrecision=true, bool addDefaultDefines=true)
Default customization of this shader source code.
bool compile(GL &gl, bool verbose=false)
GLenum shaderBinaryFormat() const noexcept
static constexpr std::string_view SUFFIX_VERTEX_BINARY
Unique resource suffix for GL2ES2#GL_VERTEX_SHADER in binary: {@value}
static string_t readShaderSource(stringview_t path) noexcept
Reads shader source from file located in path, returning the string.
constexpr bool isCompiled() const noexcept
Returns true if this instance is valid and compiled.
static ShaderCodeRef create(GLenum type, size_t count, GLenum binFormat, const bytes_t &binary) noexcept
const bytes_t & shaderBinary() const noexcept
static constexpr std::string_view SUB_PATH_NVIDIA
Unique relative path for binary shader resources for NVIDIA: {@value}
static constexpr std::string_view REQUIRE
Behavior for GLSL extension directive, see createExtensionDirective(String, String),...
static constexpr std::string_view ENABLE
Behavior for GLSL extension directive, see createExtensionDirective(String, String),...
static constexpr std::string_view gl3_default_precision_vp_gp
Default precision of GLSL ≥ 1.30 as required until < 1.50 for vertex-shader or geometry-shader: {@val...
ShaderCode(Private, GLenum type, size_t count, GLenum binFormat, const bytes_t &binary) noexcept
Private ctor for `ShaderCodeRef create(...).
static ShaderCodeRef create(GLenum type, size_t count, const source_list_t &sources) noexcept
static ShaderCodeRef create(GL &gl, GLenum type, stringview_t srcRoot, stringview_t binRoot, stringview_t basename, stringview_t srcSuffixOpt, stringview_t binSuffixOpt) noexcept
Simplified variation of create(GL2ES2, int, int, Class, String, String[], String, String,...
static constexpr std::string_view SUFFIX_TESS_CONTROL_SOURCE
Unique resource suffix for GL4#GL_TESS_CONTROL_SHADER in source code: {@value}
constexpr bool isValid() const noexcept
Returns true if this instance is valid, i.e.
const shader_list_t & shader() const noexcept
string_t shaderTypeStr() const noexcept
static constexpr std::string_view DISABLE
Behavior for GLSL extension directive, see createExtensionDirective(String, String),...
static std::string_view getFileSuffix(bool binary, GLenum type) noexcept
Returns a unique suffix for shader resources as follows:
static bool readShaderSource(stringview_t path0, string_t &result) noexcept
Reads shader source from file located in path and appends it to result.
static constexpr std::string_view SUFFIX_GEOMETRY_BINARY
Unique resource suffix for GL3#GL_GEOMETRY_SHADER in binary: {@value}
size_t addGLSLDefines(const GL &gl, size_t pos) noexcept
Add GLSL version and shader-type dependent defines of this shader source code.
static constexpr std::string_view es3_default_precision_fp
Default precision of ES3 for fragment-shader: {@value es3_default_precision_fp}, same as for vertex-s...
static constexpr std::string_view es2_default_precision_vp
Default precision of ES2 for vertex-shader: {@value es2_default_precision_vp}.
const source_list_t & shaderSource() const noexcept
static constexpr std::string_view SUFFIX_FRAGMENT_BINARY
Unique resource suffix for GL2ES2#GL_FRAGMENT_SHADER in binary: {@value}
size_t addGLSLVersion(const GL &gl) noexcept
Add GLSL version at the head of this shader source code.
size_t insertShaderSourceFile(size_t shaderIdx, size_t position, const string_t &path) noexcept
Adds shader source located in path, either relative to the location or absolute as-is at position in ...
size_t insertShaderSource(size_t shaderIdx, stringview_t tag, size_t fromIndex, stringview_t data) noexcept
Adds data after the line containing tag.
static constexpr std::string_view SUFFIX_COMPUTE_SOURCE
Unique resource suffix for GL3ES3#GL_COMPUTE_SHADER in source code: {@value}
static ShaderCodeRef create(GL &gl, GLenum type, stringview_t srcRoot, stringview_t binRoot, stringview_t basename) noexcept
Simplified variation of create(GL2ES2, int, Class, String, String, String, String,...
static constexpr std::string_view es3_default_precision_vp
Default precision of ES3 for vertex-shader: {@value es3_default_precision_vp}.
size_t addDefaultShaderPrecision(const GL &gl, size_t pos)
Adds default precision to source code at given position if required, i.e.
static constexpr std::string_view es2_default_precision_fp
Default precision of ES2 for fragment-shader: {@value es2_default_precision_fp}.
static std::string_view getBinarySubPath(GLenum binFormat) noexcept
Returns a unique relative path for binary shader resources as follows:
static constexpr std::string_view SUFFIX_GEOMETRY_SOURCE
Unique resource suffix for GL3#GL_GEOMETRY_SHADER in source code: {@value}
static constexpr bool requiresDefaultPrecision(const GL &gl) noexcept
Returns true, if GLSL version requires default precision, i.e.
static bool createAndCompileShader(GL &gl, shader_list_t &shader, GLenum shaderType, const source_list_t &sources, bool verbose=false)
Creates shader.size() new shaders, stored in the shader list.
static void deleteShader(GL &, const shader_list_t &shaders) noexcept
static bool createAndLoadShader(GL &gl, shader_list_t &shader, GLenum shaderType, GLenum binFormat, const bytes_t &bin, bool verbose=false)
Creates shader.size() new shaders, stored in the shader list.
static name_list_t getShaderBinaryFormats(GL &gl) noexcept
If supported, queries the natively supported shader binary formats using GL2ES2#GL_NUM_SHADER_BINARY_...
static bool isShaderCompilerAvailable(GL &gl) noexcept
Returns true if a hader compiler is available, otherwise false.
Simple version number class containing a version number either being defined explicit or derived from...
#define ERR_PRINT(...)
Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '.
Definition debug.hpp:122
std::ostream & operator<<(std::ostream &os, const T v)
std::string dirname(const std::string_view &path) noexcept
Return stripped last component from given path separated by /, excluding the trailing separator /.
bool isAbsolute(const std::string_view &path) noexcept
Returns true if first character is / or - in case of Windows - \\.
bool exists(const std::string &path, bool verbose_on_error=false) noexcept
Returns true if path exists and is accessible.
@ null
Denotes a func::null_target_t.
std::vector< uint8_t > bytes_t
std::vector< GLenum > name_list_t
std::string_view stringview_t
std::shared_ptr< ShaderCode > ShaderCodeRef
std::vector< string_t > string_list_t
std::vector< GLuint > shader_list_t
std::vector< string_list_t > source_list_t
static constexpr jau::util::VersionNumber Version1_30
Version 1.30, i.e.
static constexpr GLenum GL_NVIDIA_PLATFORM_BINARY_NV
static constexpr jau::util::VersionNumber Version1_50
Version 1.50, i.e.
constexpr std::string_view shaderTypeString(GLenum type) noexcept
constexpr bool isValidShaderType(GLenum type) noexcept
@ verbose
Verbose operations (debugging).
std::string resolve_asset(const std::string &asset_file, bool lookup_direct=false) noexcept
Definition gamp.cpp:37
void trimInPlace(std::string &s) noexcept
trim in place
Gamp: Graphics, Audio, Multimedia and Processing Framework (Native C++, WebAssembly,...
Definition PTS.hpp:24
void PLAIN_PRINT(const bool printPrefix, const char *format,...) noexcept
Use for unconditional plain messages, prefix '[elapsed_time] ' if printPrefix == true.
Definition debug.cpp:264
STL namespace.
std::size_t operator()(gamp::render::gl::glsl::ShaderCodeRef const &a) const noexcept
std::size_t operator()(gamp::render::gl::glsl::ShaderCode const &a) const noexcept