1 /* 2 * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.prism.impl.ps; 27 28 import com.sun.glass.ui.Screen; 29 import com.sun.javafx.geom.Rectangle; 30 import com.sun.javafx.geom.transform.Affine3D; 31 import com.sun.javafx.geom.transform.BaseTransform; 32 import com.sun.javafx.sg.prism.NGCamera; 33 import com.sun.prism.CompositeMode; 34 import com.sun.prism.PixelFormat; 35 import com.sun.prism.RTTexture; 36 import com.sun.prism.RenderTarget; 37 import com.sun.prism.ResourceFactory; 38 import com.sun.prism.Texture; 39 import com.sun.prism.impl.BaseContext; 40 import com.sun.prism.impl.BaseGraphics; 41 import com.sun.prism.impl.VertexBuffer; 42 import com.sun.prism.paint.Color; 43 import com.sun.prism.paint.Gradient; 44 import com.sun.prism.paint.ImagePattern; 45 import com.sun.prism.paint.LinearGradient; 46 import com.sun.prism.paint.Paint; 47 import com.sun.prism.paint.RadialGradient; 48 import com.sun.prism.ps.Shader; 49 import com.sun.prism.ps.ShaderFactory; 50 51 /** 52 * Maintains resources such as Shaders and GlyphCaches that are intended to 53 * be cached on a per-Screen basis, and provides methods that are called by 54 * BaseShaderGraphics to validate current state. The inner State class is 55 * used to encapsulate the current and previously validated state (such as 56 * texture bindings) so that the validation routines can avoid redundant 57 * state changes. There should be only one BaseShaderContext per Screen, 58 * however there may be one or more State instances per BaseShaderContext. 59 * <p> 60 * A note about State objects... The JOGL architecture creates a GLContext 61 * for each GLDrawable (one GLContext per GLDrawable, and one GLDrawable 62 * per onscreen window). Resources such as textures and shaders can be 63 * shared between those GLContext instances, but other state (texture bindings, 64 * scissor rect, etc) cannot be shared. Therefore we need to maintain 65 * one State instance per GLContext instance, which means there may be more 66 * than one State instance per BaseShaderContext. The currentState variable 67 * holds the current State instance corresponding to the current RenderTarget, 68 * and is revalidated as part of the updateRenderTarget() method. The ES2 69 * backend will create a new State instance for each window, but the D3D 70 * backend is free to create a single State instance that can be shared for 71 * the entire Screen. 72 */ 73 public abstract class BaseShaderContext extends BaseContext { 74 private static final int CHECK_SHADER = (0x01 ); 75 private static final int CHECK_TRANSFORM = (0x01 << 1); 76 private static final int CHECK_CLIP = (0x01 << 2); 77 private static final int CHECK_COMPOSITE = (0x01 << 3); 78 private static final int CHECK_PAINT_OP_MASK = 79 (CHECK_SHADER | CHECK_TRANSFORM | CHECK_CLIP | CHECK_COMPOSITE); 80 private static final int CHECK_TEXTURE_OP_MASK = 81 (CHECK_SHADER | CHECK_TRANSFORM | CHECK_CLIP | CHECK_COMPOSITE); 82 private static final int CHECK_CLEAR_OP_MASK = 83 (CHECK_CLIP); 84 85 public enum MaskType { 86 SOLID ("Solid"), 87 TEXTURE ("Texture"), 88 ALPHA_ONE ("AlphaOne", true), 89 ALPHA_TEXTURE ("AlphaTexture", true), 90 ALPHA_TEXTURE_DIFF ("AlphaTextureDifference", true), 91 FILL_PGRAM ("FillPgram"), 92 DRAW_PGRAM ("DrawPgram", FILL_PGRAM), 93 FILL_CIRCLE ("FillCircle"), 94 DRAW_CIRCLE ("DrawCircle", FILL_CIRCLE), 95 FILL_ELLIPSE ("FillEllipse"), 96 DRAW_ELLIPSE ("DrawEllipse", FILL_ELLIPSE), 97 FILL_ROUNDRECT ("FillRoundRect"), 98 DRAW_ROUNDRECT ("DrawRoundRect", FILL_ROUNDRECT), 99 DRAW_SEMIROUNDRECT("DrawSemiRoundRect"); 100 101 private String name; 102 private MaskType filltype; 103 private boolean newPaintStyle; 104 private MaskType(String name) { 105 this.name = name; 106 } 107 private MaskType(String name, boolean newstyle) { 108 this.name = name; 109 this.newPaintStyle = newstyle; 110 } 111 private MaskType(String name, MaskType filltype) { 112 this.name = name; 113 this.filltype = filltype; 114 } 115 public String getName() { 116 return name; 117 } 118 public MaskType getFillType() { 119 return filltype; 120 } 121 public boolean isNewPaintStyle() { 122 return newPaintStyle; 123 } 124 } 125 126 // mask type 4 bits (14 types) 127 // paint type 2 bits 128 // paint opts 2 bits 129 private static final int NUM_STOCK_SHADER_SLOTS = 130 MaskType.values().length << 4; 131 // TODO: need to dispose these when the context is disposed... (RT-27379) 132 private final Shader[] stockShaders = new Shader[NUM_STOCK_SHADER_SLOTS]; 133 // stockShaders with alpha test 134 private final Shader[] stockATShaders = new Shader[NUM_STOCK_SHADER_SLOTS]; 135 136 public enum SpecialShaderType { 137 TEXTURE_RGB ("Solid_TextureRGB"), 138 TEXTURE_MASK_RGB ("Mask_TextureRGB"), 139 TEXTURE_YV12 ("Solid_TextureYV12"), 140 TEXTURE_First_LCD ("Solid_TextureFirstPassLCD"), 141 TEXTURE_SECOND_LCD ("Solid_TextureSecondPassLCD"), 142 SUPER ("Mask_TextureSuper"); 143 144 private String name; 145 private SpecialShaderType(String name) { 146 this.name = name; 147 } 148 public String getName() { 149 return name; 150 } 151 } 152 private final Shader[] specialShaders = new Shader[SpecialShaderType.values().length]; 153 // specialShaders with alpha test 154 private final Shader[] specialATShaders = new Shader[SpecialShaderType.values().length]; 155 156 private Shader externalShader; 157 158 private RTTexture lcdBuffer; 159 private final ShaderFactory factory; 160 161 private State state; 162 163 protected BaseShaderContext(Screen screen, ShaderFactory factory, VertexBuffer vb) { 164 super(screen, factory, vb); 165 this.factory = factory; 166 init(); 167 } 168 169 protected void init() { 170 state = null; 171 if (externalShader != null && !externalShader.isValid()) { 172 externalShader.dispose(); 173 externalShader = null; 174 } 175 // the rest of the shaders will be re-validated as they are used 176 } 177 178 public static class State { 179 private Shader lastShader; 180 private RenderTarget lastRenderTarget; 181 private NGCamera lastCamera; 182 private boolean lastDepthTest; 183 private BaseTransform lastTransform = new Affine3D(); 184 private Rectangle lastClip; 185 private CompositeMode lastComp; 186 private Texture[] lastTextures = new Texture[4]; 187 private boolean isXformValid; 188 private float lastConst1 = Float.NaN; 189 private float lastConst2 = Float.NaN; 190 private float lastConst3 = Float.NaN; 191 private float lastConst4 = Float.NaN; 192 private float lastConst5 = Float.NaN; 193 private float lastConst6 = Float.NaN; 194 private boolean lastState3D = false; 195 } 196 197 protected void resetLastClip(State state) { 198 state.lastClip = null; 199 } 200 201 protected abstract State updateRenderTarget(RenderTarget target, NGCamera camera, 202 boolean depthTest); 203 204 protected abstract void updateTexture(int texUnit, Texture tex); 205 206 protected abstract void updateShaderTransform(Shader shader, 207 BaseTransform xform); 208 209 protected abstract void updateWorldTransform(BaseTransform xform); 210 211 protected abstract void updateClipRect(Rectangle clipRect); 212 213 protected abstract void updateCompositeMode(CompositeMode mode); 214 215 private static int getStockShaderIndex(MaskType maskType, Paint paint) { 216 int paintType; 217 int paintOption; 218 if (paint == null) { 219 paintType = 0; 220 paintOption = 0; 221 } else { 222 paintType = paint.getType().ordinal(); 223 if (paint.getType().isGradient()) { 224 paintOption = ((Gradient)paint).getSpreadMethod(); 225 } else { 226 paintOption = 0; 227 } 228 } 229 return (maskType.ordinal() << 4) | (paintType << 2) | (paintOption << 0); 230 } 231 232 private Shader getPaintShader(boolean alphaTest, MaskType maskType, Paint paint) { 233 int index = getStockShaderIndex(maskType, paint); 234 Shader shaders[] = alphaTest ? stockATShaders : stockShaders; 235 Shader shader = shaders[index]; 236 if (shader != null && !shader.isValid()) { 237 shader.dispose(); 238 shader = null; 239 } 240 if (shader == null) { 241 String shaderName = 242 maskType.getName() + "_" + paint.getType().getName(); 243 if (paint.getType().isGradient() && !maskType.isNewPaintStyle()) { 244 Gradient grad = (Gradient) paint; 245 int spreadMethod = grad.getSpreadMethod(); 246 if (spreadMethod == Gradient.PAD) { 247 shaderName += "_PAD"; 248 } else if (spreadMethod == Gradient.REFLECT) { 249 shaderName += "_REFLECT"; 250 } else if (spreadMethod == Gradient.REPEAT) { 251 shaderName += "_REPEAT"; 252 } 253 } 254 if (alphaTest) { 255 shaderName += "_AlphaTest"; 256 } 257 shader = shaders[index] = factory.createStockShader(shaderName); 258 } 259 return shader; 260 } 261 262 private void updatePaintShader(BaseShaderGraphics g, Shader shader, 263 MaskType maskType, Paint paint, 264 float bx, float by, float bw, float bh) 265 { 266 Paint.Type paintType = paint.getType(); 267 if (paintType == Paint.Type.COLOR || maskType.isNewPaintStyle()) { 268 return; 269 } 270 271 float rx, ry, rw, rh; 272 if (paint.isProportional()) { 273 rx = bx; ry = by; rw = bw; rh = bh; 274 } else { 275 rx = 0f; ry = 0f; rw = 1f; rh = 1f; 276 } 277 278 switch (paintType) { 279 case LINEAR_GRADIENT: 280 PaintHelper.setLinearGradient(g, shader, 281 (LinearGradient)paint, 282 rx, ry, rw, rh); 283 break; 284 case RADIAL_GRADIENT: 285 PaintHelper.setRadialGradient(g, shader, 286 (RadialGradient)paint, 287 rx, ry, rw, rh); 288 break; 289 case IMAGE_PATTERN: 290 PaintHelper.setImagePattern(g, shader, 291 (ImagePattern)paint, 292 rx, ry, rw, rh); 293 default: 294 break; 295 } 296 } 297 298 private Shader getSpecialShader(BaseGraphics g, SpecialShaderType sst) { 299 // We do alpha test if depth test is enabled 300 boolean alphaTest = g.isAlphaTestShader(); 301 Shader shaders[] = alphaTest ? specialATShaders : specialShaders; 302 Shader shader = shaders[sst.ordinal()]; 303 if (shader != null && !shader.isValid()) { 304 shader.dispose(); 305 shader = null; 306 } 307 if (shader == null) { 308 String shaderName = sst.getName(); 309 if (alphaTest) { 310 shaderName += "_AlphaTest"; 311 } 312 shaders[sst.ordinal()] = shader = factory.createStockShader(shaderName); 313 } 314 return shader; 315 } 316 317 @Override 318 public boolean isSuperShaderEnabled() { 319 return state.lastShader == specialATShaders[SpecialShaderType.SUPER.ordinal()] 320 || state.lastShader == specialShaders[SpecialShaderType.SUPER.ordinal()]; 321 } 322 323 private void updatePerVertexColor(Paint paint, float extraAlpha) { 324 if (paint != null && paint.getType() == Paint.Type.COLOR) { 325 getVertexBuffer().setPerVertexColor((Color)paint, extraAlpha); 326 } else { 327 getVertexBuffer().setPerVertexColor(extraAlpha); 328 } 329 } 330 331 @Override 332 public void validateClearOp(BaseGraphics g) { 333 checkState((BaseShaderGraphics) g, CHECK_CLEAR_OP_MASK, null, null); 334 } 335 336 @Override 337 public void validatePaintOp(BaseGraphics g, BaseTransform xform, 338 Texture maskTex, 339 float bx, float by, float bw, float bh) 340 { 341 validatePaintOp((BaseShaderGraphics)g, xform, 342 maskTex, bx, by, bw, bh); 343 } 344 345 Shader validatePaintOp(BaseShaderGraphics g, BaseTransform xform, 346 MaskType maskType, 347 float bx, float by, float bw, float bh) 348 { 349 return validatePaintOp(g, xform, maskType, null, bx, by, bw, bh); 350 } 351 352 Shader validatePaintOp(BaseShaderGraphics g, BaseTransform xform, 353 MaskType maskType, 354 float bx, float by, float bw, float bh, 355 float k1, float k2, float k3, float k4, float k5, float k6) 356 { 357 // this is not ideal, but will have to do for now (tm). 358 // various paint primitives use shader parameters, and we have to flush 359 // the vertex buffer if those change. Ideally we would do this in 360 // checkState but there is no mechanism to pass this info through. 361 if (state.lastConst1 != k1 || state.lastConst2 != k2 || 362 state.lastConst3 != k3 || state.lastConst4 != k4 || 363 state.lastConst5 != k5 || state.lastConst6 != k6) 364 { 365 flushVertexBuffer(); 366 367 state.lastConst1 = k1; 368 state.lastConst2 = k2; 369 state.lastConst3 = k3; 370 state.lastConst4 = k4; 371 state.lastConst5 = k5; 372 state.lastConst6 = k6; 373 } 374 375 return validatePaintOp(g, xform, maskType, null, bx, by, bw, bh); 376 } 377 378 Shader validatePaintOp(BaseShaderGraphics g, BaseTransform xform, 379 MaskType maskType, Texture maskTex, 380 float bx, float by, float bw, float bh, 381 float k1, float k2, float k3, float k4, float k5, float k6) 382 { 383 // this is not ideal, but will have to do for now (tm). 384 // various paint primitives use shader parameters, and we have to flush 385 // the vertex buffer if those change. Ideally we would do this in 386 // checkState but there is no mechanism to pass this info through. 387 if (state.lastConst1 != k1 || state.lastConst2 != k2 || 388 state.lastConst3 != k3 || state.lastConst4 != k4 || 389 state.lastConst5 != k5 || state.lastConst6 != k6) 390 { 391 flushVertexBuffer(); 392 393 state.lastConst1 = k1; 394 state.lastConst2 = k2; 395 state.lastConst3 = k3; 396 state.lastConst4 = k4; 397 state.lastConst5 = k5; 398 state.lastConst6 = k6; 399 } 400 401 return validatePaintOp(g, xform, maskType, maskTex, bx, by, bw, bh); 402 } 403 404 Shader validatePaintOp(BaseShaderGraphics g, BaseTransform xform, 405 Texture maskTex, 406 float bx, float by, float bw, float bh) 407 { 408 return validatePaintOp(g, xform, MaskType.TEXTURE, 409 maskTex, bx, by, bw, bh); 410 } 411 412 Shader validatePaintOp(BaseShaderGraphics g, BaseTransform xform, 413 MaskType maskType, Texture maskTex, 414 float bx, float by, float bw, float bh) 415 { 416 if (maskType == null) { 417 throw new InternalError("maskType must be non-null"); 418 } 419 420 if (externalShader == null) { 421 Paint paint = g.getPaint(); 422 Texture paintTex = null; 423 Texture tex0; 424 Texture tex1; 425 if (paint.getType().isGradient()) { 426 // we need to flush here in case the paint shader is staying 427 // the same but the paint parameters are changing; we do this 428 // unconditionally for now (in theory we could keep track 429 // of the last validated paint, and the shape bounds in the 430 // case of proportional gradients, but the case where the 431 // same paint parameters are used multiple times in a row 432 // is so rare that it's not worth optimizing this any further) 433 flushVertexBuffer(); 434 // we have to fetch the texture containing the gradient 435 // colors in advance since checkState() is responsible for 436 // binding the texture(s) 437 if (maskType.isNewPaintStyle()) { 438 paintTex = PaintHelper.getWrapGradientTexture(g); 439 } else { 440 paintTex = PaintHelper.getGradientTexture(g, (Gradient)paint); 441 } 442 } else if (paint.getType() == Paint.Type.IMAGE_PATTERN) { 443 // We need to flush here. See comment above about paint parameters changing. 444 flushVertexBuffer(); 445 ImagePattern texPaint = (ImagePattern)paint; 446 ResourceFactory rf = g.getResourceFactory(); 447 paintTex = rf.getCachedTexture(texPaint.getImage(), Texture.WrapMode.REPEAT); 448 } 449 Shader shader; 450 if (factory.isSuperShaderAllowed() && 451 paintTex == null && 452 maskTex == factory.getGlyphTexture()) 453 { 454 // Enabling the super shader to be used to render text. 455 // The texture pointed by tex0 is the region cache texture 456 // and it does not affect text rendering 457 shader = getSpecialShader(g, SpecialShaderType.SUPER); 458 tex0 = factory.getRegionTexture(); 459 tex1 = maskTex; 460 } else { 461 // NOTE: We are making assumptions here about which texture 462 // corresponds to which texture unit. In a JSL file the 463 // first sampler mentioned will correspond to texture unit 0, 464 // the second sampler will correspond to texture unit 1, 465 // and so on, and there's currently no way to explicitly 466 // associate a sampler with a texture unit in the JSL file. 467 // So for now we assume that mask-related samplers are 468 // declared before any paint-related samplers in the 469 // composed JSL files. 470 if (maskTex != null) { 471 tex0 = maskTex; 472 tex1 = paintTex; 473 } else { 474 tex0 = paintTex; 475 tex1 = null; 476 } 477 // We do alpha test if depth test is enabled 478 shader = getPaintShader(g.isAlphaTestShader(), maskType, paint); 479 } 480 checkState(g, CHECK_PAINT_OP_MASK, xform, shader); 481 setTexture(0, tex0); 482 setTexture(1, tex1); 483 updatePaintShader(g, shader, maskType, paint, bx, by, bw, bh); 484 updatePerVertexColor(paint, g.getExtraAlpha()); 485 if (paintTex != null) paintTex.unlock(); 486 return shader; 487 } else { 488 // note that paint is assumed to be a simple Color in this case 489 checkState(g, CHECK_PAINT_OP_MASK, xform, externalShader); 490 setTexture(0, maskTex); 491 setTexture(1, null); // Needed? 492 updatePerVertexColor(null, g.getExtraAlpha()); 493 return externalShader; 494 } 495 } 496 497 @Override 498 public void validateTextureOp(BaseGraphics g, BaseTransform xform, 499 Texture tex0, PixelFormat format) 500 { 501 validateTextureOp((BaseShaderGraphics)g, xform, tex0, null, format); 502 } 503 504 //This function sets the first LCD sample shader. 505 public Shader validateLCDOp(BaseShaderGraphics g, BaseTransform xform, 506 Texture tex0, Texture tex1, boolean firstPass, 507 Paint fillColor) 508 { 509 Shader shader = firstPass ? getSpecialShader(g, SpecialShaderType.TEXTURE_First_LCD) : 510 getSpecialShader(g, SpecialShaderType.TEXTURE_SECOND_LCD); 511 512 checkState(g, CHECK_TEXTURE_OP_MASK, xform, shader); 513 setTexture(0, tex0); 514 setTexture(1, tex1); 515 updatePerVertexColor(fillColor, g.getExtraAlpha()); 516 return shader; 517 } 518 519 Shader validateTextureOp(BaseShaderGraphics g, BaseTransform xform, 520 Texture[] textures, PixelFormat format) 521 { 522 Shader shader; 523 524 if (format == PixelFormat.MULTI_YCbCr_420) { 525 // must have at least three textures, any more than four are ignored 526 if (textures.length < 3) { 527 return null; 528 } 529 530 if (externalShader == null) { 531 shader = getSpecialShader(g, SpecialShaderType.TEXTURE_YV12); 532 } else { 533 shader = externalShader; 534 } 535 } else { // add more multitexture shaders here 536 return null; 537 } 538 539 if (null != shader) { 540 checkState(g, CHECK_TEXTURE_OP_MASK, xform, shader); 541 // clamp to 0..4 textures for now, expand on this later if we need to 542 int texCount = Math.max(0, Math.min(textures.length, 4)); 543 for (int index = 0; index < texCount; index++) { 544 setTexture(index, textures[index]); 545 } 546 updatePerVertexColor(null, g.getExtraAlpha()); 547 } 548 return shader; 549 } 550 551 Shader validateTextureOp(BaseShaderGraphics g, BaseTransform xform, 552 Texture tex0, Texture tex1, PixelFormat format) 553 { 554 Shader shader; 555 if (externalShader == null) { 556 switch (format) { 557 case INT_ARGB_PRE: 558 case BYTE_BGRA_PRE: 559 case BYTE_RGB: 560 case BYTE_GRAY: 561 case BYTE_APPLE_422: // uses GL_RGBA as internal format 562 if (factory.isSuperShaderAllowed() && 563 tex0 == factory.getRegionTexture() && 564 tex1 == null) 565 { 566 // Enabling the super shader to be used for texture rendering. 567 // The shader was designed to render many Regions (from the Region 568 // texture cache) and text (from the glyph cache texture) without 569 // changing the state in the context. 570 shader = getSpecialShader(g, SpecialShaderType.SUPER); 571 tex1 = factory.getGlyphTexture(); 572 } else { 573 shader = getSpecialShader(g, SpecialShaderType.TEXTURE_RGB); 574 } 575 break; 576 case MULTI_YCbCr_420: // Must use multitexture method 577 case BYTE_ALPHA: 578 default: 579 throw new InternalError("Pixel format not supported: " + format); 580 } 581 } else { 582 shader = externalShader; 583 } 584 checkState(g, CHECK_TEXTURE_OP_MASK, xform, shader); 585 setTexture(0, tex0); 586 setTexture(1, tex1); 587 updatePerVertexColor(null, g.getExtraAlpha()); 588 return shader; 589 } 590 591 Shader validateMaskTextureOp(BaseShaderGraphics g, BaseTransform xform, 592 Texture tex0, Texture tex1, PixelFormat format) 593 { 594 Shader shader; 595 if (externalShader == null) { 596 switch (format) { 597 case INT_ARGB_PRE: 598 case BYTE_BGRA_PRE: 599 case BYTE_RGB: 600 case BYTE_GRAY: 601 case BYTE_APPLE_422: // uses GL_RGBA as internal format 602 shader = getSpecialShader(g, SpecialShaderType.TEXTURE_MASK_RGB); 603 break; 604 case MULTI_YCbCr_420: // Must use multitexture method 605 case BYTE_ALPHA: 606 default: 607 throw new InternalError("Pixel format not supported: " + format); 608 } 609 } else { 610 shader = externalShader; 611 } 612 checkState(g, CHECK_TEXTURE_OP_MASK, xform, shader); 613 setTexture(0, tex0); 614 setTexture(1, tex1); 615 updatePerVertexColor(null, g.getExtraAlpha()); 616 return shader; 617 } 618 619 void setExternalShader(BaseShaderGraphics g, Shader shader) { 620 // Note that this method is called when the user calls 621 // ShaderGraphics.setExternalShader(). We flush any pending 622 // operations and synchronously enable the given shader here 623 // because the caller (i.e., decora-prism-ps peer) needs to be 624 // able to call shader.setConstant() after calling setExternalShader(). 625 // (In the ES2 backend, setConstant() bottoms out in glUniform(), 626 // which can only be called when the program is active, i.e., after 627 // shader.enable() is called. Kind of gross, but that's why the 628 // external shader mechanism is setup the way it is currently.) 629 // So here we enable the shader just so that the user can update 630 // shader constants, and we set the externalShader instance variable. 631 // Later in checkState(), we will set the externalShader and 632 // update the current transform state "for real". 633 flushVertexBuffer(); 634 if (shader != null) { 635 shader.enable(); 636 } 637 externalShader = shader; 638 } 639 640 private void checkState(BaseShaderGraphics g, 641 int checkFlags, 642 BaseTransform xform, 643 Shader shader) 644 { 645 setRenderTarget(g); 646 647 if ((checkFlags & CHECK_SHADER) != 0) { 648 if (shader != state.lastShader) { 649 flushVertexBuffer(); 650 shader.enable(); 651 state.lastShader = shader; 652 // the transform matrix is part of the state of each shader 653 // (in ES2 at least), so we need to make sure the transform 654 // is updated for the current shader by setting isXformValid=false 655 state.isXformValid = false; 656 checkFlags |= CHECK_TRANSFORM; 657 } 658 } 659 660 if ((checkFlags & CHECK_TRANSFORM) != 0) { 661 if (!state.isXformValid || !xform.equals(state.lastTransform)) { 662 flushVertexBuffer(); 663 updateShaderTransform(shader, xform); 664 state.lastTransform.setTransform(xform); 665 state.isXformValid = true; 666 } 667 } 668 669 if ((checkFlags & CHECK_CLIP) != 0) { 670 Rectangle clip = g.getClipRectNoClone(); 671 if (clip != state.lastClip) { 672 flushVertexBuffer(); 673 updateClipRect(clip); 674 state.lastClip = clip; 675 } 676 } 677 678 if ((checkFlags & CHECK_COMPOSITE) != 0) { 679 CompositeMode mode = g.getCompositeMode(); 680 if (mode != state.lastComp) { 681 flushVertexBuffer(); 682 updateCompositeMode(mode); 683 state.lastComp = mode; 684 } 685 } 686 } 687 688 private void setTexture(int texUnit, Texture tex) { 689 if (tex != null) tex.assertLocked(); 690 if (tex != state.lastTextures[texUnit]) { 691 flushVertexBuffer(); 692 updateTexture(texUnit, tex); 693 state.lastTextures[texUnit] = tex; 694 } 695 } 696 697 //Current RenderTarget is the lcdBuffer after this method. 698 public void initLCDBuffer(int width, int height) { 699 lcdBuffer = factory.createRTTexture(width, height, Texture.WrapMode.CLAMP_NOT_NEEDED); 700 // TODO: RT-29488 we need to track the uses of the LCD buffer, 701 // but the flow of control through the text methods is 702 // not straight-forward enough for a simple set of lock/unlock 703 // fixes at this time. 704 lcdBuffer.makePermanent(); 705 } 706 707 public void disposeLCDBuffer() { 708 if (lcdBuffer != null) { 709 lcdBuffer.dispose(); 710 lcdBuffer = null; 711 } 712 } 713 714 @Override 715 public RTTexture getLCDBuffer() { 716 return lcdBuffer; 717 } 718 719 //Current RenderTarget is undefined after this method. 720 public void validateLCDBuffer(RenderTarget renderTarget) { 721 if (lcdBuffer == null || 722 lcdBuffer.getPhysicalWidth() < renderTarget.getPhysicalWidth() || 723 lcdBuffer.getPhysicalHeight() < renderTarget.getPhysicalHeight()) 724 { 725 disposeLCDBuffer(); 726 initLCDBuffer(renderTarget.getPhysicalWidth(), renderTarget.getPhysicalHeight()); 727 } 728 } 729 730 abstract public void blit(RTTexture srcRTT, RTTexture dstRTT, 731 int srcX0, int srcY0, int srcX1, int srcY1, 732 int dstX0, int dstY0, int dstX1, int dstY1); 733 734 @Override 735 protected void setRenderTarget(RenderTarget target, NGCamera camera, 736 boolean depthTest, boolean state3D) 737 { 738 if (target instanceof Texture) { 739 ((Texture) target).assertLocked(); 740 } 741 if (state == null || 742 state3D != state.lastState3D || 743 target != state.lastRenderTarget || 744 camera != state.lastCamera || 745 depthTest != state.lastDepthTest) 746 { 747 flushVertexBuffer(); 748 state = updateRenderTarget(target, camera, depthTest); 749 state.lastRenderTarget = target; 750 state.lastCamera = camera; 751 state.lastDepthTest = depthTest; 752 753 // the projection matrix is set in updateShaderTransform() 754 // because it depends on the dimensions of the destination surface, 755 // so if the RenderTarget is changing we force a call to the 756 // updateShaderTransform() method by setting isXformValid=false 757 state.isXformValid = false; 758 759 // True if we switch between 2D and 3D primitives 760 if (state3D != state.lastState3D) { 761 state.lastState3D = state3D; 762 state.lastShader = null; 763 state.lastConst1 = Float.NaN; 764 state.lastConst2 = Float.NaN; 765 state.lastConst3 = Float.NaN; 766 state.lastConst4 = Float.NaN; 767 state.lastConst5 = Float.NaN; 768 state.lastConst6 = Float.NaN; 769 state.lastComp = null; 770 state.lastClip = null; 771 for (int i = 0; i != state.lastTextures.length; i++) { 772 state.lastTextures[i] = null; 773 } 774 if (state3D) { 775 // switch to 3D state 776 setDeviceParametersFor3D(); 777 } else { 778 // switch to 2D state 779 setDeviceParametersFor2D(); 780 } 781 } 782 } 783 } 784 785 @Override 786 protected void releaseRenderTarget() { 787 // Null out hard references that cause memory leak reported in RT-17304 788 if (state != null) { 789 state.lastRenderTarget = null; 790 for (int i=0; i<state.lastTextures.length; i++) { 791 state.lastTextures[i] = null; 792 } 793 } 794 } 795 796 }