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 |