c9c029fd6b071a15015947e91121c5910dde935d
[mupen64plus-pandora.git] / source / gles2n64 / src / OpenGL.cpp
1
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <math.h>
5 #include <string.h>
6 #include <time.h>
7 #include <unistd.h>
8
9 //// paulscode, added for SDL linkage:
10 #ifdef USE_SDL
11     #include <SDL.h>
12      // TODO: Remove this bandaid for SDL 2.0 compatibility (needed for SDL_SetVideoMode)
13     #if SDL_VERSION_ATLEAST(2,0,0)
14     #include "sdl2_compat.h" // Slightly hacked version of core/vidext_sdl2_compat.h
15     #endif
16         #include "eglport.h"
17 #endif
18 ////
19
20 #include "Common.h"
21 #include "gles2N64.h"
22 #include "OpenGL.h"
23 #include "Types.h"
24 #include "N64.h"
25 #include "gSP.h"
26 #include "gDP.h"
27 #include "Textures.h"
28 #include "ShaderCombiner.h"
29 #include "VI.h"
30 #include "RSP.h"
31 #include "Config.h"
32 #include "ticks.h"
33
34 #include "FrameSkipper.h"
35
36 //#include "ae_bridge.h"
37
38 //// paulscode, function prototype missing from Yongzh's code
39 void OGL_UpdateDepthUpdate();
40 ////
41
42 #ifdef TEXTURECACHE_TEST
43 int     TextureCacheTime = 0;
44 #endif
45
46
47 #ifdef RENDERSTATE_TEST
48 int     StateChanges = 0;
49 #endif
50
51 #ifdef SHADER_TEST
52 int     ProgramSwaps = 0;
53 #endif
54
55 #ifdef BATCH_TEST
56 int     TotalDrawTime = 0;
57 int     TotalTriangles = 0;
58 int     TotalDrawCalls = 0;
59 #define glDrawElements(A,B,C,D) \
60     TotalTriangles += B; TotalDrawCalls++; int t = ticksGetTicks(); glDrawElements(A,B,C,D); TotalDrawTime += (ticksGetTicks() - t);
61 #define glDrawArrays(A,B,C) \
62     TotalTriangles += C; TotalDrawCalls++; int t = ticksGetTicks(); glDrawArrays(A,B,C); TotalDrawTime += (ticksGetTicks() - t);
63
64 #endif
65
66 GLInfo OGL;
67
68 const char _default_vsh[] = "                           \n\t" \
69 "attribute highp vec2 aPosition;                        \n\t" \
70 "attribute highp vec2 aTexCoord;                        \n\t" \
71 "varying mediump vec2 vTexCoord;                        \n\t" \
72 "void main(){                                           \n\t" \
73 "gl_Position = vec4(aPosition.x, aPosition.y, 0.0, 1.0);\n\t" \
74 "vTexCoord = aTexCoord;                                 \n\t" \
75 "}                                                      \n\t";
76
77 const char _default_fsh[] = "                           \n\t" \
78 "uniform sampler2D uTex;                                \n\t" \
79 "varying mediump vec2 vTexCoord;                        \n\t" \
80 "void main(){                                           \n\t" \
81 "gl_FragColor = texture2D(uTex, vTexCoord);             \n\t" \
82 "}                                                      \n\t";
83
84 void OGL_EnableRunfast()
85 {
86 #ifdef ARM_ASM
87         static const unsigned int x = 0x04086060;
88         static const unsigned int y = 0x03000000;
89         int r;
90         asm volatile (
91                 "fmrx   %0, fpscr                       \n\t"   //r0 = FPSCR
92                 "and    %0, %0, %1                      \n\t"   //r0 = r0 & 0x04086060
93                 "orr    %0, %0, %2                      \n\t"   //r0 = r0 | 0x03000000
94                 "fmxr   fpscr, %0                       \n\t"   //FPSCR = r0
95                 : "=r"(r)
96                 : "r"(x), "r"(y)
97         );
98 #endif
99 }
100
101 int OGL_IsExtSupported( const char *extension )
102 {
103         const GLubyte *extensions = NULL;
104         const GLubyte *start;
105         GLubyte *where, *terminator;
106
107         where = (GLubyte *) strchr(extension, ' ');
108         if (where || *extension == '\0')
109                 return 0;
110
111         extensions = glGetString(GL_EXTENSIONS);
112
113     if (!extensions) return 0;
114
115         start = extensions;
116         for (;;)
117         {
118                 where = (GLubyte *) strstr((const char *) start, extension);
119                 if (!where)
120                         break;
121
122                 terminator = where + strlen(extension);
123                 if (where == start || *(where - 1) == ' ')
124                         if (*terminator == ' ' || *terminator == '\0')
125                                 return 1;
126
127                 start = terminator;
128         }
129
130         return 0;
131 }
132
133 extern void _glcompiler_error(GLint shader);
134
135 void OGL_InitStates()
136 {
137     GLint   success;
138
139     glEnable( GL_CULL_FACE );
140     glEnableVertexAttribArray( SC_POSITION );
141     glEnable( GL_DEPTH_TEST );
142     glDepthFunc( GL_ALWAYS );
143     glDepthMask( GL_FALSE );
144     glEnable( GL_SCISSOR_TEST );
145
146 ///// paulscode, fixes missing graphics on Qualcomm, Adreno:
147     glDepthRangef(0.0f, 1.0f);
148
149     // default values (only seem to work on OMAP!)
150     glPolygonOffset(0.2f, 0.2f);
151
152     //// paulscode, added for different configurations based on hardware
153     // (part of the missing shadows and stars bug fix)
154 /*    int hardwareType = Android_JNI_GetHardwareType();
155     float f1, f2;
156     Android_JNI_GetPolygonOffset(hardwareType, 1, &f1, &f2);
157     glPolygonOffset( f1, f2 );
158 */    ////
159
160 // some other settings that have been tried, which do not work:
161     //glDepthRangef(1.0f, 0.0f);  // reverses depth-order on OMAP3 chipsets
162     //glPolygonOffset(-0.2f, -0.2f);
163     //glDepthRangef( 0.09f, (float)0x7FFF );  // should work, but not on Adreno
164     //glPolygonOffset( -0.2f, 0.2f );
165     //glDepthRangef(0.0f, (float)0x7FFF);  // what Yongzh used, broken on Adreno
166     //glPolygonOffset(0.2f, 0.2f);
167 /////
168     
169
170     glViewport(config.framebuffer.xpos, config.framebuffer.ypos, config.framebuffer.width, config.framebuffer.height);
171
172     //create default shader program
173     LOG( LOG_VERBOSE, "Generate Default Shader Program.\n" );
174
175     const char *src[1];
176     src[0] = _default_fsh;
177     OGL.defaultFragShader = glCreateShader( GL_FRAGMENT_SHADER );
178     glShaderSource( OGL.defaultFragShader, 1, (const char**) src, NULL );
179     glCompileShader( OGL.defaultFragShader );
180     glGetShaderiv( OGL.defaultFragShader, GL_COMPILE_STATUS, &success );
181     if (!success)
182     {
183         LOG(LOG_ERROR, "Failed to produce default fragment shader.\n");
184     }
185
186     src[0] = _default_vsh;
187     OGL.defaultVertShader = glCreateShader( GL_VERTEX_SHADER );
188     glShaderSource( OGL.defaultVertShader, 1, (const char**) src, NULL );
189     glCompileShader( OGL.defaultVertShader );
190     glGetShaderiv( OGL.defaultVertShader, GL_COMPILE_STATUS, &success );
191     if( !success )
192     {
193         LOG( LOG_ERROR, "Failed to produce default vertex shader.\n" );
194         _glcompiler_error( OGL.defaultVertShader );
195     }
196
197     OGL.defaultProgram = glCreateProgram();
198     glBindAttribLocation( OGL.defaultProgram, 0, "aPosition" );
199     glBindAttribLocation( OGL.defaultProgram, 1, "aTexCoord" );
200     glAttachShader( OGL.defaultProgram, OGL.defaultFragShader );
201     glAttachShader( OGL.defaultProgram, OGL.defaultVertShader );
202     glLinkProgram( OGL.defaultProgram );
203     glGetProgramiv( OGL.defaultProgram, GL_LINK_STATUS, &success );
204     if( !success )
205     {
206         LOG( LOG_ERROR, "Failed to link default program.\n" );
207         _glcompiler_error( OGL.defaultFragShader );
208     }
209     glUniform1i( glGetUniformLocation( OGL.defaultProgram, "uTex" ), 0 );
210     glUseProgram( OGL.defaultProgram );
211
212 }
213
214 void OGL_UpdateScale()
215 {
216     OGL.scaleX = (float)config.framebuffer.width / (float)VI.width;
217     OGL.scaleY = (float)config.framebuffer.height / (float)VI.height;
218 }
219
220 void OGL_ResizeWindow(int x, int y, int width, int height)
221 {
222     config.window.xpos = x;
223     config.window.ypos = y;
224     config.window.width = width;
225     config.window.height = height;
226
227     config.framebuffer.xpos = x;
228     config.framebuffer.ypos = y;
229     config.framebuffer.width = width;
230     config.framebuffer.height = height;
231     OGL_UpdateScale();
232
233     glViewport(config.framebuffer.xpos, config.framebuffer.ypos,
234             config.framebuffer.width, config.framebuffer.height);
235 }
236
237 ////// paulscode, added for SDL linkage
238 #ifdef USE_SDL
239 bool OGL_SDL_Start()
240 {
241     /* Initialize SDL */
242     LOG(LOG_MINIMAL, "Initializing SDL video subsystem...\n" );
243     if (SDL_InitSubSystem( SDL_INIT_VIDEO ) == -1)
244     {
245          LOG(LOG_ERROR, "Error initializing SDL video subsystem: %s\n", SDL_GetError() );
246         return FALSE;
247     }
248 /*SEB*
249     int current_w = config.window.width;
250     int current_h = config.window.height;
251 */
252     int current_w = 800;
253     int current_h = 480;
254     /* Set the video mode */
255     LOG(LOG_MINIMAL, "Setting video mode %dx%d...\n", current_w, current_h );
256
257 // TODO: I should actually check what the pixelformat is, rather than assuming 16 bpp (RGB_565) or 32 bpp (RGBA_8888):
258 //// paulscode, added for switching between modes RGBA8888 and RGB565
259 // (part of the color banding fix)
260 int bitsPP;
261 /*if( Android_JNI_UseRGBA8888() )
262     bitsPP = 32;
263 else*/
264     bitsPP = 16;
265 ////
266
267     // TODO: Replace SDL_SetVideoMode with something that is SDL 2.0 compatible
268     //       Better yet, eliminate all SDL calls by using the Mupen64Plus core api
269     if (!(OGL.hScreen = SDL_SetVideoMode( current_w, current_h, bitsPP, SDL_HWSURFACE | SDL_FULLSCREEN )))
270     {
271         LOG(LOG_ERROR, "Problem setting videomode %dx%d: %s\n", current_w, current_h, SDL_GetError() );
272         SDL_QuitSubSystem( SDL_INIT_VIDEO );
273         return FALSE;
274     }
275
276 //// paulscode, fixes the screen-size problem
277     const float ratio = ( config.romPAL ? 9.0f/11.0f : 0.75f );
278     int videoWidth = config.window.refwidth;
279     int videoHeight = config.window.refheight;
280     int x = 0;
281     int y = 0;
282     
283     //re-scale width and height on per-rom basis
284     float width = /*(float)videoWidth * (float)config.window.refwidth /*/ 800.f;
285     float height = /*(float)videoHeight * (float)config.window.refheight / */480.f;
286     
287    if (!config.stretchVideo) {
288 /*      if ((float)videoWith*480.0f/(float)videoHeight/800.0f>1.0f) {
289                 //scale by Width
290         } else {
291                 //scale by Height
292         }*/
293         videoWidth = (int) (height / ratio);
294         if (videoWidth > width) {
295             videoWidth = width;
296             videoHeight = (int) (width * ratio);
297         }
298     } else {
299         videoWidth=800;
300         videoHeight=480;
301     }
302     x = (width - videoWidth) / 2;
303     y = (height - videoHeight) / 2;
304     
305     //set xpos and ypos
306     config.window.xpos = x;
307     config.window.ypos = y;
308     config.framebuffer.xpos = x;
309     config.framebuffer.ypos = y;
310     
311     //set width and height
312     config.window.width = (int)videoWidth;
313     config.window.height = (int)videoHeight;
314     config.framebuffer.width = (int)videoWidth;
315     config.framebuffer.height = (int)videoHeight;
316         
317         EGL_Open(800, 480);
318 ////
319     return true;
320 }
321 #endif
322 //////
323
324 #ifdef USE_SDL
325 void Android_JNI_SwapWindow()
326 {
327         EGL_SwapBuffers();
328 }
329 #endif
330
331
332 bool OGL_Start()
333 {
334 // paulscode, initialize SDL
335 #ifdef USE_SDL
336     if (!OGL_SDL_Start())
337         return false;
338 #endif
339 //
340
341     OGL_InitStates();
342
343 #ifdef USE_SDL
344 /////// paulscode, graphics bug-fixes
345     float depth = gDP.fillColor.z ;
346     glDisable( GL_SCISSOR_TEST );
347     glDepthMask( GL_TRUE );  // fixes side-bar graphics glitches
348 //    glClearDepthf( depth );  // broken on Qualcomm Adreno
349     glClearDepthf( 1.0f );  // fixes missing graphics on Qualcomm Adreno
350     glClearColor( 0, 0, 0, 1 );
351     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
352     glFinish();
353     Android_JNI_SwapWindow();  // paulscode, fix for black-screen bug
354     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
355     glFinish();
356     OGL_UpdateDepthUpdate();
357     glEnable( GL_SCISSOR_TEST );
358 ////////
359 #endif
360
361     //create framebuffer
362     if (config.framebuffer.enable)
363     {
364         LOG(LOG_VERBOSE, "Create offscreen framebuffer. \n");
365         if (config.framebuffer.width == config.window.width && config.framebuffer.height == config.window.height)
366         {
367             LOG(LOG_WARNING, "There's no point in using a offscreen framebuffer when the window and screen dimensions are the same\n");
368         }
369
370         glGenFramebuffers(1, &OGL.framebuffer.fb);
371         glGenRenderbuffers(1, &OGL.framebuffer.depth_buffer);
372         glGenTextures(1, &OGL.framebuffer.color_buffer);
373         glBindRenderbuffer(GL_RENDERBUFFER, OGL.framebuffer.depth_buffer);
374         glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, config.framebuffer.width, config.framebuffer.height);
375         glBindTexture(GL_TEXTURE_2D, OGL.framebuffer.color_buffer);
376         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, config.framebuffer.width, config.framebuffer.height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
377         glBindFramebuffer(GL_FRAMEBUFFER, OGL.framebuffer.fb);
378         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, OGL.framebuffer.color_buffer, 0);
379         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, OGL.framebuffer.depth_buffer);
380
381         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
382
383         if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
384         {
385             LOG(LOG_ERROR, "Incomplete Framebuffer Object: ");
386             switch(glCheckFramebufferStatus(GL_FRAMEBUFFER))
387             {
388                 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
389                     printf("Incomplete Attachment. \n"); break;
390                 case GL_FRAMEBUFFER_UNSUPPORTED:
391                     printf("Framebuffer Unsupported. \n"); break;
392                 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
393                     printf("Incomplete Dimensions. \n"); break;
394             }
395             config.framebuffer.enable = 0;
396             glBindFramebuffer(GL_FRAMEBUFFER, 0);
397         }
398     }
399
400     //check extensions
401     if ((config.texture.maxAnisotropy>0) && !OGL_IsExtSupported("GL_EXT_texture_filter_anistropic"))
402     {
403         LOG(LOG_WARNING, "Anistropic Filtering is not supported.\n");
404         config.texture.maxAnisotropy = 0;
405     }
406
407     float f = 0;
408     glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &f);
409     if (config.texture.maxAnisotropy > ((int)f))
410     {
411         LOG(LOG_WARNING, "Clamping max anistropy to %ix.\n", (int)f);
412         config.texture.maxAnisotropy = (int)f;
413     }
414
415     //Print some info
416     LOG(LOG_VERBOSE, "Width: %i Height:%i \n", config.framebuffer.width, config.framebuffer.height);
417     LOG(LOG_VERBOSE, "[gles2n64]: Enable Runfast... \n");
418
419     OGL_EnableRunfast();
420     OGL_UpdateScale();
421
422     //We must have a shader bound before binding any textures:
423     ShaderCombiner_Init();
424     ShaderCombiner_Set(EncodeCombineMode(0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0));
425     ShaderCombiner_Set(EncodeCombineMode(0, 0, 0, SHADE, 0, 0, 0, 1, 0, 0, 0, SHADE, 0, 0, 0, 1));
426
427     TextureCache_Init();
428
429     memset(OGL.triangles.vertices, 0, VERTBUFF_SIZE * sizeof(SPVertex));
430     memset(OGL.triangles.elements, 0, ELEMBUFF_SIZE * sizeof(GLubyte));
431     OGL.triangles.num = 0;
432
433 #ifdef __TRIBUFFER_OPT
434     __indexmap_init();
435 #endif
436
437     OGL.frameSkipped = 0;
438     for(int i = 0; i < OGL_FRAMETIME_NUM; i++) OGL.frameTime[i] = 0;
439
440     OGL.renderingToTexture = false;
441     OGL.renderState = RS_NONE;
442     gSP.changed = gDP.changed = 0xFFFFFFFF;
443     VI.displayNum = 0;
444     glGetError();
445
446     return TRUE;
447 }
448
449 void OGL_Stop()
450 {
451     LOG(LOG_MINIMAL, "Stopping OpenGL\n");
452
453 #ifdef USE_SDL
454         EGL_Close();
455     SDL_QuitSubSystem( SDL_INIT_VIDEO );
456 #endif
457
458     if (config.framebuffer.enable)
459     {
460         glDeleteFramebuffers(1, &OGL.framebuffer.fb);
461         glDeleteTextures(1, &OGL.framebuffer.color_buffer);
462         glDeleteRenderbuffers(1, &OGL.framebuffer.depth_buffer);
463     }
464
465     glDeleteShader(OGL.defaultFragShader);
466     glDeleteShader(OGL.defaultVertShader);
467     glDeleteProgram(OGL.defaultProgram);
468
469     ShaderCombiner_Destroy();
470     TextureCache_Destroy();
471 }
472
473 void OGL_UpdateCullFace()
474 {
475     if (config.enableFaceCulling && (gSP.geometryMode & G_CULL_BOTH))
476     {
477         glEnable( GL_CULL_FACE );
478         if ((gSP.geometryMode & G_CULL_BACK) && (gSP.geometryMode & G_CULL_FRONT))
479             glCullFace(GL_FRONT_AND_BACK);
480         else if (gSP.geometryMode & G_CULL_BACK)
481             glCullFace(GL_BACK);
482         else
483             glCullFace(GL_FRONT);
484     }
485     else
486         glDisable(GL_CULL_FACE);
487 }
488
489 void OGL_UpdateViewport()
490 {
491     int x, y, w, h;
492     x = config.framebuffer.xpos + (int)(gSP.viewport.x * OGL.scaleX);
493     y = config.framebuffer.ypos + (int)((VI.height - (gSP.viewport.y + gSP.viewport.height)) * OGL.scaleY);
494     w = (int)(gSP.viewport.width * OGL.scaleX);
495     h = (int)(gSP.viewport.height * OGL.scaleY);
496
497     glViewport(x, y, w, h);
498 }
499
500 void OGL_UpdateDepthUpdate()
501 {
502     if (gDP.otherMode.depthUpdate)
503         glDepthMask(GL_TRUE);
504     else
505         glDepthMask(GL_FALSE);
506 }
507
508 void OGL_UpdateScissor()
509 {
510     int x, y, w, h;
511     x = config.framebuffer.xpos + (int)(gDP.scissor.ulx * OGL.scaleX);
512     y = config.framebuffer.ypos + (int)((VI.height - gDP.scissor.lry) * OGL.scaleY);
513     w = (int)((gDP.scissor.lrx - gDP.scissor.ulx) * OGL.scaleX);
514     h = (int)((gDP.scissor.lry - gDP.scissor.uly) * OGL.scaleY);
515     glScissor(x, y, w, h);
516 }
517
518 //copied from RICE VIDEO
519 void OGL_SetBlendMode()
520 {
521
522     u32 blender = gDP.otherMode.l >> 16;
523     u32 blendmode_1 = blender&0xcccc;
524     u32 blendmode_2 = blender&0x3333;
525
526     glEnable(GL_BLEND);
527     switch(gDP.otherMode.cycleType)
528     {
529         case G_CYC_FILL:
530             glDisable(GL_BLEND);
531             break;
532
533         case G_CYC_COPY:
534             glBlendFunc(GL_ONE, GL_ZERO);
535             break;
536
537         case G_CYC_2CYCLE:
538             if (gDP.otherMode.forceBlender && gDP.otherMode.depthCompare)
539             {
540                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
541                 break;
542             }
543
544             switch(blendmode_1+blendmode_2)
545             {
546                 case BLEND_PASS+(BLEND_PASS>>2):    // In * 0 + In * 1
547                 case BLEND_FOG_APRIM+(BLEND_PASS>>2):
548                 case BLEND_FOG_MEM_FOG_MEM + (BLEND_OPA>>2):
549                 case BLEND_FOG_APRIM + (BLEND_OPA>>2):
550                 case BLEND_FOG_ASHADE + (BLEND_OPA>>2):
551                 case BLEND_BI_AFOG + (BLEND_OPA>>2):
552                 case BLEND_FOG_ASHADE + (BLEND_NOOP>>2):
553                 case BLEND_NOOP + (BLEND_OPA>>2):
554                 case BLEND_NOOP4 + (BLEND_NOOP>>2):
555                 case BLEND_FOG_ASHADE+(BLEND_PASS>>2):
556                 case BLEND_FOG_3+(BLEND_PASS>>2):
557                     glDisable(GL_BLEND);
558                     break;
559
560                 case BLEND_PASS+(BLEND_OPA>>2):
561                     if (gDP.otherMode.cvgXAlpha && gDP.otherMode.alphaCvgSel)
562                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
563                     else
564                         glDisable(GL_BLEND);
565                     break;
566
567                 case BLEND_PASS + (BLEND_XLU>>2):
568                 case BLEND_FOG_ASHADE + (BLEND_XLU>>2):
569                 case BLEND_FOG_APRIM + (BLEND_XLU>>2):
570                 case BLEND_FOG_MEM_FOG_MEM + (BLEND_PASS>>2):
571                 case BLEND_XLU + (BLEND_XLU>>2):
572                 case BLEND_BI_AFOG + (BLEND_XLU>>2):
573                 case BLEND_XLU + (BLEND_FOG_MEM_IN_MEM>>2):
574                 case BLEND_PASS + (BLEND_FOG_MEM_IN_MEM>>2):
575                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
576                     break;
577
578                 case BLEND_FOG_ASHADE+0x0301:
579                     glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
580                     break;
581
582                 case 0x0c08+0x1111:
583                     glBlendFunc(GL_ZERO, GL_DST_ALPHA);
584                     break;
585
586                 default:
587                     if (blendmode_2 == (BLEND_PASS>>2))
588                         glDisable(GL_BLEND);
589                     else
590                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
591                     break;
592                 }
593                 break;
594
595     default:
596
597         if (gDP.otherMode.forceBlender && gDP.otherMode.depthCompare && blendmode_1 != BLEND_FOG_ASHADE )
598         {
599             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
600             break;
601         }
602
603         switch (blendmode_1)
604         {
605             case BLEND_XLU:
606             case BLEND_BI_AIN:
607             case BLEND_FOG_MEM:
608             case BLEND_FOG_MEM_IN_MEM:
609             case BLEND_BLENDCOLOR:
610             case 0x00c0:
611                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
612                 break;
613
614             case BLEND_MEM_ALPHA_IN:
615                 glBlendFunc(GL_ZERO, GL_DST_ALPHA);
616                 break;
617
618             case BLEND_OPA:
619                 //if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS )
620                 //{
621                 //   glBlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA);
622                 //}
623
624                 glDisable(GL_BLEND);
625                 break;
626
627             case BLEND_PASS:
628             case BLEND_NOOP:
629             case BLEND_FOG_ASHADE:
630             case BLEND_FOG_MEM_3:
631             case BLEND_BI_AFOG:
632                 glDisable(GL_BLEND);
633                 break;
634
635             case BLEND_FOG_APRIM:
636                 glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ZERO);
637                 break;
638
639             case BLEND_NOOP3:
640             case BLEND_NOOP5:
641             case BLEND_MEM:
642                 glBlendFunc(GL_ZERO, GL_ONE);
643                 break;
644
645             default:
646                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
647         }
648     }
649
650 }
651
652 void OGL_UpdateStates()
653 {
654     if (gDP.otherMode.cycleType == G_CYC_COPY)
655         ShaderCombiner_Set(EncodeCombineMode(0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0));
656     else if (gDP.otherMode.cycleType == G_CYC_FILL)
657         ShaderCombiner_Set(EncodeCombineMode(0, 0, 0, SHADE, 0, 0, 0, 1, 0, 0, 0, SHADE, 0, 0, 0, 1));
658     else
659         ShaderCombiner_Set(gDP.combine.mux);
660
661 #ifdef SHADER_TEST
662     ProgramSwaps += scProgramChanged;
663 #endif
664
665     if (gSP.changed & CHANGED_GEOMETRYMODE)
666     {
667         OGL_UpdateCullFace();
668
669         if (gSP.geometryMode & G_ZBUFFER)
670             glEnable(GL_DEPTH_TEST);
671         else
672             glDisable(GL_DEPTH_TEST);
673
674     }
675
676     if (gDP.changed & CHANGED_CONVERT)
677     {
678         SC_SetUniform1f(uK4, gDP.convert.k4);
679         SC_SetUniform1f(uK5, gDP.convert.k5);
680     }
681
682     if (gDP.changed & CHANGED_RENDERMODE || gDP.changed & CHANGED_CYCLETYPE)
683     {
684         if (gDP.otherMode.cycleType == G_CYC_1CYCLE || gDP.otherMode.cycleType == G_CYC_2CYCLE)
685         {
686             //glDepthFunc((gDP.otherMode.depthCompare) ? GL_GEQUAL : GL_ALWAYS);
687             glDepthFunc((gDP.otherMode.depthCompare) ? GL_LESS : GL_ALWAYS);
688             glDepthMask((gDP.otherMode.depthUpdate) ? GL_TRUE : GL_FALSE);
689
690             if (gDP.otherMode.depthMode == ZMODE_DEC)
691                 glEnable(GL_POLYGON_OFFSET_FILL);
692            else
693                 glDisable(GL_POLYGON_OFFSET_FILL);
694         }
695         else
696         {
697             glDepthFunc(GL_ALWAYS);
698             glDepthMask(GL_FALSE);
699         }
700     }
701
702     if ((gDP.changed & CHANGED_BLENDCOLOR) || (gDP.changed & CHANGED_RENDERMODE))
703         SC_SetUniform1f(uAlphaRef, (gDP.otherMode.cvgXAlpha) ? 0.5f : gDP.blendColor.a);
704
705     if (gDP.changed & CHANGED_SCISSOR)
706         OGL_UpdateScissor();
707
708     if (gSP.changed & CHANGED_VIEWPORT)
709         OGL_UpdateViewport();
710
711     if (gSP.changed & CHANGED_FOGPOSITION)
712     {
713         SC_SetUniform1f(uFogMultiplier, (float) gSP.fog.multiplier / 255.0f);
714         SC_SetUniform1f(uFogOffset, (float) gSP.fog.offset / 255.0f);
715     }
716
717     if (gSP.changed & CHANGED_TEXTURESCALE)
718     {
719         if (scProgramCurrent->usesT0 || scProgramCurrent->usesT1)
720             SC_SetUniform2f(uTexScale, gSP.texture.scales, gSP.texture.scalet);
721     }
722
723     if ((gSP.changed & CHANGED_TEXTURE) || (gDP.changed & CHANGED_TILE) || (gDP.changed & CHANGED_TMEM))
724     {
725         //For some reason updating the texture cache on the first frame of LOZ:OOT causes a NULL Pointer exception...
726         if (scProgramCurrent)
727         {
728             if (scProgramCurrent->usesT0)
729             {
730 #ifdef TEXTURECACHE_TEST
731                 unsigned t = ticksGetTicks();
732                 TextureCache_Update(0);
733                 TextureCacheTime += (ticksGetTicks() - t);
734 #else
735                 TextureCache_Update(0);
736 #endif
737                 SC_ForceUniform2f(uTexOffset[0], gSP.textureTile[0]->fuls, gSP.textureTile[0]->fult);
738                 SC_ForceUniform2f(uCacheShiftScale[0], cache.current[0]->shiftScaleS, cache.current[0]->shiftScaleT);
739                 SC_ForceUniform2f(uCacheScale[0], cache.current[0]->scaleS, cache.current[0]->scaleT);
740                 SC_ForceUniform2f(uCacheOffset[0], cache.current[0]->offsetS, cache.current[0]->offsetT);
741             }
742             //else TextureCache_ActivateDummy(0);
743
744             //Note: enabling dummies makes some F-zero X textures flicker.... strange.
745
746             if (scProgramCurrent->usesT1)
747             {
748 #ifdef TEXTURECACHE_TEST
749                 unsigned t = ticksGetTicks();
750                 TextureCache_Update(1);
751                 TextureCacheTime += (ticksGetTicks() - t);
752 #else
753                 TextureCache_Update(1);
754 #endif
755                 SC_ForceUniform2f(uTexOffset[1], gSP.textureTile[1]->fuls, gSP.textureTile[1]->fult);
756                 SC_ForceUniform2f(uCacheShiftScale[1], cache.current[1]->shiftScaleS, cache.current[1]->shiftScaleT);
757                 SC_ForceUniform2f(uCacheScale[1], cache.current[1]->scaleS, cache.current[1]->scaleT);
758                 SC_ForceUniform2f(uCacheOffset[1], cache.current[1]->offsetS, cache.current[1]->offsetT);
759             }
760             //else TextureCache_ActivateDummy(1);
761         }
762     }
763
764     if ((gDP.changed & CHANGED_FOGCOLOR) && config.enableFog)
765         SC_SetUniform4fv(uFogColor, &gDP.fogColor.r );
766
767     if (gDP.changed & CHANGED_ENV_COLOR)
768         SC_SetUniform4fv(uEnvColor, &gDP.envColor.r);
769
770     if (gDP.changed & CHANGED_PRIM_COLOR)
771     {
772         SC_SetUniform4fv(uPrimColor, &gDP.primColor.r);
773         SC_SetUniform1f(uPrimLODFrac, gDP.primColor.l);
774     }
775
776     if ((gDP.changed & CHANGED_RENDERMODE) || (gDP.changed & CHANGED_CYCLETYPE))
777     {
778 #ifndef OLD_BLENDMODE
779         OGL_SetBlendMode();
780 #else
781         if ((gDP.otherMode.forceBlender) &&
782             (gDP.otherMode.cycleType != G_CYC_COPY) &&
783             (gDP.otherMode.cycleType != G_CYC_FILL) &&
784             !(gDP.otherMode.alphaCvgSel))
785         {
786             glEnable( GL_BLEND );
787
788             switch (gDP.otherMode.l >> 16)
789             {
790                 case 0x0448: // Add
791                 case 0x055A:
792                     glBlendFunc( GL_ONE, GL_ONE );
793                     break;
794                 case 0x0C08: // 1080 Sky
795                 case 0x0F0A: // Used LOTS of places
796                     glBlendFunc( GL_ONE, GL_ZERO );
797                     break;
798
799                 case 0x0040: // Fzero
800                 case 0xC810: // Blends fog
801                 case 0xC811: // Blends fog
802                 case 0x0C18: // Standard interpolated blend
803                 case 0x0C19: // Used for antialiasing
804                 case 0x0050: // Standard interpolated blend
805                 case 0x0055: // Used for antialiasing
806                     glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
807                     break;
808
809                 case 0x0FA5: // Seems to be doing just blend color - maybe combiner can be used for this?
810                 case 0x5055: // Used in Paper Mario intro, I'm not sure if this is right...
811                     glBlendFunc( GL_ZERO, GL_ONE );
812                     break;
813
814                 default:
815                     LOG(LOG_VERBOSE, "Unhandled blend mode=%x", gDP.otherMode.l >> 16);
816                     glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
817                     break;
818             }
819         }
820         else
821         {
822             glDisable( GL_BLEND );
823         }
824
825         if (gDP.otherMode.cycleType == G_CYC_FILL)
826         {
827             glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
828             glEnable( GL_BLEND );
829         }
830 #endif
831     }
832
833     gDP.changed &= CHANGED_TILE | CHANGED_TMEM;
834     gSP.changed &= CHANGED_TEXTURE | CHANGED_MATRIX;
835 }
836
837 void OGL_DrawTriangle(SPVertex *vertices, int v0, int v1, int v2)
838 {
839
840 }
841
842 void OGL_AddTriangle(int v0, int v1, int v2)
843 {
844     OGL.triangles.elements[OGL.triangles.num++] = v0;
845     OGL.triangles.elements[OGL.triangles.num++] = v1;
846     OGL.triangles.elements[OGL.triangles.num++] = v2;
847 }
848
849 void OGL_SetColorArray()
850 {
851     if (scProgramCurrent->usesCol)
852         glEnableVertexAttribArray(SC_COLOR);
853     else
854         glDisableVertexAttribArray(SC_COLOR);
855 }
856
857 void OGL_SetTexCoordArrays()
858 {
859     if (scProgramCurrent->usesT0)
860         glEnableVertexAttribArray(SC_TEXCOORD0);
861     else
862         glDisableVertexAttribArray(SC_TEXCOORD0);
863
864     if (scProgramCurrent->usesT1)
865         glEnableVertexAttribArray(SC_TEXCOORD1);
866     else
867         glDisableVertexAttribArray(SC_TEXCOORD1);
868 }
869
870 void OGL_DrawTriangles()
871 {
872     if (OGL.renderingToTexture && config.ignoreOffscreenRendering)
873     {
874         OGL.triangles.num = 0;
875         return;
876     }
877
878     if (OGL.triangles.num == 0) return;
879
880     if ((config.updateMode == SCREEN_UPDATE_AT_1ST_PRIMITIVE) && OGL.screenUpdate)
881         OGL_SwapBuffers();
882
883     if (gSP.changed || gDP.changed)
884         OGL_UpdateStates();
885
886     if (OGL.renderState != RS_TRIANGLE || scProgramChanged)
887     {
888         OGL_SetColorArray();
889         OGL_SetTexCoordArrays();
890         glDisableVertexAttribArray(SC_TEXCOORD1);
891         SC_ForceUniform1f(uRenderState, RS_TRIANGLE);
892     }
893
894     if (OGL.renderState != RS_TRIANGLE)
895     {
896 #ifdef RENDERSTATE_TEST
897         StateChanges++;
898 #endif
899         glVertexAttribPointer(SC_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(SPVertex), &OGL.triangles.vertices[0].x);
900         glVertexAttribPointer(SC_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(SPVertex), &OGL.triangles.vertices[0].r);
901         glVertexAttribPointer(SC_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, sizeof(SPVertex), &OGL.triangles.vertices[0].s);
902
903         OGL_UpdateCullFace();
904         OGL_UpdateViewport();
905         glEnable(GL_SCISSOR_TEST);
906         OGL.renderState = RS_TRIANGLE;
907     }
908
909     glDrawElements(GL_TRIANGLES, OGL.triangles.num, GL_UNSIGNED_BYTE, OGL.triangles.elements);
910     OGL.triangles.num = 0;
911
912 #ifdef __TRIBUFFER_OPT
913     __indexmap_clear();
914 #endif
915 }
916
917 void OGL_DrawLine(int v0, int v1, float width )
918 {
919     if (OGL.renderingToTexture && config.ignoreOffscreenRendering) return;
920
921     if ((config.updateMode == SCREEN_UPDATE_AT_1ST_PRIMITIVE) && OGL.screenUpdate)
922         OGL_SwapBuffers();
923
924     if (gSP.changed || gDP.changed)
925         OGL_UpdateStates();
926
927     if (OGL.renderState != RS_LINE || scProgramChanged)
928     {
929 #ifdef RENDERSTATE_TEST
930         StateChanges++;
931 #endif
932         OGL_SetColorArray();
933         glDisableVertexAttribArray(SC_TEXCOORD0);
934         glDisableVertexAttribArray(SC_TEXCOORD1);
935         glVertexAttribPointer(SC_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(SPVertex), &OGL.triangles.vertices[0].x);
936         glVertexAttribPointer(SC_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(SPVertex), &OGL.triangles.vertices[0].r);
937
938         SC_ForceUniform1f(uRenderState, RS_LINE);
939         OGL_UpdateCullFace();
940         OGL_UpdateViewport();
941         OGL.renderState = RS_LINE;
942     }
943
944     unsigned short elem[2];
945     elem[0] = v0;
946     elem[1] = v1;
947     glLineWidth( width * OGL.scaleX );
948     glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, elem);
949 }
950
951 void OGL_DrawRect( int ulx, int uly, int lrx, int lry, float *color)
952 {
953     if (OGL.renderingToTexture && config.ignoreOffscreenRendering) return;
954
955     if ((config.updateMode == SCREEN_UPDATE_AT_1ST_PRIMITIVE) && OGL.screenUpdate)
956         OGL_SwapBuffers();
957
958     if (gSP.changed || gDP.changed)
959         OGL_UpdateStates();
960
961     if (OGL.renderState != RS_RECT || scProgramChanged)
962     {
963         glDisableVertexAttribArray(SC_COLOR);
964         glDisableVertexAttribArray(SC_TEXCOORD0);
965         glDisableVertexAttribArray(SC_TEXCOORD1);
966         SC_ForceUniform1f(uRenderState, RS_RECT);
967     }
968
969     if (OGL.renderState != RS_RECT)
970     {
971 #ifdef RENDERSTATE_TEST
972         StateChanges++;
973 #endif
974         glVertexAttrib4f(SC_POSITION, 0, 0, gSP.viewport.nearz, 1.0);
975         glVertexAttribPointer(SC_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), &OGL.rect[0].x);
976         OGL.renderState = RS_RECT;
977     }
978
979     glViewport(config.framebuffer.xpos, config.framebuffer.ypos, config.framebuffer.width, config.framebuffer.height );
980     glDisable(GL_SCISSOR_TEST);
981     glDisable(GL_CULL_FACE);
982
983     OGL.rect[0].x = (float) ulx * (2.0f * VI.rwidth) - 1.0;
984     OGL.rect[0].y = (float) uly * (-2.0f * VI.rheight) + 1.0;
985     OGL.rect[1].x = (float) (lrx+1) * (2.0f * VI.rwidth) - 1.0;
986     OGL.rect[1].y = OGL.rect[0].y;
987     OGL.rect[2].x = OGL.rect[0].x;
988     OGL.rect[2].y = (float) (lry+1) * (-2.0f * VI.rheight) + 1.0;
989     OGL.rect[3].x = OGL.rect[1].x;
990     OGL.rect[3].y = OGL.rect[2].y;
991
992     glVertexAttrib4fv(SC_COLOR, color);
993     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
994     glEnable(GL_SCISSOR_TEST);
995     OGL_UpdateViewport();
996
997 }
998
999 void OGL_DrawTexturedRect( float ulx, float uly, float lrx, float lry, float uls, float ult, float lrs, float lrt, bool flip )
1000 {
1001     if (config.hackBanjoTooie)
1002     {
1003         if (gDP.textureImage.width == gDP.colorImage.width &&
1004             gDP.textureImage.format == G_IM_FMT_CI &&
1005             gDP.textureImage.size == G_IM_SIZ_8b)
1006         {
1007             return;
1008         }
1009     }
1010
1011     if (OGL.renderingToTexture && config.ignoreOffscreenRendering) return;
1012
1013     if ((config.updateMode == SCREEN_UPDATE_AT_1ST_PRIMITIVE) && OGL.screenUpdate)
1014         OGL_SwapBuffers();
1015
1016     if (gSP.changed || gDP.changed)
1017         OGL_UpdateStates();
1018
1019     if (OGL.renderState != RS_TEXTUREDRECT || scProgramChanged)
1020     {
1021         glDisableVertexAttribArray(SC_COLOR);
1022         OGL_SetTexCoordArrays();
1023         SC_ForceUniform1f(uRenderState, RS_TEXTUREDRECT);
1024     }
1025
1026     if (OGL.renderState != RS_TEXTUREDRECT)
1027     {
1028 #ifdef RENDERSTATE_TEST
1029         StateChanges++;
1030 #endif
1031         glVertexAttrib4f(SC_COLOR, 0, 0, 0, 0);
1032         glVertexAttrib4f(SC_POSITION, 0, 0, (gDP.otherMode.depthSource == G_ZS_PRIM) ? gDP.primDepth.z : gSP.viewport.nearz, 1.0);
1033         glVertexAttribPointer(SC_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), &OGL.rect[0].x);
1034         glVertexAttribPointer(SC_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), &OGL.rect[0].s0);
1035         glVertexAttribPointer(SC_TEXCOORD1, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), &OGL.rect[0].s1);
1036         OGL.renderState = RS_TEXTUREDRECT;
1037     }
1038
1039     glViewport(config.framebuffer.xpos, config.framebuffer.ypos, config.framebuffer.width, config.framebuffer.height);
1040     glDisable(GL_CULL_FACE);
1041
1042     OGL.rect[0].x = (float) ulx * (2.0f * VI.rwidth) - 1.0f;
1043     OGL.rect[0].y = (float) uly * (-2.0f * VI.rheight) + 1.0f;
1044     OGL.rect[1].x = (float) (lrx) * (2.0f * VI.rwidth) - 1.0f;
1045     OGL.rect[1].y = OGL.rect[0].y;
1046     OGL.rect[2].x = OGL.rect[0].x;
1047     OGL.rect[2].y = (float) (lry) * (-2.0f * VI.rheight) + 1.0f;
1048     OGL.rect[3].x = OGL.rect[1].x;
1049     OGL.rect[3].y = OGL.rect[2].y;
1050
1051     if (scProgramCurrent->usesT0 && cache.current[0] && gSP.textureTile[0])
1052     {
1053         OGL.rect[0].s0 = uls * cache.current[0]->shiftScaleS - gSP.textureTile[0]->fuls;
1054         OGL.rect[0].t0 = ult * cache.current[0]->shiftScaleT - gSP.textureTile[0]->fult;
1055         OGL.rect[3].s0 = (lrs + 1.0f) * cache.current[0]->shiftScaleS - gSP.textureTile[0]->fuls;
1056         OGL.rect[3].t0 = (lrt + 1.0f) * cache.current[0]->shiftScaleT - gSP.textureTile[0]->fult;
1057
1058         if ((cache.current[0]->maskS) && !(cache.current[0]->mirrorS) && (fmod( OGL.rect[0].s0, cache.current[0]->width ) == 0.0f))
1059         {
1060             OGL.rect[3].s0 -= OGL.rect[0].s0;
1061             OGL.rect[0].s0 = 0.0f;
1062         }
1063
1064         if ((cache.current[0]->maskT)  && !(cache.current[0]->mirrorT) && (fmod( OGL.rect[0].t0, cache.current[0]->height ) == 0.0f))
1065         {
1066             OGL.rect[3].t0 -= OGL.rect[0].t0;
1067             OGL.rect[0].t0 = 0.0f;
1068         }
1069
1070         glActiveTexture( GL_TEXTURE0);
1071         if ((OGL.rect[0].s0 >= 0.0f) && (OGL.rect[3].s0 <= cache.current[0]->width))
1072             glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
1073
1074         if ((OGL.rect[0].t0 >= 0.0f) && (OGL.rect[3].t0 <= cache.current[0]->height))
1075             glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
1076
1077         OGL.rect[0].s0 *= cache.current[0]->scaleS;
1078         OGL.rect[0].t0 *= cache.current[0]->scaleT;
1079         OGL.rect[3].s0 *= cache.current[0]->scaleS;
1080         OGL.rect[3].t0 *= cache.current[0]->scaleT;
1081     }
1082
1083     if (scProgramCurrent->usesT1 && cache.current[1] && gSP.textureTile[1])
1084     {
1085         OGL.rect[0].s1 = uls * cache.current[1]->shiftScaleS - gSP.textureTile[1]->fuls;
1086         OGL.rect[0].t1 = ult * cache.current[1]->shiftScaleT - gSP.textureTile[1]->fult;
1087         OGL.rect[3].s1 = (lrs + 1.0f) * cache.current[1]->shiftScaleS - gSP.textureTile[1]->fuls;
1088         OGL.rect[3].t1 = (lrt + 1.0f) * cache.current[1]->shiftScaleT - gSP.textureTile[1]->fult;
1089
1090         if ((cache.current[1]->maskS) && (fmod( OGL.rect[0].s1, cache.current[1]->width ) == 0.0f) && !(cache.current[1]->mirrorS))
1091         {
1092             OGL.rect[3].s1 -= OGL.rect[0].s1;
1093             OGL.rect[0].s1 = 0.0f;
1094         }
1095
1096         if ((cache.current[1]->maskT) && (fmod( OGL.rect[0].t1, cache.current[1]->height ) == 0.0f) && !(cache.current[1]->mirrorT))
1097         {
1098             OGL.rect[3].t1 -= OGL.rect[0].t1;
1099             OGL.rect[0].t1 = 0.0f;
1100         }
1101
1102         glActiveTexture( GL_TEXTURE1);
1103         if ((OGL.rect[0].s1 == 0.0f) && (OGL.rect[3].s1 <= cache.current[1]->width))
1104             glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
1105
1106         if ((OGL.rect[0].t1 == 0.0f) && (OGL.rect[3].t1 <= cache.current[1]->height))
1107             glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
1108
1109         OGL.rect[0].s1 *= cache.current[1]->scaleS;
1110         OGL.rect[0].t1 *= cache.current[1]->scaleT;
1111         OGL.rect[3].s1 *= cache.current[1]->scaleS;
1112         OGL.rect[3].t1 *= cache.current[1]->scaleT;
1113     }
1114
1115     if ((gDP.otherMode.cycleType == G_CYC_COPY) && !config.texture.forceBilinear)
1116     {
1117         glActiveTexture(GL_TEXTURE0);
1118         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
1119         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
1120     }
1121
1122     if (flip)
1123     {
1124         OGL.rect[1].s0 = OGL.rect[0].s0;
1125         OGL.rect[1].t0 = OGL.rect[3].t0;
1126         OGL.rect[1].s1 = OGL.rect[0].s1;
1127         OGL.rect[1].t1 = OGL.rect[3].t1;
1128         OGL.rect[2].s0 = OGL.rect[3].s0;
1129         OGL.rect[2].t0 = OGL.rect[0].t0;
1130         OGL.rect[2].s1 = OGL.rect[3].s1;
1131         OGL.rect[2].t1 = OGL.rect[0].t1;
1132     }
1133     else
1134     {
1135         OGL.rect[1].s0 = OGL.rect[3].s0;
1136         OGL.rect[1].t0 = OGL.rect[0].t0;
1137         OGL.rect[1].s1 = OGL.rect[3].s1;
1138         OGL.rect[1].t1 = OGL.rect[0].t1;
1139         OGL.rect[2].s0 = OGL.rect[0].s0;
1140         OGL.rect[2].t0 = OGL.rect[3].t0;
1141         OGL.rect[2].s1 = OGL.rect[0].s1;
1142         OGL.rect[2].t1 = OGL.rect[3].t1;
1143     }
1144
1145     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1146     OGL_UpdateViewport();
1147 }
1148
1149 void OGL_ClearDepthBuffer()
1150 {
1151     if (OGL.renderingToTexture && config.ignoreOffscreenRendering) return;
1152
1153     if ((config.updateMode == SCREEN_UPDATE_AT_1ST_PRIMITIVE) && OGL.screenUpdate)
1154         OGL_SwapBuffers();
1155
1156     //float depth = 1.0 - (gDP.fillColor.z / ((float)0x3FFF)); // broken on OMAP3
1157     float depth = gDP.fillColor.z ;
1158
1159 /////// paulscode, graphics bug-fixes
1160     glDisable( GL_SCISSOR_TEST );
1161     glDepthMask( GL_TRUE );  // fixes side-bar graphics glitches
1162 //    glClearDepthf( depth );  // broken on Qualcomm Adreno
1163     glClearDepthf( 1.0f );  // fixes missing graphics on Qualcomm Adreno
1164     glClearColor( 0, 0, 0, 1 );
1165     glClear( GL_DEPTH_BUFFER_BIT );
1166     OGL_UpdateDepthUpdate();
1167     glEnable( GL_SCISSOR_TEST );
1168 ////////
1169 }
1170
1171 void OGL_ClearColorBuffer( float *color )
1172 {
1173     if (OGL.renderingToTexture && config.ignoreOffscreenRendering) return;
1174
1175     if ((config.updateMode == SCREEN_UPDATE_AT_1ST_PRIMITIVE) && OGL.screenUpdate)
1176         OGL_SwapBuffers();
1177
1178     glScissor(config.framebuffer.xpos, config.framebuffer.ypos, config.framebuffer.width, config.framebuffer.height);
1179     glClearColor( color[0], color[1], color[2], color[3] );
1180     glClear( GL_COLOR_BUFFER_BIT );
1181     OGL_UpdateScissor();
1182
1183 }
1184
1185 int OGL_CheckError()
1186 {
1187     GLenum e = glGetError();
1188     if (e != GL_NO_ERROR)
1189     {
1190         printf("GL Error: ");
1191         switch(e)
1192         {
1193             case GL_INVALID_ENUM:   printf("INVALID ENUM"); break;
1194             case GL_INVALID_VALUE:  printf("INVALID VALUE"); break;
1195             case GL_INVALID_OPERATION:  printf("INVALID OPERATION"); break;
1196             case GL_OUT_OF_MEMORY:  printf("OUT OF MEMORY"); break;
1197         }
1198         printf("\n");
1199         return 1;
1200     }
1201     return 0;
1202 }
1203
1204 void OGL_UpdateFrameTime()
1205 {
1206     unsigned ticks = ticksGetTicks();
1207     static unsigned lastFrameTicks = 0;
1208     for(int i = OGL_FRAMETIME_NUM-1; i > 0; i--) OGL.frameTime[i] = OGL.frameTime[i-1];
1209     OGL.frameTime[0] = ticks - lastFrameTicks;
1210     lastFrameTicks = ticks;
1211 }
1212
1213 void OGL_SwapBuffers()
1214 {
1215     //OGL_DrawTriangles();
1216     scProgramChanged = 0;
1217 #if 1
1218     static int frames = 0;
1219     static unsigned lastTicks = 0;
1220     unsigned ticks = ticksGetTicks();
1221
1222     frames++;
1223     if (ticks >= (lastTicks + 1000))
1224     {
1225
1226         float fps = 1000.0f * (float) frames / (ticks - lastTicks);
1227         LOG(LOG_MINIMAL, "fps = %.2f \n", fps);
1228         LOG(LOG_MINIMAL, "skipped frame = %i of %i \n", OGL.frameSkipped, frames + OGL.frameSkipped);
1229
1230         OGL.frameSkipped = 0;
1231
1232 #ifdef BATCH_TEST
1233         LOG(LOG_MINIMAL, "time spent in draw calls per frame = %.2f ms\n", (float)TotalDrawTime / frames);
1234         LOG(LOG_MINIMAL, "average draw calls per frame = %.0f\n", (float)TotalDrawCalls / frames);
1235         LOG(LOG_MINIMAL, "average vertices per draw call = %.2f\n", (float)TotalTriangles / TotalDrawCalls);
1236         TotalDrawCalls = 0;
1237         TotalTriangles = 0;
1238         TotalDrawTime = 0;
1239 #endif
1240
1241 #ifdef SHADER_TEST
1242         LOG(LOG_MINIMAL, "average shader changes per frame = %f\n", (float)ProgramSwaps / frames);
1243         ProgramSwaps = 0;
1244 #endif
1245
1246 #ifdef TEXTURECACHE_TEST
1247         LOG(LOG_MINIMAL, "texture cache time per frame: %.2f ms\n", (float)TextureCacheTime/ frames);
1248         LOG(LOG_MINIMAL, "texture cache per frame: hits=%.2f misses=%.2f\n", (float)cache.hits / frames,
1249                 (float)cache.misses / frames);
1250         cache.hits = cache.misses = 0;
1251         TextureCacheTime = 0;
1252
1253 #endif
1254         frames = 0;
1255         lastTicks = ticks;
1256     }
1257 #endif
1258
1259
1260 #ifdef PROFILE_GBI
1261     u32 profileTicks = ticksGetTicks();
1262     static u32 profileLastTicks = 0;
1263     if (profileTicks >= (profileLastTicks + 5000))
1264     {
1265         LOG(LOG_MINIMAL, "GBI PROFILE DATA: %i ms \n", profileTicks - profileLastTicks);
1266         LOG(LOG_MINIMAL, "=========================================================\n");
1267         GBI_ProfilePrint(stdout);
1268         LOG(LOG_MINIMAL, "=========================================================\n");
1269         GBI_ProfileReset();
1270         profileLastTicks = profileTicks;
1271     }
1272 #endif
1273
1274     if (config.framebuffer.enable)
1275     {
1276         glBindFramebuffer(GL_FRAMEBUFFER, 0);
1277         glClearColor( 0, 0, 0, 1 );
1278         glClear( GL_COLOR_BUFFER_BIT );
1279
1280         glUseProgram(OGL.defaultProgram);
1281         glDisable(GL_SCISSOR_TEST);
1282         glDisable(GL_DEPTH_TEST);
1283         glViewport(config.window.xpos, config.window.ypos, config.window.width, config.window.height);
1284
1285         static const float vert[] =
1286         {
1287             -1.0, -1.0, +0.0, +0.0,
1288             +1.0, -1.0, +1.0, +0.0,
1289             -1.0, +1.0, +0.0, +1.0,
1290             +1.0, +1.0, +1.0, +1.0
1291         };
1292
1293         glActiveTexture(GL_TEXTURE0);
1294         glBindTexture(GL_TEXTURE_2D, OGL.framebuffer.color_buffer);
1295         if (config.framebuffer.bilinear)
1296         {
1297             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1298             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1299         }
1300         else
1301         {
1302             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1303             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1304         }
1305
1306         glEnableVertexAttribArray(0);
1307         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (float*)vert);
1308         glEnableVertexAttribArray(1);
1309         glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (float*)vert + 2);
1310         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1311
1312         Android_JNI_SwapWindow(); // paulscode, fix for black-screen bug
1313
1314         glBindFramebuffer(GL_FRAMEBUFFER, OGL.framebuffer.fb);
1315         OGL_UpdateViewport();
1316         if (scProgramCurrent) glUseProgram(scProgramCurrent->program);
1317         OGL.renderState = RS_NONE;
1318     }
1319     else
1320     {
1321         Android_JNI_SwapWindow(); // paulscode, fix for black-screen bug
1322     }
1323
1324     // if emulator defined a render callback function, call it before
1325         // buffer swap
1326     if (renderCallback) (*renderCallback)();
1327
1328     OGL.screenUpdate = false;
1329
1330     if (config.forceBufferClear)
1331     {
1332 /////// paulscode, graphics bug-fixes
1333     float depth = gDP.fillColor.z ;
1334     glDisable( GL_SCISSOR_TEST );
1335     glDepthMask( GL_TRUE );  // fixes side-bar graphics glitches
1336 //    glClearDepthf( depth );  // broken on Qualcomm Adreno
1337     glClearDepthf( 1.0f );  // fixes missing graphics on Qualcomm Adreno
1338     glClearColor( 0, 0, 0, 1 );
1339     glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );
1340     OGL_UpdateDepthUpdate();
1341     glEnable( GL_SCISSOR_TEST );
1342 ///////
1343     }
1344
1345 }
1346
1347 void OGL_ReadScreen( void *dest, int *width, int *height )
1348 {
1349     if (width)
1350         *width = config.framebuffer.width;
1351     if (height)
1352         *height = config.framebuffer.height;
1353
1354     if (dest == NULL)
1355         return;
1356
1357     glReadPixels( config.framebuffer.xpos, config.framebuffer.ypos,
1358             config.framebuffer.width, config.framebuffer.height,
1359             GL_RGBA, GL_UNSIGNED_BYTE, dest );
1360 }
1361