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