Project

General

Profile

« Previous | Next » 

Revision 12f9e4bb

Added by Leszek Koltunski over 6 years ago

a mix of two changes:

1) remove the DistortedInputSurface interface (now every Surface is Input)
2) make the OIT SSBO self-adjustable in size

View differences:

src/main/java/org/distorted/library/main/Distorted.java
83 83
   * of FBO_QUEUE_SIZE FBOs. (otherwise we sometimes get a 'full pipeline flush' and the end result
84 84
   * might be missing part of the Objects)
85 85
   *
86
   * This bug only exists on Mali driver r12. TODO: on other platforms, make this equal to 1.
86
   * This bug only exists on Mali driver r12.
87 87
   *
88 88
   * https://community.arm.com/graphics/f/discussions/10285/opengl-es-3-1-on-mali-t880-flashes
89 89
   */
src/main/java/org/distorted/library/main/DistortedEffects.java
76 76

  
77 77
  /// OIT SSBO BUFFER ///
78 78
  private static int[] mLinkedListSSBO = new int[1];
79
  private static int[] mAtomicCounter = new int[1];
79
  private static int[] mAtomicCounter = new int[Distorted.FBO_QUEUE_SIZE];
80
  private static int   mCurrBuffer;
80 81

  
81 82
  static
82 83
    {
83 84
    mLinkedListSSBO[0]= -1;
84
    mAtomicCounter[0] = -1;
85
    mCurrBuffer       =  0;
86

  
87
    for(int i=0; i<Distorted.FBO_QUEUE_SIZE; i++)  mAtomicCounter[i] = -1;
85 88
    }
86 89

  
87 90
  ///////////////////////////////////////////////////////////////
......
535 538
    }
536 539

  
537 540
///////////////////////////////////////////////////////////////////////////////////////////////////
538
// reset atomic counter to 0
539 541

  
540
  static void zeroOutAtomic()
542
  private static int printPreviousBuffer()
541 543
    {
542
    if( mAtomicCounter[0]<0 )
544
    int counter = 0;
545

  
546
    ByteBuffer atomicBuf = (ByteBuffer)GLES31.glMapBufferRange( GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, 4,
547
                                                                GLES31.GL_MAP_READ_BIT);
548
    if( atomicBuf!=null )
549
      {
550
      IntBuffer atomicIntBuf = atomicBuf.order(ByteOrder.nativeOrder()).asIntBuffer();
551
      counter = atomicIntBuf.get(0);
552
      }
553
    else
543 554
      {
544
      GLES31.glGenBuffers(1,mAtomicCounter,0);
545
      GLES31.glBindBufferBase(GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, mAtomicCounter[0]);
546
      GLES31.glBindBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER, mAtomicCounter[0] );
547
      GLES31.glBufferData(GLES31.GL_ATOMIC_COUNTER_BUFFER, 4, null, GLES31.GL_DYNAMIC_DRAW);
548
      GLES31.glBindBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER, 0);
555
      android.util.Log.e("effects", "print: failed to map atomic buffer");
549 556
      }
550 557

  
551
    GLES31.glBindBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER, mAtomicCounter[0] );
558
    GLES31.glUnmapBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER);
552 559

  
560
    return counter;
561
    }
562

  
563
///////////////////////////////////////////////////////////////////////////////////////////////////
564

  
565
  private static void zeroBuffer()
566
    {
553 567
    ByteBuffer atomicBuf = (ByteBuffer)GLES31.glMapBufferRange( GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, 4,
554
                                                                GLES31.GL_MAP_WRITE_BIT|GLES31.GL_MAP_INVALIDATE_BUFFER_BIT);
568
        GLES31.GL_MAP_WRITE_BIT|GLES31.GL_MAP_INVALIDATE_BUFFER_BIT);
555 569
    if( atomicBuf!=null )
556 570
      {
557 571
      IntBuffer atomicIntBuf = atomicBuf.order(ByteOrder.nativeOrder()).asIntBuffer();
558

  
559
      //int counter = atomicIntBuf.get(0);
560
      //android.util.Log.e("counter", "now = "+counter+" w="+surface.mWidth+" h="+surface.mHeight
561
      //                             +" diff="+(counter-surface.mWidth*surface.mHeight));
562 572
      atomicIntBuf.put(0,0);
563 573
      }
564 574
    else
565 575
      {
566
      android.util.Log.e("effects", "failed to map atomic buffer");
576
      android.util.Log.e("effects", "zero: failed to map atomic buffer");
567 577
      }
568 578

  
569 579
    GLES31.glUnmapBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER);
570
    GLES31.glBindBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER, 0);
580
    }
581

  
582
///////////////////////////////////////////////////////////////////////////////////////////////////
583
// reset atomic counter to 0
584

  
585
  static int zeroOutAtomic()
586
    {
587
    int counter = 0;
588

  
589
    if( mAtomicCounter[0]<0 )
590
      {
591
      GLES31.glGenBuffers(Distorted.FBO_QUEUE_SIZE,mAtomicCounter,0);
592

  
593
      for(int i=0; i<Distorted.FBO_QUEUE_SIZE; i++)
594
        {
595
        GLES31.glBindBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER, mAtomicCounter[i]);
596
        GLES31.glBufferData(GLES31.GL_ATOMIC_COUNTER_BUFFER, 4, null, GLES31.GL_DYNAMIC_DRAW);
597
        zeroBuffer();
598
        }
599
      }
600

  
601
    // reading the value of the buffer on every frame would slow down rendering by
602
    // about 3%; doing it only once every 5 frames affects speed by less than 1%.
603
    if( mCurrBuffer==0 )
604
      {
605
      GLES31.glBindBufferBase(GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, mAtomicCounter[mCurrBuffer]);
606
      counter = printPreviousBuffer();
607
      }
608

  
609
    if( ++mCurrBuffer>=Distorted.FBO_QUEUE_SIZE ) mCurrBuffer = 0;
610

  
611
    GLES31.glBindBufferBase(GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, mAtomicCounter[mCurrBuffer]);
612
    zeroBuffer();
613

  
614
    return counter;
571 615
    }
572 616

  
573 617
///////////////////////////////////////////////////////////////////////////////////////////////////
574 618
// Pass1 of the OIT algorithm. Clear per-pixel head-poiners.
575 619

  
576
  static void oitClear(DistortedOutputSurface surface)
620
  static void oitClear(DistortedOutputSurface surface, int counter)
577 621
    {
578 622
    if( mLinkedListSSBO[0]<0 )
579 623
      {
580
      int size = (int)(surface.mWidth*surface.mHeight*(3*mBufferSize+1)*4);
581

  
582 624
      GLES31.glGenBuffers(1,mLinkedListSSBO,0);
625

  
626
      int size = (int)(surface.mWidth*surface.mHeight*(3*mBufferSize+1)*4);
583 627
      GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, mLinkedListSSBO[0]);
584 628
      GLES31.glBufferData(GLES31.GL_SHADER_STORAGE_BUFFER, size, null, GLES31.GL_DYNAMIC_READ|GLES31.GL_DYNAMIC_DRAW);
629
      GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, 0);
630

  
585 631
      GLES31.glBindBufferBase(GLES31.GL_SHADER_STORAGE_BUFFER, 1, mLinkedListSSBO[0]);
632
      }
633

  
634
    // See if we have overflown the SSBO in one of the previous frames.
635
    // If yes, assume we need to make the SSBO larger.
636
    float overflow = counter/(mBufferSize*surface.mWidth*surface.mHeight);
637

  
638
    if( overflow>1.0f )
639
      {
640
      //android.util.Log.e("effects", "previous frame rendered "+counter+
641
      //                   " fragments, but there was only "+(mBufferSize*surface.mWidth*surface.mHeight)+" space");
642

  
643
      mBufferSize *= (int)(overflow+1.0f);
644
      int size = (int)(surface.mWidth*surface.mHeight*(3*mBufferSize+1)*4);
645
      GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, mLinkedListSSBO[0]);
646
      GLES31.glBufferData(GLES31.GL_SHADER_STORAGE_BUFFER, size, null, GLES31.GL_DYNAMIC_READ|GLES31.GL_DYNAMIC_DRAW);
586 647
      GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, 0);
587 648
      }
588 649

  
......
665 726
  static void onPause()
666 727
    {
667 728
    mLinkedListSSBO[0]= -1;
668
    mAtomicCounter[0] = -1;
729

  
730
    for(int i=0; i<Distorted.FBO_QUEUE_SIZE; i++) mAtomicCounter[i] = -1;
669 731
    }
670 732

  
671 733
///////////////////////////////////////////////////////////////////////////////////////////////////
......
675 737
    mNextID =  0;
676 738
    }
677 739

  
740
///////////////////////////////////////////////////////////////////////////////////////////////////
741

  
742
  static void setSSBOSize(float size)
743
    {
744
    mBufferSize = size;
745
    }
746

  
678 747
///////////////////////////////////////////////////////////////////////////////////////////////////
679 748
// PUBLIC API
680 749
///////////////////////////////////////////////////////////////////////////////////////////////////
src/main/java/org/distorted/library/main/DistortedFramebuffer.java
28 28
 * User is able to create offscreen FBOs and both a) render to them b) use their COLOR0 attachment as
29 29
 * an input texture. Attaching Depths and/or Stencils is also possible.
30 30
 */
31
public class DistortedFramebuffer extends DistortedOutputSurface implements DistortedInputSurface
31
public class DistortedFramebuffer extends DistortedOutputSurface
32 32
  {
33 33

  
34 34
///////////////////////////////////////////////////////////////////////////////////////////////////
......
250 250
    super(width,height,NOT_CREATED_YET,1,numcolors,depthStencil,NOT_CREATED_YET,TYPE_USER);
251 251
    }
252 252

  
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254
/**
255
 * Bind the underlying rectangle of pixels as a OpenGL Texture.
256
 *
257
 * @return <code>true</code> if successful.
258
 */
259
  public boolean setAsInput()
260
    {
261
    if( mColorH[0]>0 )
262
      {
263
      GLES31.glActiveTexture(GLES31.GL_TEXTURE0);
264
      GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, mColorH[0]);
265
      return true;
266
      }
267

  
268
    return false;
269
    }
270

  
271 253
///////////////////////////////////////////////////////////////////////////////////////////////////
272 254
/**
273 255
 * Bind the underlying rectangle of pixels as a OpenGL Texture.
src/main/java/org/distorted/library/main/DistortedInputSurface.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2016 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted is free software: you can redistribute it and/or modify                             //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Distorted is distributed in the hope that it will be useful,                                  //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

  
20
package org.distorted.library.main;
21

  
22
///////////////////////////////////////////////////////////////////////////////////////////////////
23
/**
24
 * A Surface that we can set as an Input (take its rectangle of pixels and skin a Mesh with it).
25
 */
26

  
27
// This really ought to be an abstract class instead, but effing Java has no multiple inheritance...
28

  
29
public interface DistortedInputSurface
30
{
31
/**
32
 * Do not document this as public API
33
 * @y.exclude
34
 */
35
  long getID();
36
/**
37
 * Do not document this as public API
38
 * @y.exclude
39
 */
40
  int getWidth();
41
/**
42
 * Do not document this as public API
43
 * @y.exclude
44
 */
45
  int getHeight();
46
/**
47
 * Take the underlying rectangle of pixels and bind this texture to OpenGL.
48
 */
49
  boolean setAsInput();
50
}
src/main/java/org/distorted/library/main/DistortedNode.java
68 68
  private DistortedOutputSurface mSurfaceParent;
69 69
  private MeshObject mMesh;
70 70
  private DistortedEffects mEffects;
71
  private DistortedInputSurface mSurface;
71
  private DistortedSurface mSurface;
72 72
  private DistortedRenderState mState;
73 73
  private NodeData mData;
74 74
  private int mFboW, mFboH, mFboDepthStencil;
......
243 243

  
244 244
  int markStencilAndDepth(long currTime, DistortedOutputSurface surface, EffectQueuePostprocess queue)
245 245
    {
246
    DistortedInputSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
246
    DistortedSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
247 247

  
248 248
    if( input.setAsInput() )
249 249
      {
......
261 261

  
262 262
  int drawNoBlend(long currTime, DistortedOutputSurface surface)
263 263
    {
264
    DistortedInputSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
264
    DistortedSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
265 265

  
266 266
    if( input.setAsInput() )
267 267
      {
......
280 280

  
281 281
  int drawOIT(long currTime, DistortedOutputSurface surface)
282 282
    {
283
    DistortedInputSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
283
    DistortedSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
284 284

  
285 285
    if( input.setAsInput() )
286 286
      {
......
297 297

  
298 298
  int draw(long currTime, DistortedOutputSurface surface)
299 299
    {
300
    DistortedInputSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
300
    DistortedSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
301 301

  
302 302
    if( input.setAsInput() )
303 303
      {
......
392 392
 * @param effects DistortedEffects to put into the new Node.
393 393
 * @param mesh MeshObject to put into the new Node.
394 394
 */
395
  public DistortedNode(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
395
  public DistortedNode(DistortedSurface surface, DistortedEffects effects, MeshObject mesh)
396 396
    {
397 397
    mSurface       = surface;
398 398
    mEffects       = effects;
......
526 526
    mRenderWayOIT = oit;
527 527
    }
528 528

  
529
///////////////////////////////////////////////////////////////////////////////////////////////////
530
  /**
531
   * When rendering this Node, should we use the Order Independent Transparency render more?
532
   * <p>
533
   * There are two modes of rendering: the fast 'normal' way, which however renders transparent
534
   * fragments in different ways depending on which fragments get rendered first, or the slower
535
   * 'oit' way, which renders transparent fragments correctly regardless of their order.
536
   *
537
   * @param oit True if we want to render more slowly, but in a way which accounts for transparency.
538
   * @param initialSize Initial number of transparent fragments we expect, in screenfulls.
539
   *                    I.e '1.0' means 'the scene we are going to render contains about 1 screen
540
   *                    worth of transparent fragments'. Valid values: 0.0 &lt; initialSize &lt; 10.0
541
   *                    Even if you get this wrong, the library will detect that there are more
542
   *                    transparent fragments than it has space for and readjust its internal buffers,
543
   *                    but only after a few frames during which one will probably see missing objects.
544
   */
545
  public void setOrderIndependentTransparency(boolean oit, float initialSize)
546
    {
547
    mRenderWayOIT = oit;
548

  
549
    if( initialSize>0.0f && initialSize<10.0f )
550
      DistortedEffects.setSSBOSize(initialSize);
551
    }
552

  
529 553
///////////////////////////////////////////////////////////////////////////////////////////////////
530 554
/**
531 555
 * Adds a new child to the last position in the list of our Node's children.
......
553 577
 * @param mesh MeshObject to initialize our child Node with.
554 578
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
555 579
 */
556
  public DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
580
  public DistortedNode attach(DistortedSurface surface, DistortedEffects effects, MeshObject mesh)
557 581
    {
558 582
    DistortedNode node = new DistortedNode(surface,effects,mesh);
559 583
    mJobs.add(new Job(ATTACH,node));
......
717 741
 *
718 742
 * @return The DistortedInputSurface contained in the Node.
719 743
 */
720
  public DistortedInputSurface getSurface()
744
  public DistortedSurface getSurface()
721 745
    {
722 746
    return mSurface;
723 747
    }
src/main/java/org/distorted/library/main/DistortedOutputSurface.java
311 311

  
312 312
  private static void oitClear(DistortedOutputSurface buffer)
313 313
    {
314
    DistortedEffects.zeroOutAtomic();
315
    DistortedEffects.oitClear(buffer);
314
    int counter = DistortedEffects.zeroOutAtomic();
315
    DistortedEffects.oitClear(buffer,counter);
316 316
    GLES31.glMemoryBarrier(GLES31.GL_SHADER_STORAGE_BARRIER_BIT|GLES31.GL_ATOMIC_COUNTER_BARRIER_BIT);
317 317
    }
318 318

  
......
881 881
    mRenderWayOIT = oit;
882 882
    }
883 883

  
884
///////////////////////////////////////////////////////////////////////////////////////////////////
885
/**
886
 * When rendering this Node, should we use the Order Independent Transparency render more?
887
 * <p>
888
 * There are two modes of rendering: the fast 'normal' way, which however renders transparent
889
 * fragments in different ways depending on which fragments get rendered first, or the slower
890
 * 'oit' way, which renders transparent fragments correctly regardless of their order.
891
 *
892
 * @param oit True if we want to render more slowly, but in a way which accounts for transparency.
893
 * @param initialSize Initial number of transparent fragments we expect, in screenfuls.
894
 *                    I.e '1.0' means 'the scene we are going to render contains about 1 screen
895
 *                    worth of transparent fragments'. Valid values: 0.0 &lt; initialSize &lt; 10.0
896
 *                    Even if you get this wrong, the library will detect that there are more
897
 *                    transparent fragments than it has space for and readjust its internal buffers,
898
 *                    but only after a few frames during which one will probably see missing objects.
899
 */
900
public void setOrderIndependentTransparency(boolean oit, float initialSize)
901
  {
902
  mRenderWayOIT = oit;
903

  
904
  if( initialSize>0.0f && initialSize<10.0f )
905
    DistortedEffects.setSSBOSize(initialSize);
906
  }
907

  
884 908
///////////////////////////////////////////////////////////////////////////////////////////////////
885 909
/**
886 910
 * Adds a new child to the last position in the list of our Surface's children.
......
908 932
 * @param mesh MeshObject to initialize our child Node with.
909 933
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
910 934
 */
911
  public DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
935
  public DistortedNode attach(DistortedSurface surface, DistortedEffects effects, MeshObject mesh)
912 936
    {
913 937
    DistortedNode node = new DistortedNode(surface,effects,mesh);
914 938
    mJobs.add(new Job(ATTACH,node));
src/main/java/org/distorted/library/main/DistortedSurface.java
19 19

  
20 20
package org.distorted.library.main;
21 21

  
22
///////////////////////////////////////////////////////////////////////////////////////////////////
22
import android.opengl.GLES31;
23 23

  
24
abstract class DistortedSurface extends DistortedObject
24
///////////////////////////////////////////////////////////////////////////////////////////////////
25
/**
26
 * This is not really part of the public API.
27
 *
28
 * @y.exclude
29
 */
30
public abstract class DistortedSurface extends DistortedObject
25 31
{
26 32
  int mColorCreated;
27 33
  int mNumColors;
......
96 102
    {
97 103
    return mesh==null ? 0 : (int)(mWidth*mesh.zFactor);
98 104
    }
105

  
106
///////////////////////////////////////////////////////////////////////////////////////////////////
107
/**
108
 * Bind the underlying rectangle of pixels as a OpenGL Texture.
109
 *
110
 * @return <code>true</code> if successful.
111
 */
112
  public boolean setAsInput()
113
    {
114
    if( mColorH[0]>0 )
115
      {
116
      GLES31.glActiveTexture(GLES31.GL_TEXTURE0);
117
      GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, mColorH[0]);
118
      return true;
119
      }
120

  
121
    return false;
122
    }
99 123
}
src/main/java/org/distorted/library/main/DistortedTexture.java
32 32
 * <p>
33 33
 * Create a Texture of arbitrary size and feed some pixels to it via the setTexture() method.
34 34
 */
35
public class DistortedTexture extends DistortedSurface implements DistortedInputSurface
35
public class DistortedTexture extends DistortedSurface
36 36
  {
37 37
  private Bitmap mBmp;
38 38

  

Also available in: Unified diff