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