最近工作中的问题笔记

调试GLES, 发现某平台有各种问题,

1.用三星手机测试和iphone测试, 在drawcall以后不调用glDisableVertexAttribArray, 没有问题. 但在某平台下,后续的draw call会花屏.

实际问题主要是因为shader会优化掉某些不用的attrib, 这种情况下, 要根据shader内的信息, disable掉不用的attrib.

这个问题还可能好说,虽然还没找到GLES spec上怎么说, 但是配对使用是最保险的, 不配对可能是undefined behavior, 已知GL下确实有可能会有问题.

2.最奇葩的问题是该平台的shader, GL/ES的spec说生成program以后, 可以detach/delete shader, 但是在某平台上, 如果删除shader竟然也会渲染出错.

由于引擎的代码过于复杂, 为了排除其他因素, 专门用NativeActivity简化才最终确定这个问题.下面代码画了三个cube, 如果使用detach sader/delete shader, 只显示第一个cube (line130).

  1 /*
  2  * Copyright (C) 2010 The Android Open Source Project
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  *
 16  */
 17 
 18 //BEGIN_INCLUDE(all)
 19 #include <jni.h>
 20 #include <errno.h>
 21 
 22 #include <EGL/egl.h>
 23 #include <GLES/gl.h>
 24 #include <GLES2/gl2.h>
 25 
 26 #include <android/sensor.h>
 27 #include <android/log.h>
 28 #include <android_native_app_glue.h>
 29 
 30 #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
 31 #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))
 32 
 33 /**
 34  * Our saved state data.
 35  */
 36 struct saved_state {
 37     float angle;
 38     int32_t x;
 39     int32_t y;
 40 };
 41 
 42 /**
 43  * Shared state for our app.
 44  */
 45 struct engine {
 46     struct android_app* app;
 47 
 48     ASensorManager* sensorManager;
 49     const ASensor* accelerometerSensor;
 50     ASensorEventQueue* sensorEventQueue;
 51 
 52     int animating;
 53     EGLDisplay display;
 54     EGLSurface surface;
 55     EGLContext context;
 56     int32_t width;
 57     int32_t height;
 58     GLuint program[3];
 59     struct saved_state state;
 60 };
 61 
 62 GLuint    Position = 1;
 63 GLuint    UV = 2;
 64 
 65 //////////////////////////////////////////////////////////////////////////
 66 GLuint LoadShader(GLenum shaderType, const char* pSource) {
 67 
 68     GLuint shader = glCreateShader(shaderType);
 69 
 70     if (shader != 0) {
 71         glShaderSource(shader, 1, &pSource, NULL);
 72         glCompileShader(shader);
 73         GLint compiled = 0;
 74         glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
 75         if (compiled == 0) {
 76             GLint infoLen = 0;
 77             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
 78             if (infoLen != 0) {
 79                 char* buf = (char*)alloca(infoLen);
 80                 if (buf != NULL) {
 81                     glGetShaderInfoLog(shader, infoLen, NULL, buf);
 82                     LOGW( "Could not compile shader %d:
%s
", shaderType,  buf );
 83                 }
 84                 glDeleteShader(shader);
 85                 shader = 0;
 86             }
 87         }
 88     }
 89     return shader;
 90 }
 91 
 92 //////////////////////////////////////////////////////////////////////////
 93 GLuint CreateProgram(const char* pVertexSource, const char* pFragmentSource) {
 94 
 95     GLuint vertexShader = LoadShader(GL_VERTEX_SHADER, pVertexSource);
 96     if (vertexShader == 0) {
 97         return 0;
 98     }
 99 
100     GLuint pixelShader = LoadShader(GL_FRAGMENT_SHADER, pFragmentSource);
101     if (pixelShader == 0) {
102         return 0;
103     }
104 
105     GLuint program = glCreateProgram();
106     if (program != 0) {
107         glAttachShader(program, vertexShader);
108         glAttachShader(program, pixelShader);
109 
110         glBindAttribLocation(program, Position, "vsin_POSITION0");
111         glBindAttribLocation(program, UV, "vsin_TEXCOORD0");
112 
113         glLinkProgram(program);
114         GLint linkStatus = GL_FALSE;
115         glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
116         if (linkStatus != GL_TRUE) {
117             GLint bufLength = 0;
118             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
119             if (bufLength != 0) {
120                 char* buf = (char*)alloca(bufLength);
121                 if (buf != NULL) {
122                     glGetProgramInfoLog(program, bufLength, NULL, buf);
123                     LOGW( "Could not link program:
%s
", buf );
124                 }
125             }
126             glDeleteProgram(program);
127             program = 0;
128         }
129 
130         //uncomment this will get weird problems
131         glDetachShader(program, vertexShader);
132         glDetachShader(program, pixelShader);
133         glDeleteShader(vertexShader);
134         glDeleteShader(pixelShader);
135     }
136     return program;
137 }
138 
139 
140 /**
141  * Initialize an EGL context for the current display.
142  */
143 static int engine_init_display(struct engine* engine) {
144     // initialize OpenGL ES and EGL
145 
146     /*
147      * Here specify the attributes of the desired configuration.
148      * Below, we select an EGLConfig with at least 8 bits per color
149      * component compatible with on-screen windows
150      */
151     const EGLint attribs[] = {
152             EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
153             EGL_BLUE_SIZE, 8,
154             EGL_GREEN_SIZE, 8,
155             EGL_RED_SIZE, 8,
156             EGL_DEPTH_SIZE, 24,
157             EGL_STENCIL_SIZE, 8,
158             EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,    //GLES 2.0
159             EGL_CONFORMANT, EGL_OPENGL_ES2_BIT,
160             EGL_NONE
161     };
162     EGLint w, h, dummy, format;
163     EGLint numConfigs;
164     EGLConfig config;
165     EGLSurface surface;
166     EGLContext context;
167 
168     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
169 
170     eglInitialize(display, 0, 0);
171 
172     /* Here, the application chooses the configuration it desires. In this
173      * sample, we have a very simplified selection process, where we pick
174      * the first EGLConfig that matches our criteria */
175     eglChooseConfig(display, attribs, &config, 1, &numConfigs);
176 
177     /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
178      * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
179      * As soon as we picked a EGLConfig, we can safely reconfigure the
180      * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
181     eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
182 
183     ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);
184 
185     surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
186 
187     const EGLint ContextAttribs[] = {
188         EGL_CONTEXT_CLIENT_VERSION, 2,
189         EGL_NONE,
190     };
191     context = eglCreateContext(display, config, EGL_NO_CONTEXT, ContextAttribs);
192 
193     if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
194         LOGW("Unable to eglMakeCurrent");
195         return -1;
196     }
197 
198     eglQuerySurface(display, surface, EGL_WIDTH, &w);
199     eglQuerySurface(display, surface, EGL_HEIGHT, &h);
200 
201     engine->display = display;
202     engine->context = context;
203     engine->surface = surface;
204     engine->width = w;
205     engine->height = h;
206     engine->state.angle = 0;
207 
208     // Initialize GL state.
209     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
210     glDisable(GL_CULL_FACE);
211     //glShadeModel(GL_SMOOTH);
212     //glDisable(GL_DEPTH_TEST);
213 
214     //create shader
215     const char* vertexShaders[3] = {
216 "#version 100 

217 //#extension GL_OES_standard_derivatives : enable 

218 //uniform vec4 WORLD_POS; 

219 uniform vec4 _WORLD2PROJECTED_ROW3; 

220 uniform vec4 _WORLD2PROJECTED_ROW2; 

221 uniform vec4 _WORLD2PROJECTED_ROW1; 

222 uniform vec4 _WORLD2PROJECTED_ROW0; 

223 attribute vec3 vsin_POSITION0; 

224 attribute vec4 vsin_TEXCOORD0; 

225 varying mediump vec4 vsout_TEXCOORD0; 

226 varying mediump vec4 vsout_COLOR0; 

227 void main () 

228 { 

229     vec4 r_6 = vec4(vsin_POSITION0,1);// + WORLD_POS; 

230     mediump vec4 r_8;  

231     r_8.x = dot (r_6, _WORLD2PROJECTED_ROW0); 

232     r_8.y = dot (r_6, _WORLD2PROJECTED_ROW1); 

233     r_8.z = dot (r_6, _WORLD2PROJECTED_ROW2); 

234     r_8.w = dot (r_6, _WORLD2PROJECTED_ROW3); 

235     gl_Position = r_8; 

236     vsout_TEXCOORD0 = vsin_TEXCOORD0; 

237     vsout_COLOR0 = vec4( normalize(vsin_POSITION0-vec3(5,5,5) ),1); 

238 }",
239 
240 "#version 100 

241 //#extension GL_OES_standard_derivatives : enable 

242 //uniform vec4 WORLD_POS; 

243 uniform vec4 _WORLD2PROJECTED_ROW3; 

244 uniform vec4 _WORLD2PROJECTED_ROW2; 

245 uniform vec4 _WORLD2PROJECTED_ROW1; 

246 uniform vec4 _WORLD2PROJECTED_ROW0; 

247 attribute vec3 vsin_POSITION0; 

248 attribute vec4 vsin_TEXCOORD0; 

249 varying mediump vec4 vsout_TEXCOORD0; 

250 varying mediump vec4 vsout_COLOR0; 

251 void main () 

252 { 

253     vec4 r_6 = vec4(vsin_POSITION0,1) + vec4(20,0,0,0);// + WORLD_POS; 

254     mediump vec4 r_8;  

255     r_8.x = dot (r_6, _WORLD2PROJECTED_ROW0); 

256     r_8.y = dot (r_6, _WORLD2PROJECTED_ROW1); 

257     r_8.z = dot (r_6, _WORLD2PROJECTED_ROW2); 

258     r_8.w = dot (r_6, _WORLD2PROJECTED_ROW3); 

259     gl_Position = r_8; 

260     vsout_TEXCOORD0 = vsin_TEXCOORD0; 

261     vsout_COLOR0 = vec4( vec3(1,1,1) - normalize(vsin_POSITION0-vec3(5,5,5) ),1); 

262 }",
263 
264 "#version 100 

265 //#extension GL_OES_standard_derivatives : enable 

266 //uniform vec4 WORLD_POS; 

267 uniform vec4 _WORLD2PROJECTED_ROW3; 

268 uniform vec4 _WORLD2PROJECTED_ROW2; 

269 uniform vec4 _WORLD2PROJECTED_ROW1; 

270 uniform vec4 _WORLD2PROJECTED_ROW0; 

271 attribute vec3 vsin_POSITION0; 

272 attribute vec4 vsin_TEXCOORD0; 

273 varying mediump vec4 vsout_TEXCOORD0; 

274 varying mediump vec4 vsout_COLOR0; 

275 void main () 

276 { 

277     vec4 r_6 = vec4(vsin_POSITION0,1) + vec4(-20,0,0,0);// + WORLD_POS; 

278     mediump vec4 r_8;  

279     r_8.x = dot (r_6, _WORLD2PROJECTED_ROW0); 

280     r_8.y = dot (r_6, _WORLD2PROJECTED_ROW1); 

281     r_8.z = dot (r_6, _WORLD2PROJECTED_ROW2); 

282     r_8.w = dot (r_6, _WORLD2PROJECTED_ROW3); 

283     gl_Position = r_8; 

284     vsout_TEXCOORD0 = vsin_TEXCOORD0; 

285     vsout_COLOR0 = vec4(1,1,1,1); 

286 }",    };
287 
288     const char* fragmentShader[3] = {
289 
290 "#version 100 

291 precision mediump float; 

292 #extension GL_OES_standard_derivatives : enable 

293 //uniform mediump sampler2D AlbedoSampler; 

294 varying mediump  vec4 vsout_TEXCOORD0; 

295 varying mediump  vec4 vsout_COLOR0; 

296 void main () 

297 { 

298     //gl_FragColor = texture2D (AlbedoSampler, vsout_TEXCOORD0.xy) + vsout_COLOR0; 

299     //gl_FragColor = vsout_COLOR0; 

300     gl_FragColor = vsout_COLOR0; 

301 }",
302 
303 
304 "#version 100 

305 precision mediump float; 

306 #extension GL_OES_standard_derivatives : enable 

307 //uniform mediump sampler2D AlbedoSampler; 

308 varying mediump  vec4 vsout_TEXCOORD0; 

309 varying mediump  vec4 vsout_COLOR0; 

310 void main () 

311 { 

312     //gl_FragColor = texture2D (AlbedoSampler, vsout_TEXCOORD0.xy); 

313     //gl_FragColor = texture2D (AlbedoSampler, vsout_TEXCOORD0.xy) + vsout_COLOR0; 

314     gl_FragColor = vsout_COLOR0; 

315 }",
316 
317 
318 "#version 100 

319 precision mediump float; 

320 #extension GL_OES_standard_derivatives : enable 

321 //uniform mediump sampler2D AlbedoSampler; 

322 varying mediump  vec4 vsout_TEXCOORD0; 

323 varying mediump  vec4 vsout_COLOR0; 

324 void main () 

325 { 

326     //gl_FragColor = texture2D (AlbedoSampler, vsout_TEXCOORD0.xy); 

327     //gl_FragColor = texture2D (AlbedoSampler, vsout_TEXCOORD0.xy) + vsout_COLOR0; 

328     gl_FragColor = vsout_COLOR0; 

329 }",
330 
331     };
332 
333     engine->program[0] = CreateProgram(vertexShaders[0], fragmentShader[0]);
334     engine->program[1] = CreateProgram(vertexShaders[1], fragmentShader[1]);
335     engine->program[2] = CreateProgram(vertexShaders[2], fragmentShader[2]);
336 
337     return 0;
338 }
339 
340 /**
341  * Just the current frame in the display.
342  */
343 static void engine_draw_frame(struct engine* engine) {
344     if (engine->display == NULL) {
345         // No display.
346         return;
347     }
348 
349     // Just fill the screen with a color.
350     //glClearColor(((float)engine->state.x)/engine->width, engine->state.angle,
351     //        ((float)engine->state.y)/engine->height, 1);
352 
353     glClearColor( 0.5, 0.5, 0.5, 1);
354     glClearDepthf(1.0f);
355     glClear(GL_COLOR_BUFFER_BIT);
356     
357 
358 
359 #define Scale 10.0f
360 
361     static const GLfloat CubeVertices[36][3] = { 
362         Scale, Scale,   Scale, 
363         Scale, Scale,   0,
364         Scale, 0,       0,
365 
366         Scale, Scale,   Scale,
367         Scale, 0,       0,
368         Scale, 0,       Scale,
369 
370         0,     0,       0,
371         Scale, 0,       0,
372         Scale, Scale,   0,
373 
374         0,     0,       0,
375         Scale, Scale,   0,
376         0,     Scale,   0,
377 
378         0,     Scale,   0,
379         Scale, Scale,   0,
380         Scale, Scale,   Scale,
381 
382         0,     Scale,   0,
383         Scale, Scale,   Scale,
384         0,     Scale,   Scale,
385 
386         0,     Scale,   0,
387         0,     0,       Scale,
388         0,     0,       0,
389 
390         0,     Scale,   0,
391         0,     Scale,   Scale,
392         0,     0,       Scale,
393 
394         0,     0,       Scale,
395         0,     0,       0,
396         Scale, 0,       0,
397 
398         0,     0,       Scale,
399         Scale, 0,       0,
400         Scale, 0,       Scale,
401 
402         0,     Scale,   Scale,
403         Scale, 0,       Scale,
404         0,     0,       Scale,
405 
406         0,     Scale,   Scale,
407         Scale, Scale,   Scale,
408         Scale, 0,       Scale,
409     };
410 
411     static const GLfloat CubeUV[36][2] = { 
412         0, 0, 
413         0, 1, 
414         1, 1, 
415                       
416         0, 0, 
417         1, 1, 
418         1, 0, 
419                       
420         1, 0, 
421         1, 1, 
422         0, 1, 
423                       
424         1, 0, 
425         0, 1, 
426         0, 0, 
427                       
428         0, 0, 
429         0, 1, 
430         1, 1, 
431                       
432         0, 0, 
433         1, 1, 
434         1, 0, 
435                       
436         0, 0, 
437         1, 1, 
438         1, 0,
439     };
440 
441     //for simplification, this view-projection matrix is copied from engine using  matrix utility
442     GLfloat viewporj[4][4] = 
443     {
444         1.73217857,0,-3.09281524e-011,0,
445         -3.49910968e-011, 1.95973194, -1.95973027, 0,
446         -1.26294461e-011, -0.707330883, -0.707331479, 52.8758965,
447         -1.26254051e-011, -0.707104564, -0.70710516, 84.8589783
448     };
449 
450     int i = 0;
451     for(i = 0; i < 3; ++i)
452     {
453         glUseProgram(engine->program[i]);
454         glUniform4fv( glGetUniformLocation(engine->program[i], "_WORLD2PROJECTED_ROW0"), 1, viewporj[0]);
455         glUniform4fv( glGetUniformLocation(engine->program[i], "_WORLD2PROJECTED_ROW1"), 1, viewporj[1]);
456         glUniform4fv( glGetUniformLocation(engine->program[i], "_WORLD2PROJECTED_ROW2"), 1, viewporj[2]);
457         glUniform4fv( glGetUniformLocation(engine->program[i], "_WORLD2PROJECTED_ROW3"), 1, viewporj[3]);
458         glEnableVertexAttribArray( Position );
459         glVertexAttribPointer(Position, 3, GL_FLOAT, GL_FALSE, 0, CubeVertices);
460         //setup vertex UV buffer
461         glEnableVertexAttribArray(UV);
462         glVertexAttribPointer(UV, 2, GL_FLOAT, GL_FALSE, 0, CubeUV);
463         //draw call & swap
464         glDrawArrays(GL_TRIANGLES, 0, 36);
465 
466         glDisableVertexAttribArray(Position);
467         glDisableVertexAttribArray(UV);
468     }
469 
470 
471     eglSwapBuffers(engine->display, engine->surface);
472 }
473 
474 /**
475  * Tear down the EGL context currently associated with the display.
476  */
477 static void engine_term_display(struct engine* engine) {
478     if (engine->display != EGL_NO_DISPLAY) {
479         eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
480         if (engine->context != EGL_NO_CONTEXT) {
481             eglDestroyContext(engine->display, engine->context);
482         }
483         if (engine->surface != EGL_NO_SURFACE) {
484             eglDestroySurface(engine->display, engine->surface);
485         }
486         eglTerminate(engine->display);
487     }
488     engine->animating = 0;
489     engine->display = EGL_NO_DISPLAY;
490     engine->context = EGL_NO_CONTEXT;
491     engine->surface = EGL_NO_SURFACE;
492 }
493 
494 /**
495  * Process the next input event.
496  */
497 static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) {
498     struct engine* engine = (struct engine*)app->userData;
499     if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
500         engine->animating = 1;
501         engine->state.x = AMotionEvent_getX(event, 0);
502         engine->state.y = AMotionEvent_getY(event, 0);
503         return 1;
504     }
505     return 0;
506 }
507 
508 /**
509  * Process the next main command.
510  */
511 static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
512     struct engine* engine = (struct engine*)app->userData;
513     switch (cmd) {
514         case APP_CMD_SAVE_STATE:
515             // The system has asked us to save our current state.  Do so.
516             engine->app->savedState = malloc(sizeof(struct saved_state));
517             *((struct saved_state*)engine->app->savedState) = engine->state;
518             engine->app->savedStateSize = sizeof(struct saved_state);
519             break;
520         case APP_CMD_INIT_WINDOW:
521             // The window is being shown, get it ready.
522             if (engine->app->window != NULL) {
523                 engine_init_display(engine);
524                 engine_draw_frame(engine);
525             }
526             break;
527         case APP_CMD_TERM_WINDOW:
528             // The window is being hidden or closed, clean it up.
529             engine_term_display(engine);
530             break;
531         case APP_CMD_GAINED_FOCUS:
532             // When our app gains focus, we start monitoring the accelerometer.
533             if (engine->accelerometerSensor != NULL) {
534                 ASensorEventQueue_enableSensor(engine->sensorEventQueue,
535                         engine->accelerometerSensor);
536                 // We'd like to get 60 events per second (in us).
537                 ASensorEventQueue_setEventRate(engine->sensorEventQueue,
538                         engine->accelerometerSensor, (1000L/60)*1000);
539             }
540             break;
541         case APP_CMD_LOST_FOCUS:
542             // When our app loses focus, we stop monitoring the accelerometer.
543             // This is to avoid consuming battery while not being used.
544             if (engine->accelerometerSensor != NULL) {
545                 ASensorEventQueue_disableSensor(engine->sensorEventQueue,
546                         engine->accelerometerSensor);
547             }
548             // Also stop animating.
549             engine->animating = 0;
550             engine_draw_frame(engine);
551             break;
552     }
553 }
554 
555 /**
556  * This is the main entry point of a native application that is using
557  * android_native_app_glue.  It runs in its own thread, with its own
558  * event loop for receiving input events and doing other things.
559  */
560 void android_main(struct android_app* state) {
561     struct engine engine;
562 
563     // Make sure glue isn't stripped.
564     app_dummy();
565 
566     memset(&engine, 0, sizeof(engine));
567     state->userData = &engine;
568     state->onAppCmd = engine_handle_cmd;
569     state->onInputEvent = engine_handle_input;
570     engine.app = state;
571 
572     // Prepare to monitor accelerometer
573     engine.sensorManager = ASensorManager_getInstance();
574     engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
575             ASENSOR_TYPE_ACCELEROMETER);
576     engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager,
577             state->looper, LOOPER_ID_USER, NULL, NULL);
578 
579     if (state->savedState != NULL) {
580         // We are starting with a previous saved state; restore from it.
581         engine.state = *(struct saved_state*)state->savedState;
582     }
583 
584     // loop waiting for stuff to do.
585 
586     while (1) {
587         // Read all pending events.
588         int ident;
589         int events;
590         struct android_poll_source* source;
591 
592         // If not animating, we will block forever waiting for events.
593         // If animating, we loop until all events are read, then continue
594         // to draw the next frame of animation.
595         while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL, &events,
596                 (void**)&source)) >= 0) {
597 
598             // Process this event.
599             if (source != NULL) {
600                 source->process(state, source);
601             }
602 
603             // If a sensor has data, process it now.
604             if (ident == LOOPER_ID_USER) {
605                 if (engine.accelerometerSensor != NULL) {
606                     ASensorEvent event;
607                     while (ASensorEventQueue_getEvents(engine.sensorEventQueue,
608                             &event, 1) > 0) {
609                         //LOGI("accelerometer: x=%f y=%f z=%f",
610                         //       event.acceleration.x, event.acceleration.y,
611                         //        event.acceleration.z);
612                     }
613                 }
614             }
615 
616             // Check if we are exiting.
617             if (state->destroyRequested != 0) {
618                 engine_term_display(&engine);
619                 return;
620             }
621         }
622 
623         if (engine.animating) {
624             // Done with events; draw next animation frame.
625             engine.state.angle += .01f;
626             if (engine.state.angle > 1) {
627                 engine.state.angle = 0;
628             }
629 
630             // Drawing is throttled to the screen update rate, so there
631             // is no need to do timing here.
632             engine_draw_frame(&engine);
633         }
634     }
635 }
636 //END_INCLUDE(all)
View Code

主要是对GL/ES不太熟悉, 而且bug比较诡异, 根本没想到会出这种问题. 代码贴出来, 或许是别的地方有问题, 希望有大大看到帮忙瞧一眼.

顺便, 该平台的GLES是2.0, build version是1.8, 可以正常显式的三星手机也是GLES2.0, build version是1.9rc.


另外, 之前OBB的问题, 使用40M+的OBB, 运行时基本不会报错了, 但是现在OBB单个文件夹内的文件数太少了, 打包时会抛出异常.

http://stackoverflow.com/questions/13562617/using-jobb-tool-in-android

SO上说,内置的OBB格式是FAT16,单个文件夹内只能有512个项...想起来自己引擎新写的pacakge,应该算没有白写.
公司的项目, 考虑使用多文件夹来重新组织数据, 但是太繁琐,太不可控, 一不小心就会超了, 或者考虑也得写自定义的package.

工作很忙, 暂时写这么多吧.


对于OBB, 目前最快的方案是使用子文件夹, 这样根目录的限制就没有了, mount以后把子文件夹的路径加上, 作为data的根路径, 应该最简单了.

原文地址:https://www.cnblogs.com/crazii/p/3653633.html