GLES2N64: Enabled Framebuffer (and lowres) rendering
[mupen64plus-pandora.git] / source / gles2n64 / src / OpenGL.cpp
CommitLineData
34cf4058 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
39void OGL_UpdateDepthUpdate();
40////
41
42#ifdef TEXTURECACHE_TEST
43int TextureCacheTime = 0;
44#endif
45
46
47#ifdef RENDERSTATE_TEST
48int StateChanges = 0;
49#endif
50
51#ifdef SHADER_TEST
52int ProgramSwaps = 0;
53#endif
54
55#ifdef BATCH_TEST
56int TotalDrawTime = 0;
57int TotalTriangles = 0;
58int 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
66GLInfo OGL;
67
68const 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
77const 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
afa31bdd 84
34cf4058 85void 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
102int 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
134extern void _glcompiler_error(GLint shader);
135
136void 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
215void 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
221void 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
afa31bdd 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 }
34cf4058 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
242bool 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)
263int bitsPP;
264/*if( Android_JNI_UseRGBA8888() )
265 bitsPP = 32;
266else*/
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
ac4f8e43 272 if (!(OGL.hScreen = SDL_SetVideoMode( current_w, current_h, bitsPP, SDL_HWSURFACE | SDL_FULLSCREEN )))
34cf4058 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;
34cf4058 311
312 //set width and height
313 config.window.width = (int)videoWidth;
314 config.window.height = (int)videoHeight;
afa31bdd 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 }
34cf4058 321
322 EGL_Open(800, 480);
323////
324 return true;
325}
326#endif
afa31bdd 327
34cf4058 328//////
329
330#ifdef USE_SDL
331void Android_JNI_SwapWindow()
332{
333 EGL_SwapBuffers();
334}
335#endif
336
34cf4058 337bool 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);
34cf4058 376 glGenTextures(1, &OGL.framebuffer.color_buffer);
34cf4058 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);
afa31bdd 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);
34cf4058 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
459void 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
483void 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
499void 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
510void OGL_UpdateDepthUpdate()
511{
512 if (gDP.otherMode.depthUpdate)
513 glDepthMask(GL_TRUE);
514 else
515 glDepthMask(GL_FALSE);
516}
517
518void 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
529void 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
662void 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
847void OGL_DrawTriangle(SPVertex *vertices, int v0, int v1, int v2)
848{
849
850}
851
852void 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
859void OGL_SetColorArray()
860{
861 if (scProgramCurrent->usesCol)
862 glEnableVertexAttribArray(SC_COLOR);
863 else
864 glDisableVertexAttribArray(SC_COLOR);
865}
866
867void 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
880void 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
927void 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
961void 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
1009void 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
1159void 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 );
0ced54f8 1175 glClear( GL_DEPTH_BUFFER_BIT );
34cf4058 1176 OGL_UpdateDepthUpdate();
1177 glEnable( GL_SCISSOR_TEST );
1178////////
1179}
1180
1181void 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
1195int 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
1214void 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
1223void OGL_SwapBuffers()
1224{
1225 //OGL_DrawTriangles();
1226 scProgramChanged = 0;
90768f93 1227#if 1
34cf4058 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
afa31bdd 1284 // if emulator defined a render callback function, call it before
1285 // buffer swap
1286 if (renderCallback) (*renderCallback)();
1287
34cf4058 1288 if (config.framebuffer.enable)
1289 {
1290 glBindFramebuffer(GL_FRAMEBUFFER, 0);
afa31bdd 1291 glClearColor( 0, 0, 0, 1 );
34cf4058 1292 glClear( GL_COLOR_BUFFER_BIT );
1293
1294 glUseProgram(OGL.defaultProgram);
1295 glDisable(GL_SCISSOR_TEST);
1296 glDisable(GL_DEPTH_TEST);
afa31bdd 1297 glDisable(GL_CULL_FACE); //*SEB*
34cf4058 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();
afa31bdd 1331 OGL_UpdateCullFace();
34cf4058 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
34cf4058 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
1359void 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