modules/graphics/src/main/java/com/sun/prism/impl/ps/BaseShaderContext.java

Print this page




  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 
  75     public enum MaskType {
  76         SOLID          ("Solid"),
  77         TEXTURE        ("Texture"),
  78         ALPHA_ONE           ("AlphaOne", true),
  79         ALPHA_TEXTURE       ("AlphaTexture", true),
  80         ALPHA_TEXTURE_DIFF  ("AlphaTextureDifference", true),
  81         FILL_PGRAM     ("FillPgram"),
  82         DRAW_PGRAM     ("DrawPgram", FILL_PGRAM),
  83         FILL_CIRCLE    ("FillCircle"),
  84         DRAW_CIRCLE    ("DrawCircle", FILL_CIRCLE),
  85         FILL_ELLIPSE   ("FillEllipse"),
  86         DRAW_ELLIPSE   ("DrawEllipse", FILL_ELLIPSE),
  87         FILL_ROUNDRECT ("FillRoundRect"),
  88         DRAW_ROUNDRECT ("DrawRoundRect", FILL_ROUNDRECT),
  89         DRAW_SEMIROUNDRECT("DrawSemiRoundRect"),
  90         FILL_CUBICCURVE("FillCubicCurve");
  91 
  92         private String name;
  93         private MaskType filltype;


 303             shaders[sst.ordinal()] = shader = factory.createStockShader(shaderName);
 304         }
 305         return shader;
 306     }
 307 
 308     @Override
 309     public boolean isSuperShaderEnabled() {
 310         return state.lastShader == specialATShaders[SpecialShaderType.SUPER.ordinal()]
 311                 || state.lastShader == specialShaders[SpecialShaderType.SUPER.ordinal()];
 312     }
 313 
 314     private void updatePerVertexColor(Paint paint, float extraAlpha) {
 315         if (paint != null && paint.getType() == Paint.Type.COLOR) {
 316             getVertexBuffer().setPerVertexColor((Color)paint, extraAlpha);
 317         } else {
 318             getVertexBuffer().setPerVertexColor(extraAlpha);
 319         }
 320     }
 321 
 322     @Override





 323     public void validatePaintOp(BaseGraphics g, BaseTransform xform,
 324                                 Texture maskTex,
 325                                 float bx, float by, float bw, float bh)
 326     {
 327         validatePaintOp((BaseShaderGraphics)g, xform,
 328                         maskTex, bx, by, bw, bh);
 329     }
 330 
 331     Shader validatePaintOp(BaseShaderGraphics g, BaseTransform xform,
 332                            MaskType maskType,
 333                            float bx, float by, float bw, float bh)
 334     {
 335         return validatePaintOp(g, xform, maskType, null, bx, by, bw, bh);
 336     }
 337 
 338     Shader validatePaintOp(BaseShaderGraphics g, BaseTransform xform,
 339                            MaskType maskType,
 340                            float bx, float by, float bw, float bh,
 341                            float k1, float k2, float k3, float k4, float k5, float k6)
 342     {


 389 
 390     Shader validatePaintOp(BaseShaderGraphics g, BaseTransform xform,
 391                            Texture maskTex,
 392                            float bx, float by, float bw, float bh)
 393     {
 394         return validatePaintOp(g, xform, MaskType.TEXTURE,
 395                                maskTex, bx, by, bw, bh);
 396     }
 397 
 398     Shader validatePaintOp(BaseShaderGraphics g, BaseTransform xform,
 399                            MaskType maskType, Texture maskTex,
 400                            float bx, float by, float bw, float bh)
 401     {
 402         if (maskType == null) {
 403             throw new InternalError("maskType must be non-null");
 404         }
 405 
 406         if (externalShader == null) {
 407             Paint paint = g.getPaint();
 408             Texture paintTex = null;
 409             Texture tex0 = null;
 410             Texture tex1 = null;
 411             if (paint.getType().isGradient()) {
 412                 // we need to flush here in case the paint shader is staying
 413                 // the same but the paint parameters are changing; we do this
 414                 // unconditionally for now (in theory we could keep track
 415                 // of the last validated paint, and the shape bounds in the
 416                 // case of proportional gradients, but the case where the
 417                 // same paint parameters are used multiple times in a row
 418                 // is so rare that it's not worth optimizing this any further)
 419                 flushVertexBuffer();
 420                 // we have to fetch the texture containing the gradient
 421                 // colors in advance since checkState() is responsible for
 422                 // binding the texture(s)
 423                 if (maskType.isNewPaintStyle()) {
 424                     paintTex = PaintHelper.getWrapGradientTexture(g);
 425                 } else {
 426                     paintTex = PaintHelper.getGradientTexture(g, (Gradient)paint);
 427                 }
 428             } else if (paint.getType() == Paint.Type.IMAGE_PATTERN) {
 429                 // We need to flush here. See comment above about paint parameters changing.
 430                 flushVertexBuffer();
 431                 ImagePattern texPaint = (ImagePattern)paint;
 432                 ResourceFactory rf = g.getResourceFactory();
 433                 paintTex = rf.getCachedTexture(texPaint.getImage(), Texture.WrapMode.REPEAT);
 434             }
 435             Shader shader = null;
 436             if (factory.isSuperShaderAllowed() &&
 437                 paintTex == null &&
 438                 maskTex == factory.getGlyphTexture())
 439             {
 440                 // Enabling the super shader to be used to render text.
 441                 // The texture pointed by tex0 is the region cache texture
 442                 // and it does not affect text rendering
 443                 shader = getSpecialShader(g, SpecialShaderType.SUPER);
 444                 tex0 = factory.getRegionTexture();
 445                 tex1 = maskTex;
 446             } else {
 447                 // NOTE: We are making assumptions here about which texture
 448                 // corresponds to which texture unit.  In a JSL file the
 449                 // first sampler mentioned will correspond to texture unit 0,
 450                 // the second sampler will correspond to texture unit 1,
 451                 // and so on, and there's currently no way to explicitly
 452                 // associate a sampler with a texture unit in the JSL file.
 453                 // So for now we assume that mask-related samplers are
 454                 // declared before any paint-related samplers in the
 455                 // composed JSL files.
 456                 if (maskTex != null) {
 457                     tex0 = maskTex;
 458                     tex1 = paintTex;
 459                 } else {
 460                     tex0 = paintTex;
 461                     tex1 = null;
 462                 }
 463                 // We do alpha test if depth test is enabled
 464                 shader = getPaintShader(g.isDepthTest() && g.isDepthBuffer(), maskType, paint);
 465             }
 466             checkState(g, xform, shader, tex0, tex1);


 467             updatePaintShader(g, shader, maskType, paint, bx, by, bw, bh);
 468             updatePerVertexColor(paint, g.getExtraAlpha());
 469             if (paintTex != null) paintTex.unlock();
 470             return shader;
 471         } else {
 472             // note that paint is assumed to be a simple Color in this case
 473             checkState(g, xform, externalShader, maskTex, null);


 474             updatePerVertexColor(null, g.getExtraAlpha());
 475             return externalShader;
 476         }
 477     }
 478 
 479     @Override
 480     public void validateTextureOp(BaseGraphics g, BaseTransform xform,
 481                                   Texture tex0, PixelFormat format)
 482     {
 483         validateTextureOp((BaseShaderGraphics)g, xform, tex0, null, format);
 484     }
 485 
 486     //This function sets the first LCD sample shader.
 487     public Shader validateLCDOp(BaseShaderGraphics g, BaseTransform xform,
 488                                 Texture tex0, Texture tex1, boolean firstPass,
 489                                 Paint fillColor)
 490     {
 491         Shader shader = firstPass ? getSpecialShader(g, SpecialShaderType.TEXTURE_First_LCD) :
 492                                     getSpecialShader(g, SpecialShaderType.TEXTURE_SECOND_LCD);
 493 
 494         checkState(g, xform, shader, tex0, tex1);


 495         updatePerVertexColor(fillColor, g.getExtraAlpha());
 496         return shader;
 497     }
 498 
 499     Shader validateTextureOp(BaseShaderGraphics g, BaseTransform xform,
 500                              Texture[] textures, PixelFormat format)
 501     {
 502         Shader shader = null;
 503 
 504         if (format == PixelFormat.MULTI_YCbCr_420) {
 505             // must have at least three textures, any more than four are ignored
 506             if (textures.length < 3) {
 507                 return null;
 508             }
 509 
 510             if (externalShader == null) {
 511                 shader = getSpecialShader(g, SpecialShaderType.TEXTURE_YV12);
 512             } else {
 513                 shader = externalShader;
 514             }
 515         } else { // add more multitexture shaders here
 516             return null;
 517         }
 518 
 519         if (null != shader) {
 520             checkState(g, xform, shader, textures);





 521             updatePerVertexColor(null, g.getExtraAlpha());
 522         }
 523         return shader;
 524     }
 525 
 526     Shader validateTextureOp(BaseShaderGraphics g, BaseTransform xform,
 527                              Texture tex0, Texture tex1, PixelFormat format)
 528     {
 529         Shader shader;
 530         if (externalShader == null) {
 531             switch (format) {
 532             case INT_ARGB_PRE:
 533             case BYTE_BGRA_PRE:
 534             case BYTE_RGB:
 535             case BYTE_GRAY:
 536             case BYTE_APPLE_422: // uses GL_RGBA as internal format
 537                 if (factory.isSuperShaderAllowed() &&
 538                     tex0 == factory.getRegionTexture() &&
 539                     tex1 == null)
 540                 {
 541                     // Enabling the super shader to be used for texture rendering.
 542                     // The shader was designed to render many Regions (from the Region
 543                     // texture cache) and text (from the glyph cache texture) without
 544                     // changing the state in the context.
 545                     shader = getSpecialShader(g, SpecialShaderType.SUPER);
 546                     tex1 = factory.getGlyphTexture();
 547                 } else {
 548                     shader = getSpecialShader(g, SpecialShaderType.TEXTURE_RGB);
 549                 }
 550                 break;
 551             case MULTI_YCbCr_420: // Must use multitexture method
 552             case BYTE_ALPHA:
 553             default:
 554                 throw new InternalError("Pixel format not supported: " + format);
 555             }
 556         } else {
 557             shader = externalShader;
 558         }
 559         checkState(g, xform, shader, tex0, tex1);


 560         updatePerVertexColor(null, g.getExtraAlpha());
 561         return shader;
 562     }
 563 
 564     Shader validateMaskTextureOp(BaseShaderGraphics g, BaseTransform xform,
 565                                  Texture tex0, Texture tex1, PixelFormat format)
 566     {
 567         Shader shader;
 568         if (externalShader == null) {
 569             switch (format) {
 570             case INT_ARGB_PRE:
 571             case BYTE_BGRA_PRE:
 572             case BYTE_RGB:
 573             case BYTE_GRAY:
 574             case BYTE_APPLE_422: // uses GL_RGBA as internal format
 575                 shader = getSpecialShader(g, SpecialShaderType.TEXTURE_MASK_RGB);
 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, xform, shader, tex0, tex1);


 586         updatePerVertexColor(null, g.getExtraAlpha());
 587         return shader;
 588     }
 589 
 590     void setExternalShader(BaseShaderGraphics g, Shader shader) {
 591         // Note that this method is called when the user calls
 592         // ShaderGraphics.setExternalShader().  We flush any pending
 593         // operations and synchronously enable the given shader here
 594         // because the caller (i.e., decora-prism-ps peer) needs to be
 595         // able to call shader.setConstant() after calling setExternalShader().
 596         // (In the ES2 backend, setConstant() bottoms out in glUniform(),
 597         // which can only be called when the program is active, i.e., after
 598         // shader.enable() is called.  Kind of gross, but that's why the
 599         // external shader mechanism is setup the way it is currently.)
 600         // So here we enable the shader just so that the user can update
 601         // shader constants, and we set the externalShader instance variable.
 602         // Later in checkState(), we will set the externalShader and
 603         // update the current transform state "for real".
 604         flushVertexBuffer();
 605         if (shader != null) {
 606             shader.enable();
 607         }
 608         externalShader = shader;
 609     }
 610 
 611     private void checkState(BaseShaderGraphics g,

 612                             BaseTransform xform,
 613                             Shader shader,
 614                             Texture tex0, Texture tex1)
 615     {
 616         setRenderTarget(g);
 617 
 618         setTexture(0, tex0);
 619         setTexture(1, tex1);
 620 
 621         if (shader != state.lastShader) {
 622             flushVertexBuffer();
 623             shader.enable();
 624             state.lastShader = shader;
 625             // the transform matrix is part of the state of each shader
 626             // (in ES2 at least), so we need to make sure the transform
 627             // is updated for the current shader by setting isXformValid=false
 628             state.isXformValid = false;

 629         }
 630 
 631         if (!state.isXformValid || !xform.equals(state.lastTransform)) {
 632             flushVertexBuffer();
 633             updateShaderTransform(shader, xform);
 634             state.lastTransform.setTransform(xform);
 635             state.isXformValid = true;
 636         }
 637 
 638         Rectangle clip = g.getClipRectNoClone();
 639         if (clip != state.lastClip) {
 640             flushVertexBuffer();
 641             updateClipRect(clip);
 642             state.lastClip = clip;
 643         }
 644 
 645         CompositeMode mode = g.getCompositeMode();
 646         if (mode != state.lastComp) {
 647             flushVertexBuffer();
 648             updateCompositeMode(mode);
 649             state.lastComp = mode;
 650         }
 651     }
 652 
 653     private void checkState(BaseShaderGraphics g,
 654                             BaseTransform xform,
 655                             Shader shader,
 656                             Texture[] textures)
 657     {
 658         setRenderTarget(g);
 659 
 660         // clamp to 0..4 textures for now, expand on this later if we need to
 661         int texCount = Math.max(0, Math.min(textures.length, 4));
 662         for (int index = 0; index < texCount; index++) {
 663             setTexture(index, textures[index]);
 664         }
 665 
 666         if (shader != state.lastShader) {
 667             flushVertexBuffer();
 668             shader.enable();
 669             state.lastShader = shader;
 670             // the transform matrix is part of the state of each shader
 671             // (in ES2 at least), so we need to make sure the transform
 672             // is updated for the current shader by setting isXformValid=false
 673             state.isXformValid = false;
 674         }
 675 

 676         if (!state.isXformValid || !xform.equals(state.lastTransform)) {
 677             flushVertexBuffer();
 678             updateShaderTransform(shader, xform);
 679             state.lastTransform.setTransform(xform);
 680             state.isXformValid = true;
 681         }

 682 

 683         Rectangle clip = g.getClipRectNoClone();
 684         if (clip != state.lastClip) {
 685             flushVertexBuffer();
 686             updateClipRect(clip);
 687             state.lastClip = clip;
 688         }

 689 

 690         CompositeMode mode = g.getCompositeMode();
 691         if (mode != state.lastComp) {
 692             flushVertexBuffer();
 693             updateCompositeMode(mode);
 694             state.lastComp = mode;
 695         }
 696     }

 697 
 698     private void setTexture(int texUnit, Texture tex) {
 699         if (tex != null) tex.assertLocked();
 700         if (tex != state.lastTextures[texUnit]) {
 701             flushVertexBuffer();
 702             updateTexture(texUnit, tex);
 703             state.lastTextures[texUnit] = tex;
 704         }
 705     }
 706 
 707     //Current RenderTarget is the lcdBuffer after this method.
 708     public void initLCDBuffer(int width, int height) {
 709         lcdBuffer = factory.createRTTexture(width, height, Texture.WrapMode.CLAMP_NOT_NEEDED);
 710         // TODO: RT-29488 we need to track the uses of the LCD buffer,
 711         // but the flow of control through the text methods is
 712         // not straight-forward enough for a simple set of lock/unlock
 713         // fixes at this time.
 714         lcdBuffer.makePermanent();
 715     }
 716 
 717     public void disposeLCDBuffer() {
 718         if (lcdBuffer != null) {
 719             lcdBuffer.dispose();
 720             lcdBuffer = null;
 721         }
 722     }
 723 

 724     public RTTexture getLCDBuffer() {
 725         return lcdBuffer;
 726     }
 727 
 728     //Current RenderTarget is undefined after this method.
 729     public void validateLCDBuffer(RenderTarget renderTarget) {
 730         if (lcdBuffer == null ||
 731                 lcdBuffer.getPhysicalWidth() < renderTarget.getPhysicalWidth() ||
 732                 lcdBuffer.getPhysicalHeight() < renderTarget.getPhysicalHeight())
 733         {
 734             disposeLCDBuffer();
 735             initLCDBuffer(renderTarget.getPhysicalWidth(), renderTarget.getPhysicalHeight());
 736         }
 737     }
 738 
 739     abstract public void blit(RTTexture srcRTT, RTTexture dstRTT,
 740                           int srcX0, int srcY0, int srcX1, int srcY1,
 741                           int dstX0, int dstY0, int dstX1, int dstY1);
 742 
 743     @Override




  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;


 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     {


 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.isDepthTest() && g.isDepthBuffer(), 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