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