@@ -81,6 +81,62 @@ private static int getLimitCount(Buffer buffer, int elementSize) {
8181 return buffer .limit () / elementSize ;
8282 }
8383
84+ private static int getRemainingBytes (ByteBuffer buffer ) {
85+ checkLimit (buffer );
86+ return buffer .remaining ();
87+ }
88+
89+ private static int getRemainingBytes (IntBuffer buffer ) {
90+ checkLimit (buffer );
91+ return checkedLongToInt ((long ) buffer .remaining () * 4L , "buffer size" );
92+ }
93+
94+ private static int checkedLongToInt (long value , String name ) {
95+ if (value < 0 || value > Integer .MAX_VALUE ) {
96+ throw new RendererException (name + " exceeds the range supported by Android GLES bindings: " + value );
97+ }
98+ return (int ) value ;
99+ }
100+
101+ private static long getSyncHandle (Object sync ) {
102+ if (!(sync instanceof Long )) {
103+ throw new IllegalArgumentException ("Expected a sync object returned by glFenceSync" );
104+ }
105+ return (Long ) sync ;
106+ }
107+
108+ private static int getBooleanValueCount (int pname ) {
109+ if (pname == GLES20 .GL_COLOR_WRITEMASK ) {
110+ return 4 ;
111+ }
112+ return 1 ;
113+ }
114+
115+ private static String joinShaderSource (String [] strings , IntBuffer lengths ) {
116+ StringBuilder builder = new StringBuilder ();
117+ int lengthPosition = lengths == null ? 0 : lengths .position ();
118+
119+ for (int i = 0 ; i < strings .length ; i ++) {
120+ String source = strings [i ];
121+ if (lengths != null ) {
122+ int length = lengths .get (lengthPosition + i );
123+ if (length >= 0 && length < source .length ()) {
124+ builder .append (source , 0 , length );
125+ continue ;
126+ }
127+ }
128+ builder .append (source );
129+ }
130+
131+ return builder .toString ();
132+ }
133+
134+ private static void unmapBufferAfterRead (int target ) {
135+ if (!GLES30 .glUnmapBuffer (target )) {
136+ throw new RendererException ("Mapped buffer data became corrupted while reading" );
137+ }
138+ }
139+
84140 private static void checkLimit (Buffer buffer ) {
85141 if (buffer == null ) {
86142 return ;
@@ -148,32 +204,57 @@ public void glBufferData(int target, ByteBuffer data, int usage) {
148204
149205 @ Override
150206 public void glBufferData (int target , long dataSize , int usage ) {
151- GLES20 .glBufferData (target , ( int ) dataSize , null , usage );
207+ GLES20 .glBufferData (target , checkedLongToInt ( dataSize , "data size" ) , null , usage );
152208 }
153209
154210 @ Override
155211 public void glBufferSubData (int target , long offset , FloatBuffer data ) {
156- GLES20 .glBufferSubData (target , ( int ) offset , getLimitBytes (data ), data );
212+ GLES20 .glBufferSubData (target , checkedLongToInt ( offset , " offset" ) , getLimitBytes (data ), data );
157213 }
158214
159215 @ Override
160216 public void glBufferSubData (int target , long offset , ShortBuffer data ) {
161- GLES20 .glBufferSubData (target , ( int ) offset , getLimitBytes (data ), data );
217+ GLES20 .glBufferSubData (target , checkedLongToInt ( offset , " offset" ) , getLimitBytes (data ), data );
162218 }
163219
164220 @ Override
165221 public void glBufferSubData (int target , long offset , ByteBuffer data ) {
166- GLES20 .glBufferSubData (target , ( int ) offset , getLimitBytes (data ), data );
222+ GLES20 .glBufferSubData (target , checkedLongToInt ( offset , " offset" ) , getLimitBytes (data ), data );
167223 }
168224
169225 @ Override
170226 public void glGetBufferSubData (int target , long offset , ByteBuffer data ) {
171- throw new UnsupportedOperationException ("OpenGL ES 2 does not support glGetBufferSubData" );
227+ int byteCount = getRemainingBytes (data );
228+ Buffer mapped = GLES30 .glMapBufferRange (target , checkedLongToInt (offset , "offset" ), byteCount , GLES30 .GL_MAP_READ_BIT );
229+ if (!(mapped instanceof ByteBuffer )) {
230+ throw new RendererException ("Unable to map buffer for reading" );
231+ }
232+
233+ try {
234+ ByteBuffer source = (ByteBuffer ) mapped ;
235+ source .limit (byteCount );
236+ data .duplicate ().put (source );
237+ } finally {
238+ unmapBufferAfterRead (target );
239+ }
172240 }
173241
174242 @ Override
175243 public void glGetBufferSubData (int target , long offset , IntBuffer data ) {
176- throw new UnsupportedOperationException ("OpenGL ES 2 does not support glGetBufferSubData" );
244+ int byteCount = getRemainingBytes (data );
245+ Buffer mapped = GLES30 .glMapBufferRange (target , checkedLongToInt (offset , "offset" ), byteCount , GLES30 .GL_MAP_READ_BIT );
246+ if (!(mapped instanceof ByteBuffer )) {
247+ throw new RendererException ("Unable to map buffer for reading" );
248+ }
249+
250+ try {
251+ ByteBuffer source = (ByteBuffer ) mapped ;
252+ source .limit (byteCount );
253+ source .order (data .order ());
254+ data .duplicate ().put (source .asIntBuffer ());
255+ } finally {
256+ unmapBufferAfterRead (target );
257+ }
177258 }
178259
179260 @ Override
@@ -280,7 +361,7 @@ public void glDrawArrays(int mode, int first, int count) {
280361
281362 @ Override
282363 public void glDrawRangeElements (int mode , int start , int end , int count , int type , long indices ) {
283- GLES20 . glDrawElements (mode , count , type , ( int ) indices );
364+ GLES30 . glDrawRangeElements (mode , start , end , count , type , checkedLongToInt ( indices , "indices offset" ) );
284365 }
285366
286367 @ Override
@@ -325,8 +406,18 @@ public int glGetAttribLocation(int program, String name) {
325406
326407 @ Override
327408 public void glGetBoolean (int pname , ByteBuffer params ) {
328- // GLES20.glGetBoolean(pname, params);
329- throw new UnsupportedOperationException ("Today is not a good day for this" );
409+ checkLimit (params );
410+ int count = getBooleanValueCount (pname );
411+ if (params .remaining () < count ) {
412+ throw new RendererException ("Insufficient buffer space for boolean query result" );
413+ }
414+ boolean [] values = new boolean [count ];
415+ GLES20 .glGetBooleanv (pname , values , 0 );
416+
417+ ByteBuffer destination = params .duplicate ();
418+ for (boolean value : values ) {
419+ destination .put ((byte ) (value ? GLES20 .GL_TRUE : GLES20 .GL_FALSE ));
420+ }
330421 }
331422
332423 @ Override
@@ -427,10 +518,7 @@ public void glScissor(int x, int y, int width, int height) {
427518
428519 @ Override
429520 public void glShaderSource (int shader , String [] string , IntBuffer length ) {
430- if (string .length != 1 ) {
431- throw new UnsupportedOperationException ("Today is not a good day" );
432- }
433- GLES20 .glShaderSource (shader , string [0 ]);
521+ GLES20 .glShaderSource (shader , joinShaderSource (string , length ));
434522 }
435523
436524 @ Override
@@ -545,7 +633,7 @@ public void glUseProgram(int program) {
545633
546634 @ Override
547635 public void glVertexAttribPointer (int index , int size , int type , boolean normalized , int stride , long pointer ) {
548- GLES20 .glVertexAttribPointer (index , size , type , normalized , stride , ( int ) pointer );
636+ GLES20 .glVertexAttribPointer (index , size , type , normalized , stride , checkedLongToInt ( pointer , "pointer offset" ) );
549637 }
550638
551639 @ Override
@@ -565,7 +653,7 @@ public void glBufferData(int target, IntBuffer data, int usage) {
565653
566654 @ Override
567655 public void glBufferSubData (int target , long offset , IntBuffer data ) {
568- GLES20 .glBufferSubData (target , ( int ) offset , getLimitBytes (data ), data );
656+ GLES20 .glBufferSubData (target , checkedLongToInt ( offset , "offset" ) , getLimitBytes (data ), data );
569657 }
570658
571659 @ Override
@@ -580,12 +668,12 @@ public void glDrawBuffers(IntBuffer bufs) {
580668
581669 @ Override
582670 public void glDrawElementsInstancedARB (int mode , int indicesCount , int type , long indicesBufferOffset , int primcount ) {
583- GLES30 .glDrawElementsInstanced (mode , indicesCount , type , ( int ) indicesBufferOffset , primcount );
671+ GLES30 .glDrawElementsInstanced (mode , indicesCount , type , checkedLongToInt ( indicesBufferOffset , "indices offset" ) , primcount );
584672 }
585673
586674 @ Override
587675 public void glGetMultisample (int pname , int index , FloatBuffer val ) {
588- GLES31 . glGetMultisamplefv ( pname , index , val );
676+ throw new UnsupportedOperationException ( "Multisample textures require OpenGL ES 3.1" );
589677 }
590678
591679 @ Override
@@ -595,7 +683,7 @@ public void glRenderbufferStorageMultisampleEXT(int target, int samples, int int
595683
596684 @ Override
597685 public void glTexImage2DMultisample (int target , int samples , int internalformat , int width , int height , boolean fixedSampleLocations ) {
598- GLES31 . glTexStorage2DMultisample ( target , samples , internalformat , width , height , fixedSampleLocations );
686+ throw new UnsupportedOperationException ( "Multisample textures require OpenGL ES 3.1" );
599687 }
600688
601689 @ Override
@@ -620,15 +708,12 @@ public void glUniformBlockBinding(int program, int uniformBlockIndex, int unifor
620708
621709 @ Override
622710 public int glGetProgramResourceIndex (int program , int programInterface , String name ) {
623- return GLES31 . glGetProgramResourceIndex ( program , programInterface , name );
711+ throw new UnsupportedOperationException ( "Shader storage buffer objects require OpenGL ES 3.1" );
624712 }
625713
626714 @ Override
627715 public void glShaderStorageBlockBinding (int program , int storageBlockIndex , int storageBlockBinding ) {
628- /*
629- * GLES 3.1 exposes shader storage block binding through GLSL layout(binding = N).
630- * Android's GLES31 Java bindings do not expose glShaderStorageBlockBinding.
631- */
716+ throw new UnsupportedOperationException ("Shader storage buffer objects require OpenGL ES 3.1" );
632717 }
633718
634719 @ Override
@@ -692,23 +777,22 @@ public void glRenderbufferStorageEXT(int param1, int param2, int param3, int par
692777
693778 @ Override
694779 public void glReadPixels (int x , int y , int width , int height , int format , int type , long offset ) {
695- // TODO: no offset???
696- GLES20 .glReadPixels (x , y , width , height , format , type , null );
780+ GLES30 .glReadPixels (x , y , width , height , format , type , checkedLongToInt (offset , "offset" ));
697781 }
698782
699783 @ Override
700784 public int glClientWaitSync (Object sync , int flags , long timeout ) {
701- throw new UnsupportedOperationException ( "OpenGL ES 2 does not support sync fences" );
785+ return GLES30 . glClientWaitSync ( getSyncHandle ( sync ), flags , timeout );
702786 }
703787
704788 @ Override
705789 public void glDeleteSync (Object sync ) {
706- throw new UnsupportedOperationException ( "OpenGL ES 2 does not support sync fences" );
790+ GLES30 . glDeleteSync ( getSyncHandle ( sync ) );
707791 }
708792
709793 @ Override
710794 public Object glFenceSync (int condition , int flags ) {
711- throw new UnsupportedOperationException ( "OpenGL ES 2 does not support sync fences" );
795+ return GLES30 . glFenceSync ( condition , flags );
712796 }
713797
714798 @ Override
0 commit comments