1 /** 2 * Copyright 2010 JogAmp Community. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without modification, are 5 * permitted provided that the following conditions are met: 6 * 7 * 1. Redistributions of source code must retain the above copyright notice, this list of 8 * conditions and the following disclaimer. 9 * 10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 * of conditions and the following disclaimer in the documentation and/or other materials 12 * provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED 15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * 24 * The views and conclusions contained in the software and documentation are those of the 25 * authors and should not be interpreted as representing official policies, either expressed 26 * or implied, of JogAmp Community. 27 */ 28 package com.jogamp.graph.curve.opengl; 29 30 import java.io.IOException; 31 import java.util.Iterator; 32 33 import com.jogamp.opengl.GL; 34 import com.jogamp.opengl.GL2ES2; 35 import com.jogamp.opengl.GLES2; 36 import com.jogamp.opengl.GLException; 37 import com.jogamp.opengl.fixedfunc.GLMatrixFunc; 38 39 import jogamp.graph.curve.opengl.shader.AttributeNames; 40 import jogamp.graph.curve.opengl.shader.UniformNames; 41 42 import com.jogamp.opengl.GLExtensions; 43 import com.jogamp.opengl.util.glsl.ShaderCode; 44 import com.jogamp.opengl.util.glsl.ShaderProgram; 45 import com.jogamp.opengl.util.texture.TextureSequence; 46 import com.jogamp.opengl.util.PMVMatrix; 47 import com.jogamp.common.os.Platform; 48 import com.jogamp.common.util.IntObjectHashMap; 49 import com.jogamp.graph.curve.Region; 50 51 /** 52 * OpenGL {@link Region} renderer 53 * <p> 54 * All OpenGL related operations regarding {@link Region}s 55 * are passed through an instance of this class. 56 * </p> 57 */ 58 public class RegionRenderer { 59 protected static final boolean DEBUG = Region.DEBUG; 60 protected static final boolean DEBUG_INSTANCE = Region.DEBUG_INSTANCE; 61 62 /** 63 * May be passed to 64 * {@link RegionRenderer#create(RenderState, com.jogamp.graph.curve.opengl.RegionRenderer.GLCallback, com.jogamp.graph.curve.opengl.RegionRenderer.GLCallback) RegionRenderer ctor}, 65 * e.g. 66 * <ul> 67 * <li>{@link RegionRenderer#defaultBlendEnable}</li> 68 * <li>{@link RegionRenderer#defaultBlendDisable}</li> 69 * </ul> 70 */ 71 public interface GLCallback { 72 /** 73 * @param gl a current GL object 74 * @param renderer {@link RegionRenderer} calling this method. 75 */ run(GL gl, RegionRenderer renderer)76 void run(GL gl, RegionRenderer renderer); 77 } 78 79 /** 80 * Default {@link GL#GL_BLEND} <i>enable</i> {@link GLCallback}, 81 * turning-off depth writing via {@link GL#glDepthMask(boolean)} if {@link RenderState#BITHINT_GLOBAL_DEPTH_TEST_ENABLED} is set 82 * and turning-on the {@link GL#GL_BLEND} state. 83 * <p> 84 * Implementation also sets {@link RegionRenderer#getRenderState() RenderState}'s {@link RenderState#BITHINT_BLENDING_ENABLED blending bit-hint}, 85 * which will cause {@link GLRegion#draw(GL2ES2, RegionRenderer, int[]) GLRegion's draw-method} 86 * to set the proper {@link GL#glBlendFuncSeparate(int, int, int, int) blend-function} 87 * and the clear-color to <i>transparent-black</i> in case of {@link Region#isTwoPass(int) multipass} FBO rendering. 88 * </p> 89 * @see #create(RenderState, GLCallback, GLCallback) 90 * @see #enable(GL2ES2, boolean) 91 */ 92 public static final GLCallback defaultBlendEnable = new GLCallback() { 93 @Override 94 public void run(final GL gl, final RegionRenderer renderer) { 95 if( renderer.rs.isHintMaskSet(RenderState.BITHINT_GLOBAL_DEPTH_TEST_ENABLED) ) { 96 gl.glDepthMask(false); 97 // gl.glDisable(GL.GL_DEPTH_TEST); 98 // gl.glDepthFunc(GL.GL_ALWAYS); 99 } 100 gl.glEnable(GL.GL_BLEND); 101 gl.glBlendEquation(GL.GL_FUNC_ADD); // default 102 renderer.rs.setHintMask(RenderState.BITHINT_BLENDING_ENABLED); 103 } 104 }; 105 106 /** 107 * Default {@link GL#GL_BLEND} <i>disable</i> {@link GLCallback}, 108 * simply turning-off the {@link GL#GL_BLEND} state 109 * and turning-on depth writing via {@link GL#glDepthMask(boolean)} if {@link RenderState#BITHINT_GLOBAL_DEPTH_TEST_ENABLED} is set. 110 * <p> 111 * Implementation also clears {@link RegionRenderer#getRenderState() RenderState}'s {@link RenderState#BITHINT_BLENDING_ENABLED blending bit-hint}. 112 * </p> 113 * @see #create(RenderState, GLCallback, GLCallback) 114 * @see #enable(GL2ES2, boolean) 115 */ 116 public static final GLCallback defaultBlendDisable = new GLCallback() { 117 @Override 118 public void run(final GL gl, final RegionRenderer renderer) { 119 renderer.rs.clearHintMask(RenderState.BITHINT_BLENDING_ENABLED); 120 gl.glDisable(GL.GL_BLEND); 121 if( renderer.rs.isHintMaskSet(RenderState.BITHINT_GLOBAL_DEPTH_TEST_ENABLED) ) { 122 // gl.glEnable(GL.GL_DEPTH_TEST); 123 // gl.glDepthFunc(GL.GL_LESS); 124 gl.glDepthMask(true); 125 } 126 } 127 }; 128 129 /** 130 * Create a Hardware accelerated Region Renderer. 131 * <p> 132 * The optional {@link GLCallback}s <code>enableCallback</code> and <code>disableCallback</code> 133 * maybe used to issue certain tasks at {@link #enable(GL2ES2, boolean)}.<br/> 134 * For example, instances {@link #defaultBlendEnable} and {@link #defaultBlendDisable} 135 * can be utilized to enable and disable {@link GL#GL_BLEND}. 136 * </p> 137 * @param rs the used {@link RenderState} 138 * @param enableCallback optional {@link GLCallback}, if not <code>null</code> will be issued at 139 * {@link #init(GL2ES2, int) init(gl)} and {@link #enable(GL2ES2, boolean) enable(gl, true)}. 140 * @param disableCallback optional {@link GLCallback}, if not <code>null</code> will be issued at 141 * {@link #enable(GL2ES2, boolean) enable(gl, false)}. 142 * @return an instance of Region Renderer 143 * @see #enable(GL2ES2, boolean) 144 */ create(final RenderState rs, final GLCallback enableCallback, final GLCallback disableCallback)145 public static RegionRenderer create(final RenderState rs, final GLCallback enableCallback, 146 final GLCallback disableCallback) { 147 return new RegionRenderer(rs, enableCallback, disableCallback); 148 } 149 150 private final RenderState rs; 151 152 private final GLCallback enableCallback; 153 private final GLCallback disableCallback; 154 155 private int vp_width; 156 private int vp_height; 157 private boolean initialized; 158 private boolean vboSupported = false; 159 isInitialized()160 public final boolean isInitialized() { return initialized; } 161 162 /** Return width of current viewport */ getWidth()163 public final int getWidth() { return vp_width; } 164 /** Return height of current viewport */ getHeight()165 public final int getHeight() { return vp_height; } 166 getMatrix()167 public final PMVMatrix getMatrix() { return rs.getMatrix(); } 168 169 ////////////////////////////////////// 170 171 /** 172 * @param rs the used {@link RenderState} 173 */ RegionRenderer(final RenderState rs, final GLCallback enableCallback, final GLCallback disableCallback)174 protected RegionRenderer(final RenderState rs, final GLCallback enableCallback, final GLCallback disableCallback) { 175 this.rs = rs; 176 this.enableCallback = enableCallback; 177 this.disableCallback = disableCallback; 178 } 179 isVBOSupported()180 public final boolean isVBOSupported() { return vboSupported; } 181 182 /** 183 * Initialize shader and bindings for GPU based rendering bound to the given GL object's GLContext 184 * if not initialized yet. 185 * <p>Leaves the renderer enabled, ie ShaderState.</p> 186 * <p>Shall be called by a {@code draw()} method, e.g. {@link RegionRenderer#draw(GL2ES2, Region, int)}</p> 187 * 188 * @param gl referencing the current GLContext to which the ShaderState is bound to 189 * @param renderModes 190 * @throws GLException if initialization failed 191 */ init(final GL2ES2 gl, final int renderModes)192 public final void init(final GL2ES2 gl, final int renderModes) throws GLException { 193 if(initialized){ 194 return; 195 } 196 vboSupported = gl.isFunctionAvailable("glGenBuffers") && 197 gl.isFunctionAvailable("glBindBuffer") && 198 gl.isFunctionAvailable("glBufferData") && 199 gl.isFunctionAvailable("glDrawElements") && 200 gl.isFunctionAvailable("glVertexAttribPointer") && 201 gl.isFunctionAvailable("glDeleteBuffers"); 202 203 if(DEBUG) { 204 System.err.println("TextRendererImpl01: VBO Supported = " + isVBOSupported()); 205 } 206 207 if(!vboSupported){ 208 throw new GLException("VBO not supported"); 209 } 210 211 rs.attachTo(gl); 212 213 if( null != enableCallback ) { 214 enableCallback.run(gl, this); 215 } 216 initialized = true; 217 } 218 destroy(final GL2ES2 gl)219 public final void destroy(final GL2ES2 gl) { 220 if(!initialized){ 221 if(DEBUG_INSTANCE) { 222 System.err.println("TextRenderer: Not initialized!"); 223 } 224 return; 225 } 226 for(final Iterator<IntObjectHashMap.Entry> i = shaderPrograms.iterator(); i.hasNext(); ) { 227 final ShaderProgram sp = (ShaderProgram) i.next().getValue(); 228 sp.destroy(gl); 229 } 230 shaderPrograms.clear(); 231 rs.destroy(gl); 232 initialized = false; 233 } 234 getRenderState()235 public final RenderState getRenderState() { return rs; } 236 237 /** 238 * Enabling or disabling the {@link #getRenderState() RenderState}'s 239 * {@link RenderState#getShaderProgram() shader program}. 240 * <p> 241 * In case enable and disable {@link GLCallback}s are setup via {@link #create(RenderState, GLCallback, GLCallback)}, 242 * they will be called before toggling the shader program. 243 * </p> 244 * @see #create(RenderState, GLCallback, GLCallback) 245 */ enable(final GL2ES2 gl, final boolean enable)246 public final void enable(final GL2ES2 gl, final boolean enable) { 247 if( enable ) { 248 if( null != enableCallback ) { 249 enableCallback.run(gl, this); 250 } 251 } else { 252 if( null != disableCallback ) { 253 disableCallback.run(gl, this); 254 } 255 } 256 if( !enable ) { 257 final ShaderProgram sp = rs.getShaderProgram(); 258 if( null != sp ) { 259 sp.useProgram(gl, false); 260 } 261 } 262 } 263 264 /** No PMVMatrix operation is performed here. PMVMatrix is marked dirty. */ reshapeNotify(final int width, final int height)265 public final void reshapeNotify(final int width, final int height) { 266 this.vp_width = width; 267 this.vp_height = height; 268 } 269 reshapePerspective(final float angle, final int width, final int height, final float near, final float far)270 public final void reshapePerspective(final float angle, final int width, final int height, final float near, final float far) { 271 this.vp_width = width; 272 this.vp_height = height; 273 final float ratio = (float)width/(float)height; 274 final PMVMatrix p = rs.getMatrix(); 275 p.glMatrixMode(GLMatrixFunc.GL_PROJECTION); 276 p.glLoadIdentity(); 277 p.gluPerspective(angle, ratio, near, far); 278 } 279 reshapeOrtho(final int width, final int height, final float near, final float far)280 public final void reshapeOrtho(final int width, final int height, final float near, final float far) { 281 this.vp_width = width; 282 this.vp_height = height; 283 final PMVMatrix p = rs.getMatrix(); 284 p.glMatrixMode(GLMatrixFunc.GL_PROJECTION); 285 p.glLoadIdentity(); 286 p.glOrthof(0, width, 0, height, near, far); 287 } 288 289 // 290 // Shader Management 291 // 292 293 private static final String SHADER_SRC_SUB = ""; 294 private static final String SHADER_BIN_SUB = "bin"; 295 296 private static String GLSL_USE_COLOR_CHANNEL = "#define USE_COLOR_CHANNEL 1\n"; 297 private static String GLSL_USE_COLOR_TEXTURE = "#define USE_COLOR_TEXTURE 1\n"; 298 private static String GLSL_DEF_SAMPLE_COUNT = "#define SAMPLE_COUNT "; 299 private static String GLSL_CONST_SAMPLE_COUNT = "const float sample_count = "; 300 private static String GLSL_MAIN_BEGIN = "void main (void)\n{\n"; 301 private static final String gcuTexture2D = "gcuTexture2D"; 302 getVersionedShaderName()303 private String getVersionedShaderName() { 304 return "curverenderer01"; 305 } 306 307 // FIXME: Really required to have sampler2D def. precision ? If not, we can drop getFragmentShaderPrecision(..) and use default ShaderCode .. 308 private static final String es2_precision_fp = "\nprecision mediump float;\nprecision mediump int;\nprecision mediump sampler2D;\n"; 309 getFragmentShaderPrecision(final GL2ES2 gl)310 private final String getFragmentShaderPrecision(final GL2ES2 gl) { 311 if( gl.isGLES() ) { 312 return es2_precision_fp; 313 } 314 if( ShaderCode.requiresGL3DefaultPrecision(gl) ) { 315 return ShaderCode.gl3_default_precision_fp; 316 } 317 return null; 318 } 319 320 private static enum ShaderModeSelector1 { 321 /** Pass-1: Curve Simple */ 322 PASS1_SIMPLE("curve", "_simple", 0), 323 /** Pass-1: Curve Varying Weight */ 324 PASS1_WEIGHT("curve", "_weight", 0), 325 /** Pass-2: MSAA */ 326 PASS2_MSAA("msaa", "", 0), 327 /** Pass-2: VBAA Flipquad3, 1 sample */ 328 PASS2_VBAA_QUAL0_SAMPLES1("vbaa", "_flipquad3", 1), 329 /** Pass-2: VBAA Flipquad3, 2 samples */ 330 PASS2_VBAA_QUAL0_SAMPLES2("vbaa", "_flipquad3", 2), 331 /** Pass-2: VBAA Flipquad3, 4 samples */ 332 PASS2_VBAA_QUAL0_SAMPLES4("vbaa", "_flipquad3", 4), 333 /** Pass-2: VBAA Flipquad3, 8 samples */ 334 PASS2_VBAA_QUAL0_SAMPLES8("vbaa", "_flipquad3", 8), 335 336 /** Pass-2: VBAA Brute-Force, Odd, 1 samples */ 337 PASS2_VBAA_QUAL1_SAMPLES1("vbaa", "_bforce_odd", 1), 338 /** Pass-2: VBAA Brute-Force, Even, 2 samples */ 339 PASS2_VBAA_QUAL1_SAMPLES2("vbaa", "_bforce_even", 2), 340 /** Pass-2: VBAA Brute-Force, Odd, 3 samples */ 341 PASS2_VBAA_QUAL1_SAMPLES3("vbaa", "_bforce_odd", 3), 342 /** Pass-2: VBAA Brute-Force, Even, 4 samples */ 343 PASS2_VBAA_QUAL1_SAMPLES4("vbaa", "_bforce_even", 4), 344 /** Pass-2: VBAA Brute-Force, Odd, 5 samples */ 345 PASS2_VBAA_QUAL1_SAMPLES5("vbaa", "_bforce_odd", 5), 346 /** Pass-2: VBAA Brute-Force, Even, 6 samples */ 347 PASS2_VBAA_QUAL1_SAMPLES6("vbaa", "_bforce_even", 6), 348 /** Pass-2: VBAA Brute-Force, Odd, 7 samples */ 349 PASS2_VBAA_QUAL1_SAMPLES7("vbaa", "_bforce_odd", 7), 350 /** Pass-2: VBAA Brute-Force, Even, 8 samples */ 351 PASS2_VBAA_QUAL1_SAMPLES8("vbaa", "_bforce_even", 8); 352 353 public final String tech; 354 public final String sub; 355 public final int sampleCount; 356 ShaderModeSelector1(final String tech, final String sub, final int sampleCount)357 ShaderModeSelector1(final String tech, final String sub, final int sampleCount) { 358 this.tech = tech; 359 this.sub= sub; 360 this.sampleCount = sampleCount; 361 } 362 selectPass1(final int renderModes)363 public static ShaderModeSelector1 selectPass1(final int renderModes) { 364 return Region.hasVariableWeight(renderModes) ? PASS1_WEIGHT : PASS1_SIMPLE; 365 } 366 selectPass2(final int renderModes, final int quality, final int sampleCount)367 public static ShaderModeSelector1 selectPass2(final int renderModes, final int quality, final int sampleCount) { 368 if( Region.isMSAA(renderModes) ) { 369 return PASS2_MSAA; 370 } else if( Region.isVBAA(renderModes) ) { 371 if( 0 == quality ) { 372 if( sampleCount < 2 ) { 373 return PASS2_VBAA_QUAL0_SAMPLES1; 374 } else if( sampleCount < 4 ) { 375 return PASS2_VBAA_QUAL0_SAMPLES2; 376 } else if( sampleCount < 8 ) { 377 return PASS2_VBAA_QUAL0_SAMPLES4; 378 } else { 379 return PASS2_VBAA_QUAL0_SAMPLES8; 380 } 381 } else { 382 switch( sampleCount ) { 383 case 0: // Fall through intended 384 case 1: return PASS2_VBAA_QUAL1_SAMPLES1; 385 case 2: return PASS2_VBAA_QUAL1_SAMPLES2; 386 case 3: return PASS2_VBAA_QUAL1_SAMPLES3; 387 case 4: return PASS2_VBAA_QUAL1_SAMPLES4; 388 case 5: return PASS2_VBAA_QUAL1_SAMPLES5; 389 case 6: return PASS2_VBAA_QUAL1_SAMPLES6; 390 case 7: return PASS2_VBAA_QUAL1_SAMPLES7; 391 default: return PASS2_VBAA_QUAL1_SAMPLES8; 392 } 393 } 394 } else { 395 return null; 396 } 397 } 398 } 399 private final IntObjectHashMap shaderPrograms = new IntObjectHashMap(); 400 401 private static final int HIGH_MASK = Region.COLORCHANNEL_RENDERING_BIT | Region.COLORTEXTURE_RENDERING_BIT; 402 private static final int TWO_PASS_BIT = 1 << 31; 403 404 /** 405 * @param gl 406 * @param renderModes 407 * @param pass1 408 * @param quality 409 * @param sampleCount 410 * @param colorTexSeq 411 * @return true if a new shader program is being used and hence external uniform-data and -location, 412 * as well as the attribute-location must be updated, otherwise false. 413 */ useShaderProgram(final GL2ES2 gl, final int renderModes, final boolean pass1, final int quality, final int sampleCount, final TextureSequence colorTexSeq)414 public final boolean useShaderProgram(final GL2ES2 gl, final int renderModes, 415 final boolean pass1, final int quality, final int sampleCount, final TextureSequence colorTexSeq) { 416 final int colorTexSeqHash; 417 if( null != colorTexSeq ) { 418 colorTexSeqHash = colorTexSeq.getTextureFragmentShaderHashCode(); 419 } else { 420 colorTexSeqHash = 0; 421 } 422 final ShaderModeSelector1 sel1 = pass1 ? ShaderModeSelector1.selectPass1(renderModes) : 423 ShaderModeSelector1.selectPass2(renderModes, quality, sampleCount); 424 final boolean isTwoPass = Region.isTwoPass( renderModes ); 425 final boolean isPass1ColorTexSeq = pass1 && null != colorTexSeq; 426 final int shaderKey = ( (colorTexSeqHash << 5) - colorTexSeqHash ) + 427 ( sel1.ordinal() | ( HIGH_MASK & renderModes ) | ( isTwoPass ? TWO_PASS_BIT : 0 ) ); 428 429 /** 430 if(DEBUG) { 431 System.err.printf("RegionRendererImpl01.useShaderProgram.0: renderModes %s, sel1 %s, key 0x%X (pass1 %b, q %d, samples %d) - Thread %s%n", 432 Region.getRenderModeString(renderModes), sel1, shaderKey, pass1, quality, sampleCount, Thread.currentThread()); 433 } */ 434 435 ShaderProgram sp = (ShaderProgram) shaderPrograms.get( shaderKey ); 436 if( null != sp ) { 437 final boolean spChanged = getRenderState().setShaderProgram(gl, sp); 438 if(DEBUG) { 439 if( spChanged ) { 440 System.err.printf("RegionRendererImpl01.useShaderProgram.X1: GOT renderModes %s, sel1 %s, key 0x%X -> sp %d / %d (changed)%n", Region.getRenderModeString(renderModes), sel1, shaderKey, sp.program(), sp.id()); 441 } else { 442 System.err.printf("RegionRendererImpl01.useShaderProgram.X1: GOT renderModes %s, sel1 %s, key 0x%X -> sp %d / %d (keep)%n", Region.getRenderModeString(renderModes), sel1, shaderKey, sp.program(), sp.id()); 443 } 444 } 445 return spChanged; 446 } 447 final String versionedBaseName = getVersionedShaderName(); 448 final String vertexShaderName; 449 if( isTwoPass ) { 450 vertexShaderName = versionedBaseName+"-pass"+(pass1?1:2); 451 } else { 452 vertexShaderName = versionedBaseName+"-single"; 453 } 454 final ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, AttributeNames.class, SHADER_SRC_SUB, SHADER_BIN_SUB, vertexShaderName, true); 455 final ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, AttributeNames.class, SHADER_SRC_SUB, SHADER_BIN_SUB, versionedBaseName+"-segment-head", true); 456 457 if( isPass1ColorTexSeq && GLES2.GL_TEXTURE_EXTERNAL_OES == colorTexSeq.getTextureTarget() ) { 458 if( !gl.isExtensionAvailable(GLExtensions.OES_EGL_image_external) ) { 459 throw new GLException(GLExtensions.OES_EGL_image_external+" requested but not available"); 460 } 461 } 462 boolean supressGLSLVersionES30 = false; 463 if( isPass1ColorTexSeq && GLES2.GL_TEXTURE_EXTERNAL_OES == colorTexSeq.getTextureTarget() ) { 464 if( Platform.OSType.ANDROID == Platform.getOSType() && gl.isGLES3() ) { 465 // Bug on Nexus 10, ES3 - Android 4.3, where 466 // GL_OES_EGL_image_external extension directive leads to a failure _with_ '#version 300 es' ! 467 // P0003: Extension 'GL_OES_EGL_image_external' not supported 468 supressGLSLVersionES30 = true; 469 } 470 } 471 // 472 // GLSL customization at top 473 // 474 int posVp = rsVp.defaultShaderCustomization(gl, !supressGLSLVersionES30, true); 475 // rsFp.defaultShaderCustomization(gl, true, true); 476 int posFp = supressGLSLVersionES30 ? 0 : rsFp.addGLSLVersion(gl); 477 if( isPass1ColorTexSeq ) { 478 posFp = rsFp.insertShaderSource(0, posFp, colorTexSeq.getRequiredExtensionsShaderStub()); 479 } 480 if( pass1 && supressGLSLVersionES30 || ( gl.isGLES2() && !gl.isGLES3() ) ) { 481 posFp = rsFp.insertShaderSource(0, posFp, ShaderCode.createExtensionDirective(GLExtensions.OES_standard_derivatives, ShaderCode.ENABLE)); 482 } 483 if( false ) { 484 final String rsFpDefPrecision = getFragmentShaderPrecision(gl); 485 if( null != rsFpDefPrecision ) { 486 posFp = rsFp.insertShaderSource(0, posFp, rsFpDefPrecision); 487 } 488 } else { 489 posFp = rsFp.addDefaultShaderPrecision(gl, posFp); 490 } 491 492 // 493 // GLSL append from here on 494 posFp = -1; 495 496 if( Region.hasColorChannel( renderModes ) ) { 497 posVp = rsVp.insertShaderSource(0, posVp, GLSL_USE_COLOR_CHANNEL); 498 posFp = rsFp.insertShaderSource(0, posFp, GLSL_USE_COLOR_CHANNEL); 499 } 500 if( Region.hasColorTexture( renderModes ) ) { 501 rsVp.insertShaderSource(0, posVp, GLSL_USE_COLOR_TEXTURE); 502 posFp = rsFp.insertShaderSource(0, posFp, GLSL_USE_COLOR_TEXTURE); 503 } 504 if( !pass1 ) { 505 posFp = rsFp.insertShaderSource(0, posFp, GLSL_DEF_SAMPLE_COUNT+sel1.sampleCount+"\n"); 506 posFp = rsFp.insertShaderSource(0, posFp, GLSL_CONST_SAMPLE_COUNT+sel1.sampleCount+".0;\n"); 507 } 508 509 try { 510 posFp = rsFp.insertShaderSource(0, posFp, AttributeNames.class, "uniforms.glsl"); 511 posFp = rsFp.insertShaderSource(0, posFp, AttributeNames.class, "varyings.glsl"); 512 } catch (final IOException ioe) { 513 throw new RuntimeException("Failed to read: includes", ioe); 514 } 515 if( 0 > posFp ) { 516 throw new RuntimeException("Failed to read: includes"); 517 } 518 519 final String texLookupFuncName; 520 if( isPass1ColorTexSeq ) { 521 posFp = rsFp.insertShaderSource(0, posFp, "uniform "+colorTexSeq.getTextureSampler2DType()+" "+UniformNames.gcu_ColorTexUnit+";\n"); 522 texLookupFuncName = colorTexSeq.getTextureLookupFunctionName(gcuTexture2D); 523 posFp = rsFp.insertShaderSource(0, posFp, colorTexSeq.getTextureLookupFragmentShaderImpl()); 524 } else { 525 texLookupFuncName = null; 526 } 527 528 posFp = rsFp.insertShaderSource(0, posFp, GLSL_MAIN_BEGIN); 529 530 final String passS = pass1 ? "-pass1-" : "-pass2-"; 531 final String shaderSegment = versionedBaseName+passS+sel1.tech+sel1.sub+".glsl"; 532 if(DEBUG) { 533 System.err.printf("RegionRendererImpl01.useShaderProgram.1: segment %s%n", shaderSegment); 534 } 535 try { 536 posFp = rsFp.insertShaderSource(0, posFp, AttributeNames.class, shaderSegment); 537 } catch (final IOException ioe) { 538 throw new RuntimeException("Failed to read: "+shaderSegment, ioe); 539 } 540 if( 0 > posFp ) { 541 throw new RuntimeException("Failed to read: "+shaderSegment); 542 } 543 posFp = rsFp.insertShaderSource(0, posFp, "}\n"); 544 545 if( isPass1ColorTexSeq ) { 546 rsFp.replaceInShaderSource(gcuTexture2D, texLookupFuncName); 547 } 548 549 sp = new ShaderProgram(); 550 sp.add(rsVp); 551 sp.add(rsFp); 552 553 if( !sp.init(gl) ) { 554 throw new GLException("RegionRenderer: Couldn't init program: "+sp); 555 } 556 557 if( !sp.link(gl, System.err) ) { 558 throw new GLException("could not link program: "+sp); 559 } 560 getRenderState().setShaderProgram(gl, sp); 561 562 shaderPrograms.put(shaderKey, sp); 563 if(DEBUG) { 564 System.err.printf("RegionRendererImpl01.useShaderProgram.X1: PUT renderModes %s, sel1 %s, key 0x%X -> sp %d / %d (changed)%n", 565 Region.getRenderModeString(renderModes), sel1, shaderKey, sp.program(), sp.id()); 566 } 567 return true; 568 } 569 }