9 //// paulscode, added for SDL linkage:
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
28 #include "ShaderCombiner.h"
34 #include "FrameSkipper.h"
36 //#include "ae_bridge.h"
38 //// paulscode, function prototype missing from Yongzh's code
39 void OGL_UpdateDepthUpdate();
42 #ifdef TEXTURECACHE_TEST
43 int TextureCacheTime = 0;
47 #ifdef RENDERSTATE_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);
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" \
73 "gl_Position = vec4(aPosition.x, aPosition.y, 0.0, 1.0);\n\t" \
74 "vTexCoord = aTexCoord; \n\t" \
77 const char _default_fsh[] = " \n\t" \
78 "uniform sampler2D uTex; \n\t" \
79 "varying mediump vec2 vTexCoord; \n\t" \
81 "gl_FragColor = texture2D(uTex, vTexCoord); \n\t" \
84 void OGL_EnableRunfast()
87 static const unsigned int x = 0x04086060;
88 static const unsigned int y = 0x03000000;
91 "fmrx %0, fpscr \n\t" //r0 = FPSCR
92 "and %0, %0, %1 \n\t" //r0 = r0 & 0x04086060
93 "orr %0, %0, %2 \n\t" //r0 = r0 | 0x03000000
94 "fmxr fpscr, %0 \n\t" //FPSCR = r0
101 int OGL_IsExtSupported( const char *extension )
103 const GLubyte *extensions = NULL;
104 const GLubyte *start;
105 GLubyte *where, *terminator;
107 where = (GLubyte *) strchr(extension, ' ');
108 if (where || *extension == '\0')
111 extensions = glGetString(GL_EXTENSIONS);
113 if (!extensions) return 0;
118 where = (GLubyte *) strstr((const char *) start, extension);
122 terminator = where + strlen(extension);
123 if (where == start || *(where - 1) == ' ')
124 if (*terminator == ' ' || *terminator == '\0')
133 extern void _glcompiler_error(GLint shader);
135 void OGL_InitStates()
139 glEnable( GL_CULL_FACE );
140 glEnableVertexAttribArray( SC_POSITION );
141 glEnable( GL_DEPTH_TEST );
142 glDepthFunc( GL_ALWAYS );
143 glDepthMask( GL_FALSE );
144 glEnable( GL_SCISSOR_TEST );
146 ///// paulscode, fixes missing graphics on Qualcomm, Adreno:
147 glDepthRangef(0.0f, 1.0f);
149 // default values (only seem to work on OMAP!)
150 glPolygonOffset(0.2f, 0.2f);
152 //// paulscode, added for different configurations based on hardware
153 // (part of the missing shadows and stars bug fix)
154 /* int hardwareType = Android_JNI_GetHardwareType();
156 Android_JNI_GetPolygonOffset(hardwareType, 1, &f1, &f2);
157 glPolygonOffset( f1, f2 );
160 // some other settings that have been tried, which do not work:
161 //glDepthRangef(1.0f, 0.0f); // reverses depth-order on OMAP3 chipsets
162 //glPolygonOffset(-0.2f, -0.2f);
163 //glDepthRangef( 0.09f, (float)0x7FFF ); // should work, but not on Adreno
164 //glPolygonOffset( -0.2f, 0.2f );
165 //glDepthRangef(0.0f, (float)0x7FFF); // what Yongzh used, broken on Adreno
166 //glPolygonOffset(0.2f, 0.2f);
170 glViewport(config.framebuffer.xpos, config.framebuffer.ypos, config.framebuffer.width, config.framebuffer.height);
172 //create default shader program
173 LOG( LOG_VERBOSE, "Generate Default Shader Program.\n" );
176 src[0] = _default_fsh;
177 OGL.defaultFragShader = glCreateShader( GL_FRAGMENT_SHADER );
178 glShaderSource( OGL.defaultFragShader, 1, (const char**) src, NULL );
179 glCompileShader( OGL.defaultFragShader );
180 glGetShaderiv( OGL.defaultFragShader, GL_COMPILE_STATUS, &success );
183 LOG(LOG_ERROR, "Failed to produce default fragment shader.\n");
186 src[0] = _default_vsh;
187 OGL.defaultVertShader = glCreateShader( GL_VERTEX_SHADER );
188 glShaderSource( OGL.defaultVertShader, 1, (const char**) src, NULL );
189 glCompileShader( OGL.defaultVertShader );
190 glGetShaderiv( OGL.defaultVertShader, GL_COMPILE_STATUS, &success );
193 LOG( LOG_ERROR, "Failed to produce default vertex shader.\n" );
194 _glcompiler_error( OGL.defaultVertShader );
197 OGL.defaultProgram = glCreateProgram();
198 glBindAttribLocation( OGL.defaultProgram, 0, "aPosition" );
199 glBindAttribLocation( OGL.defaultProgram, 1, "aTexCoord" );
200 glAttachShader( OGL.defaultProgram, OGL.defaultFragShader );
201 glAttachShader( OGL.defaultProgram, OGL.defaultVertShader );
202 glLinkProgram( OGL.defaultProgram );
203 glGetProgramiv( OGL.defaultProgram, GL_LINK_STATUS, &success );
206 LOG( LOG_ERROR, "Failed to link default program.\n" );
207 _glcompiler_error( OGL.defaultFragShader );
209 glUniform1i( glGetUniformLocation( OGL.defaultProgram, "uTex" ), 0 );
210 glUseProgram( OGL.defaultProgram );
214 void OGL_UpdateScale()
216 OGL.scaleX = (float)config.framebuffer.width / (float)VI.width;
217 OGL.scaleY = (float)config.framebuffer.height / (float)VI.height;
220 void OGL_ResizeWindow(int x, int y, int width, int height)
222 config.window.xpos = x;
223 config.window.ypos = y;
224 config.window.width = width;
225 config.window.height = height;
227 config.framebuffer.xpos = x;
228 config.framebuffer.ypos = y;
229 config.framebuffer.width = width;
230 config.framebuffer.height = height;
233 glViewport(config.framebuffer.xpos, config.framebuffer.ypos,
234 config.framebuffer.width, config.framebuffer.height);
237 ////// paulscode, added for SDL linkage
242 LOG(LOG_MINIMAL, "Initializing SDL video subsystem...\n" );
243 if (SDL_InitSubSystem( SDL_INIT_VIDEO ) == -1)
245 LOG(LOG_ERROR, "Error initializing SDL video subsystem: %s\n", SDL_GetError() );
249 int current_w = config.window.width;
250 int current_h = config.window.height;
254 /* Set the video mode */
255 LOG(LOG_MINIMAL, "Setting video mode %dx%d...\n", current_w, current_h );
257 // TODO: I should actually check what the pixelformat is, rather than assuming 16 bpp (RGB_565) or 32 bpp (RGBA_8888):
258 //// paulscode, added for switching between modes RGBA8888 and RGB565
259 // (part of the color banding fix)
261 /*if( Android_JNI_UseRGBA8888() )
267 // TODO: Replace SDL_SetVideoMode with something that is SDL 2.0 compatible
268 // Better yet, eliminate all SDL calls by using the Mupen64Plus core api
269 if (!(OGL.hScreen = SDL_SetVideoMode( current_w, current_h, bitsPP, SDL_HWSURFACE | SDL_FULLSCREEN )))
271 LOG(LOG_ERROR, "Problem setting videomode %dx%d: %s\n", current_w, current_h, SDL_GetError() );
272 SDL_QuitSubSystem( SDL_INIT_VIDEO );
276 //// paulscode, fixes the screen-size problem
277 const float ratio = ( config.romPAL ? 9.0f/11.0f : 0.75f );
278 int videoWidth = config.window.refwidth;
279 int videoHeight = config.window.refheight;
283 //re-scale width and height on per-rom basis
284 float width = /*(float)videoWidth * (float)config.window.refwidth /*/ 800.f;
285 float height = /*(float)videoHeight * (float)config.window.refheight / */480.f;
287 if (!config.stretchVideo) {
288 /* if ((float)videoWith*480.0f/(float)videoHeight/800.0f>1.0f) {
293 videoWidth = (int) (height / ratio);
294 if (videoWidth > width) {
296 videoHeight = (int) (width * ratio);
302 x = (width - videoWidth) / 2;
303 y = (height - videoHeight) / 2;
306 config.window.xpos = x;
307 config.window.ypos = y;
308 config.framebuffer.xpos = x;
309 config.framebuffer.ypos = y;
311 //set width and height
312 config.window.width = (int)videoWidth;
313 config.window.height = (int)videoHeight;
314 config.framebuffer.width = (int)videoWidth;
315 config.framebuffer.height = (int)videoHeight;
325 void Android_JNI_SwapWindow()
334 // paulscode, initialize SDL
336 if (!OGL_SDL_Start())
344 /////// paulscode, graphics bug-fixes
345 float depth = gDP.fillColor.z ;
346 glDisable( GL_SCISSOR_TEST );
347 glDepthMask( GL_TRUE ); // fixes side-bar graphics glitches
348 // glClearDepthf( depth ); // broken on Qualcomm Adreno
349 glClearDepthf( 1.0f ); // fixes missing graphics on Qualcomm Adreno
350 glClearColor( 0, 0, 0, 1 );
351 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
353 Android_JNI_SwapWindow(); // paulscode, fix for black-screen bug
354 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
356 OGL_UpdateDepthUpdate();
357 glEnable( GL_SCISSOR_TEST );
362 if (config.framebuffer.enable)
364 LOG(LOG_VERBOSE, "Create offscreen framebuffer. \n");
365 if (config.framebuffer.width == config.window.width && config.framebuffer.height == config.window.height)
367 LOG(LOG_WARNING, "There's no point in using a offscreen framebuffer when the window and screen dimensions are the same\n");
370 glGenFramebuffers(1, &OGL.framebuffer.fb);
371 glGenRenderbuffers(1, &OGL.framebuffer.depth_buffer);
372 glGenTextures(1, &OGL.framebuffer.color_buffer);
373 glBindRenderbuffer(GL_RENDERBUFFER, OGL.framebuffer.depth_buffer);
374 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, config.framebuffer.width, config.framebuffer.height);
375 glBindTexture(GL_TEXTURE_2D, OGL.framebuffer.color_buffer);
376 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, config.framebuffer.width, config.framebuffer.height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
377 glBindFramebuffer(GL_FRAMEBUFFER, OGL.framebuffer.fb);
378 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, OGL.framebuffer.color_buffer, 0);
379 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, OGL.framebuffer.depth_buffer);
381 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
383 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
385 LOG(LOG_ERROR, "Incomplete Framebuffer Object: ");
386 switch(glCheckFramebufferStatus(GL_FRAMEBUFFER))
388 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
389 printf("Incomplete Attachment. \n"); break;
390 case GL_FRAMEBUFFER_UNSUPPORTED:
391 printf("Framebuffer Unsupported. \n"); break;
392 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
393 printf("Incomplete Dimensions. \n"); break;
395 config.framebuffer.enable = 0;
396 glBindFramebuffer(GL_FRAMEBUFFER, 0);
401 if ((config.texture.maxAnisotropy>0) && !OGL_IsExtSupported("GL_EXT_texture_filter_anistropic"))
403 LOG(LOG_WARNING, "Anistropic Filtering is not supported.\n");
404 config.texture.maxAnisotropy = 0;
408 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &f);
409 if (config.texture.maxAnisotropy > ((int)f))
411 LOG(LOG_WARNING, "Clamping max anistropy to %ix.\n", (int)f);
412 config.texture.maxAnisotropy = (int)f;
416 LOG(LOG_VERBOSE, "Width: %i Height:%i \n", config.framebuffer.width, config.framebuffer.height);
417 LOG(LOG_VERBOSE, "[gles2n64]: Enable Runfast... \n");
422 //We must have a shader bound before binding any textures:
423 ShaderCombiner_Init();
424 ShaderCombiner_Set(EncodeCombineMode(0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0));
425 ShaderCombiner_Set(EncodeCombineMode(0, 0, 0, SHADE, 0, 0, 0, 1, 0, 0, 0, SHADE, 0, 0, 0, 1));
429 memset(OGL.triangles.vertices, 0, VERTBUFF_SIZE * sizeof(SPVertex));
430 memset(OGL.triangles.elements, 0, ELEMBUFF_SIZE * sizeof(GLubyte));
431 OGL.triangles.num = 0;
433 #ifdef __TRIBUFFER_OPT
437 OGL.frameSkipped = 0;
438 for(int i = 0; i < OGL_FRAMETIME_NUM; i++) OGL.frameTime[i] = 0;
440 OGL.renderingToTexture = false;
441 OGL.renderState = RS_NONE;
442 gSP.changed = gDP.changed = 0xFFFFFFFF;
451 LOG(LOG_MINIMAL, "Stopping OpenGL\n");
455 SDL_QuitSubSystem( SDL_INIT_VIDEO );
458 if (config.framebuffer.enable)
460 glDeleteFramebuffers(1, &OGL.framebuffer.fb);
461 glDeleteTextures(1, &OGL.framebuffer.color_buffer);
462 glDeleteRenderbuffers(1, &OGL.framebuffer.depth_buffer);
465 glDeleteShader(OGL.defaultFragShader);
466 glDeleteShader(OGL.defaultVertShader);
467 glDeleteProgram(OGL.defaultProgram);
469 ShaderCombiner_Destroy();
470 TextureCache_Destroy();
473 void OGL_UpdateCullFace()
475 if (config.enableFaceCulling && (gSP.geometryMode & G_CULL_BOTH))
477 glEnable( GL_CULL_FACE );
478 if ((gSP.geometryMode & G_CULL_BACK) && (gSP.geometryMode & G_CULL_FRONT))
479 glCullFace(GL_FRONT_AND_BACK);
480 else if (gSP.geometryMode & G_CULL_BACK)
483 glCullFace(GL_FRONT);
486 glDisable(GL_CULL_FACE);
489 void OGL_UpdateViewport()
492 x = config.framebuffer.xpos + (int)(gSP.viewport.x * OGL.scaleX);
493 y = config.framebuffer.ypos + (int)((VI.height - (gSP.viewport.y + gSP.viewport.height)) * OGL.scaleY);
494 w = (int)(gSP.viewport.width * OGL.scaleX);
495 h = (int)(gSP.viewport.height * OGL.scaleY);
497 glViewport(x, y, w, h);
500 void OGL_UpdateDepthUpdate()
502 if (gDP.otherMode.depthUpdate)
503 glDepthMask(GL_TRUE);
505 glDepthMask(GL_FALSE);
508 void OGL_UpdateScissor()
511 x = config.framebuffer.xpos + (int)(gDP.scissor.ulx * OGL.scaleX);
512 y = config.framebuffer.ypos + (int)((VI.height - gDP.scissor.lry) * OGL.scaleY);
513 w = (int)((gDP.scissor.lrx - gDP.scissor.ulx) * OGL.scaleX);
514 h = (int)((gDP.scissor.lry - gDP.scissor.uly) * OGL.scaleY);
515 glScissor(x, y, w, h);
518 //copied from RICE VIDEO
519 void OGL_SetBlendMode()
522 u32 blender = gDP.otherMode.l >> 16;
523 u32 blendmode_1 = blender&0xcccc;
524 u32 blendmode_2 = blender&0x3333;
527 switch(gDP.otherMode.cycleType)
534 glBlendFunc(GL_ONE, GL_ZERO);
538 if (gDP.otherMode.forceBlender && gDP.otherMode.depthCompare)
540 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
544 switch(blendmode_1+blendmode_2)
546 case BLEND_PASS+(BLEND_PASS>>2): // In * 0 + In * 1
547 case BLEND_FOG_APRIM+(BLEND_PASS>>2):
548 case BLEND_FOG_MEM_FOG_MEM + (BLEND_OPA>>2):
549 case BLEND_FOG_APRIM + (BLEND_OPA>>2):
550 case BLEND_FOG_ASHADE + (BLEND_OPA>>2):
551 case BLEND_BI_AFOG + (BLEND_OPA>>2):
552 case BLEND_FOG_ASHADE + (BLEND_NOOP>>2):
553 case BLEND_NOOP + (BLEND_OPA>>2):
554 case BLEND_NOOP4 + (BLEND_NOOP>>2):
555 case BLEND_FOG_ASHADE+(BLEND_PASS>>2):
556 case BLEND_FOG_3+(BLEND_PASS>>2):
560 case BLEND_PASS+(BLEND_OPA>>2):
561 if (gDP.otherMode.cvgXAlpha && gDP.otherMode.alphaCvgSel)
562 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
567 case BLEND_PASS + (BLEND_XLU>>2):
568 case BLEND_FOG_ASHADE + (BLEND_XLU>>2):
569 case BLEND_FOG_APRIM + (BLEND_XLU>>2):
570 case BLEND_FOG_MEM_FOG_MEM + (BLEND_PASS>>2):
571 case BLEND_XLU + (BLEND_XLU>>2):
572 case BLEND_BI_AFOG + (BLEND_XLU>>2):
573 case BLEND_XLU + (BLEND_FOG_MEM_IN_MEM>>2):
574 case BLEND_PASS + (BLEND_FOG_MEM_IN_MEM>>2):
575 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
578 case BLEND_FOG_ASHADE+0x0301:
579 glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
583 glBlendFunc(GL_ZERO, GL_DST_ALPHA);
587 if (blendmode_2 == (BLEND_PASS>>2))
590 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
597 if (gDP.otherMode.forceBlender && gDP.otherMode.depthCompare && blendmode_1 != BLEND_FOG_ASHADE )
599 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
608 case BLEND_FOG_MEM_IN_MEM:
609 case BLEND_BLENDCOLOR:
611 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
614 case BLEND_MEM_ALPHA_IN:
615 glBlendFunc(GL_ZERO, GL_DST_ALPHA);
619 //if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS )
621 // glBlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA);
629 case BLEND_FOG_ASHADE:
630 case BLEND_FOG_MEM_3:
635 case BLEND_FOG_APRIM:
636 glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ZERO);
642 glBlendFunc(GL_ZERO, GL_ONE);
646 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
652 void OGL_UpdateStates()
654 if (gDP.otherMode.cycleType == G_CYC_COPY)
655 ShaderCombiner_Set(EncodeCombineMode(0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0));
656 else if (gDP.otherMode.cycleType == G_CYC_FILL)
657 ShaderCombiner_Set(EncodeCombineMode(0, 0, 0, SHADE, 0, 0, 0, 1, 0, 0, 0, SHADE, 0, 0, 0, 1));
659 ShaderCombiner_Set(gDP.combine.mux);
662 ProgramSwaps += scProgramChanged;
665 if (gSP.changed & CHANGED_GEOMETRYMODE)
667 OGL_UpdateCullFace();
669 if (gSP.geometryMode & G_ZBUFFER)
670 glEnable(GL_DEPTH_TEST);
672 glDisable(GL_DEPTH_TEST);
676 if (gDP.changed & CHANGED_CONVERT)
678 SC_SetUniform1f(uK4, gDP.convert.k4);
679 SC_SetUniform1f(uK5, gDP.convert.k5);
682 if (gDP.changed & CHANGED_RENDERMODE || gDP.changed & CHANGED_CYCLETYPE)
684 if (gDP.otherMode.cycleType == G_CYC_1CYCLE || gDP.otherMode.cycleType == G_CYC_2CYCLE)
686 //glDepthFunc((gDP.otherMode.depthCompare) ? GL_GEQUAL : GL_ALWAYS);
687 glDepthFunc((gDP.otherMode.depthCompare) ? GL_LESS : GL_ALWAYS);
688 glDepthMask((gDP.otherMode.depthUpdate) ? GL_TRUE : GL_FALSE);
690 if (gDP.otherMode.depthMode == ZMODE_DEC)
691 glEnable(GL_POLYGON_OFFSET_FILL);
693 glDisable(GL_POLYGON_OFFSET_FILL);
697 glDepthFunc(GL_ALWAYS);
698 glDepthMask(GL_FALSE);
702 if ((gDP.changed & CHANGED_BLENDCOLOR) || (gDP.changed & CHANGED_RENDERMODE))
703 SC_SetUniform1f(uAlphaRef, (gDP.otherMode.cvgXAlpha) ? 0.5f : gDP.blendColor.a);
705 if (gDP.changed & CHANGED_SCISSOR)
708 if (gSP.changed & CHANGED_VIEWPORT)
709 OGL_UpdateViewport();
711 if (gSP.changed & CHANGED_FOGPOSITION)
713 SC_SetUniform1f(uFogMultiplier, (float) gSP.fog.multiplier / 255.0f);
714 SC_SetUniform1f(uFogOffset, (float) gSP.fog.offset / 255.0f);
717 if (gSP.changed & CHANGED_TEXTURESCALE)
719 if (scProgramCurrent->usesT0 || scProgramCurrent->usesT1)
720 SC_SetUniform2f(uTexScale, gSP.texture.scales, gSP.texture.scalet);
723 if ((gSP.changed & CHANGED_TEXTURE) || (gDP.changed & CHANGED_TILE) || (gDP.changed & CHANGED_TMEM))
725 //For some reason updating the texture cache on the first frame of LOZ:OOT causes a NULL Pointer exception...
726 if (scProgramCurrent)
728 if (scProgramCurrent->usesT0)
730 #ifdef TEXTURECACHE_TEST
731 unsigned t = ticksGetTicks();
732 TextureCache_Update(0);
733 TextureCacheTime += (ticksGetTicks() - t);
735 TextureCache_Update(0);
737 SC_ForceUniform2f(uTexOffset[0], gSP.textureTile[0]->fuls, gSP.textureTile[0]->fult);
738 SC_ForceUniform2f(uCacheShiftScale[0], cache.current[0]->shiftScaleS, cache.current[0]->shiftScaleT);
739 SC_ForceUniform2f(uCacheScale[0], cache.current[0]->scaleS, cache.current[0]->scaleT);
740 SC_ForceUniform2f(uCacheOffset[0], cache.current[0]->offsetS, cache.current[0]->offsetT);
742 //else TextureCache_ActivateDummy(0);
744 //Note: enabling dummies makes some F-zero X textures flicker.... strange.
746 if (scProgramCurrent->usesT1)
748 #ifdef TEXTURECACHE_TEST
749 unsigned t = ticksGetTicks();
750 TextureCache_Update(1);
751 TextureCacheTime += (ticksGetTicks() - t);
753 TextureCache_Update(1);
755 SC_ForceUniform2f(uTexOffset[1], gSP.textureTile[1]->fuls, gSP.textureTile[1]->fult);
756 SC_ForceUniform2f(uCacheShiftScale[1], cache.current[1]->shiftScaleS, cache.current[1]->shiftScaleT);
757 SC_ForceUniform2f(uCacheScale[1], cache.current[1]->scaleS, cache.current[1]->scaleT);
758 SC_ForceUniform2f(uCacheOffset[1], cache.current[1]->offsetS, cache.current[1]->offsetT);
760 //else TextureCache_ActivateDummy(1);
764 if ((gDP.changed & CHANGED_FOGCOLOR) && config.enableFog)
765 SC_SetUniform4fv(uFogColor, &gDP.fogColor.r );
767 if (gDP.changed & CHANGED_ENV_COLOR)
768 SC_SetUniform4fv(uEnvColor, &gDP.envColor.r);
770 if (gDP.changed & CHANGED_PRIM_COLOR)
772 SC_SetUniform4fv(uPrimColor, &gDP.primColor.r);
773 SC_SetUniform1f(uPrimLODFrac, gDP.primColor.l);
776 if ((gDP.changed & CHANGED_RENDERMODE) || (gDP.changed & CHANGED_CYCLETYPE))
778 #ifndef OLD_BLENDMODE
781 if ((gDP.otherMode.forceBlender) &&
782 (gDP.otherMode.cycleType != G_CYC_COPY) &&
783 (gDP.otherMode.cycleType != G_CYC_FILL) &&
784 !(gDP.otherMode.alphaCvgSel))
786 glEnable( GL_BLEND );
788 switch (gDP.otherMode.l >> 16)
792 glBlendFunc( GL_ONE, GL_ONE );
794 case 0x0C08: // 1080 Sky
795 case 0x0F0A: // Used LOTS of places
796 glBlendFunc( GL_ONE, GL_ZERO );
799 case 0x0040: // Fzero
800 case 0xC810: // Blends fog
801 case 0xC811: // Blends fog
802 case 0x0C18: // Standard interpolated blend
803 case 0x0C19: // Used for antialiasing
804 case 0x0050: // Standard interpolated blend
805 case 0x0055: // Used for antialiasing
806 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
809 case 0x0FA5: // Seems to be doing just blend color - maybe combiner can be used for this?
810 case 0x5055: // Used in Paper Mario intro, I'm not sure if this is right...
811 glBlendFunc( GL_ZERO, GL_ONE );
815 LOG(LOG_VERBOSE, "Unhandled blend mode=%x", gDP.otherMode.l >> 16);
816 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
822 glDisable( GL_BLEND );
825 if (gDP.otherMode.cycleType == G_CYC_FILL)
827 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
828 glEnable( GL_BLEND );
833 gDP.changed &= CHANGED_TILE | CHANGED_TMEM;
834 gSP.changed &= CHANGED_TEXTURE | CHANGED_MATRIX;
837 void OGL_DrawTriangle(SPVertex *vertices, int v0, int v1, int v2)
842 void OGL_AddTriangle(int v0, int v1, int v2)
844 OGL.triangles.elements[OGL.triangles.num++] = v0;
845 OGL.triangles.elements[OGL.triangles.num++] = v1;
846 OGL.triangles.elements[OGL.triangles.num++] = v2;
849 void OGL_SetColorArray()
851 if (scProgramCurrent->usesCol)
852 glEnableVertexAttribArray(SC_COLOR);
854 glDisableVertexAttribArray(SC_COLOR);
857 void OGL_SetTexCoordArrays()
859 if (scProgramCurrent->usesT0)
860 glEnableVertexAttribArray(SC_TEXCOORD0);
862 glDisableVertexAttribArray(SC_TEXCOORD0);
864 if (scProgramCurrent->usesT1)
865 glEnableVertexAttribArray(SC_TEXCOORD1);
867 glDisableVertexAttribArray(SC_TEXCOORD1);
870 void OGL_DrawTriangles()
872 if (OGL.renderingToTexture && config.ignoreOffscreenRendering)
874 OGL.triangles.num = 0;
878 if (OGL.triangles.num == 0) return;
880 if ((config.updateMode == SCREEN_UPDATE_AT_1ST_PRIMITIVE) && OGL.screenUpdate)
883 if (gSP.changed || gDP.changed)
886 if (OGL.renderState != RS_TRIANGLE || scProgramChanged)
889 OGL_SetTexCoordArrays();
890 glDisableVertexAttribArray(SC_TEXCOORD1);
891 SC_ForceUniform1f(uRenderState, RS_TRIANGLE);
894 if (OGL.renderState != RS_TRIANGLE)
896 #ifdef RENDERSTATE_TEST
899 glVertexAttribPointer(SC_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(SPVertex), &OGL.triangles.vertices[0].x);
900 glVertexAttribPointer(SC_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(SPVertex), &OGL.triangles.vertices[0].r);
901 glVertexAttribPointer(SC_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, sizeof(SPVertex), &OGL.triangles.vertices[0].s);
903 OGL_UpdateCullFace();
904 OGL_UpdateViewport();
905 glEnable(GL_SCISSOR_TEST);
906 OGL.renderState = RS_TRIANGLE;
909 glDrawElements(GL_TRIANGLES, OGL.triangles.num, GL_UNSIGNED_BYTE, OGL.triangles.elements);
910 OGL.triangles.num = 0;
912 #ifdef __TRIBUFFER_OPT
917 void OGL_DrawLine(int v0, int v1, float width )
919 if (OGL.renderingToTexture && config.ignoreOffscreenRendering) return;
921 if ((config.updateMode == SCREEN_UPDATE_AT_1ST_PRIMITIVE) && OGL.screenUpdate)
924 if (gSP.changed || gDP.changed)
927 if (OGL.renderState != RS_LINE || scProgramChanged)
929 #ifdef RENDERSTATE_TEST
933 glDisableVertexAttribArray(SC_TEXCOORD0);
934 glDisableVertexAttribArray(SC_TEXCOORD1);
935 glVertexAttribPointer(SC_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(SPVertex), &OGL.triangles.vertices[0].x);
936 glVertexAttribPointer(SC_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(SPVertex), &OGL.triangles.vertices[0].r);
938 SC_ForceUniform1f(uRenderState, RS_LINE);
939 OGL_UpdateCullFace();
940 OGL_UpdateViewport();
941 OGL.renderState = RS_LINE;
944 unsigned short elem[2];
947 glLineWidth( width * OGL.scaleX );
948 glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, elem);
951 void OGL_DrawRect( int ulx, int uly, int lrx, int lry, float *color)
953 if (OGL.renderingToTexture && config.ignoreOffscreenRendering) return;
955 if ((config.updateMode == SCREEN_UPDATE_AT_1ST_PRIMITIVE) && OGL.screenUpdate)
958 if (gSP.changed || gDP.changed)
961 if (OGL.renderState != RS_RECT || scProgramChanged)
963 glDisableVertexAttribArray(SC_COLOR);
964 glDisableVertexAttribArray(SC_TEXCOORD0);
965 glDisableVertexAttribArray(SC_TEXCOORD1);
966 SC_ForceUniform1f(uRenderState, RS_RECT);
969 if (OGL.renderState != RS_RECT)
971 #ifdef RENDERSTATE_TEST
974 glVertexAttrib4f(SC_POSITION, 0, 0, gSP.viewport.nearz, 1.0);
975 glVertexAttribPointer(SC_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), &OGL.rect[0].x);
976 OGL.renderState = RS_RECT;
979 glViewport(config.framebuffer.xpos, config.framebuffer.ypos, config.framebuffer.width, config.framebuffer.height );
980 glDisable(GL_SCISSOR_TEST);
981 glDisable(GL_CULL_FACE);
983 OGL.rect[0].x = (float) ulx * (2.0f * VI.rwidth) - 1.0;
984 OGL.rect[0].y = (float) uly * (-2.0f * VI.rheight) + 1.0;
985 OGL.rect[1].x = (float) (lrx+1) * (2.0f * VI.rwidth) - 1.0;
986 OGL.rect[1].y = OGL.rect[0].y;
987 OGL.rect[2].x = OGL.rect[0].x;
988 OGL.rect[2].y = (float) (lry+1) * (-2.0f * VI.rheight) + 1.0;
989 OGL.rect[3].x = OGL.rect[1].x;
990 OGL.rect[3].y = OGL.rect[2].y;
992 glVertexAttrib4fv(SC_COLOR, color);
993 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
994 glEnable(GL_SCISSOR_TEST);
995 OGL_UpdateViewport();
999 void OGL_DrawTexturedRect( float ulx, float uly, float lrx, float lry, float uls, float ult, float lrs, float lrt, bool flip )
1001 if (config.hackBanjoTooie)
1003 if (gDP.textureImage.width == gDP.colorImage.width &&
1004 gDP.textureImage.format == G_IM_FMT_CI &&
1005 gDP.textureImage.size == G_IM_SIZ_8b)
1011 if (OGL.renderingToTexture && config.ignoreOffscreenRendering) return;
1013 if ((config.updateMode == SCREEN_UPDATE_AT_1ST_PRIMITIVE) && OGL.screenUpdate)
1016 if (gSP.changed || gDP.changed)
1019 if (OGL.renderState != RS_TEXTUREDRECT || scProgramChanged)
1021 glDisableVertexAttribArray(SC_COLOR);
1022 OGL_SetTexCoordArrays();
1023 SC_ForceUniform1f(uRenderState, RS_TEXTUREDRECT);
1026 if (OGL.renderState != RS_TEXTUREDRECT)
1028 #ifdef RENDERSTATE_TEST
1031 glVertexAttrib4f(SC_COLOR, 0, 0, 0, 0);
1032 glVertexAttrib4f(SC_POSITION, 0, 0, (gDP.otherMode.depthSource == G_ZS_PRIM) ? gDP.primDepth.z : gSP.viewport.nearz, 1.0);
1033 glVertexAttribPointer(SC_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), &OGL.rect[0].x);
1034 glVertexAttribPointer(SC_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), &OGL.rect[0].s0);
1035 glVertexAttribPointer(SC_TEXCOORD1, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), &OGL.rect[0].s1);
1036 OGL.renderState = RS_TEXTUREDRECT;
1039 glViewport(config.framebuffer.xpos, config.framebuffer.ypos, config.framebuffer.width, config.framebuffer.height);
1040 glDisable(GL_CULL_FACE);
1042 OGL.rect[0].x = (float) ulx * (2.0f * VI.rwidth) - 1.0f;
1043 OGL.rect[0].y = (float) uly * (-2.0f * VI.rheight) + 1.0f;
1044 OGL.rect[1].x = (float) (lrx) * (2.0f * VI.rwidth) - 1.0f;
1045 OGL.rect[1].y = OGL.rect[0].y;
1046 OGL.rect[2].x = OGL.rect[0].x;
1047 OGL.rect[2].y = (float) (lry) * (-2.0f * VI.rheight) + 1.0f;
1048 OGL.rect[3].x = OGL.rect[1].x;
1049 OGL.rect[3].y = OGL.rect[2].y;
1051 if (scProgramCurrent->usesT0 && cache.current[0] && gSP.textureTile[0])
1053 OGL.rect[0].s0 = uls * cache.current[0]->shiftScaleS - gSP.textureTile[0]->fuls;
1054 OGL.rect[0].t0 = ult * cache.current[0]->shiftScaleT - gSP.textureTile[0]->fult;
1055 OGL.rect[3].s0 = (lrs + 1.0f) * cache.current[0]->shiftScaleS - gSP.textureTile[0]->fuls;
1056 OGL.rect[3].t0 = (lrt + 1.0f) * cache.current[0]->shiftScaleT - gSP.textureTile[0]->fult;
1058 if ((cache.current[0]->maskS) && !(cache.current[0]->mirrorS) && (fmod( OGL.rect[0].s0, cache.current[0]->width ) == 0.0f))
1060 OGL.rect[3].s0 -= OGL.rect[0].s0;
1061 OGL.rect[0].s0 = 0.0f;
1064 if ((cache.current[0]->maskT) && !(cache.current[0]->mirrorT) && (fmod( OGL.rect[0].t0, cache.current[0]->height ) == 0.0f))
1066 OGL.rect[3].t0 -= OGL.rect[0].t0;
1067 OGL.rect[0].t0 = 0.0f;
1070 glActiveTexture( GL_TEXTURE0);
1071 if ((OGL.rect[0].s0 >= 0.0f) && (OGL.rect[3].s0 <= cache.current[0]->width))
1072 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
1074 if ((OGL.rect[0].t0 >= 0.0f) && (OGL.rect[3].t0 <= cache.current[0]->height))
1075 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
1077 OGL.rect[0].s0 *= cache.current[0]->scaleS;
1078 OGL.rect[0].t0 *= cache.current[0]->scaleT;
1079 OGL.rect[3].s0 *= cache.current[0]->scaleS;
1080 OGL.rect[3].t0 *= cache.current[0]->scaleT;
1083 if (scProgramCurrent->usesT1 && cache.current[1] && gSP.textureTile[1])
1085 OGL.rect[0].s1 = uls * cache.current[1]->shiftScaleS - gSP.textureTile[1]->fuls;
1086 OGL.rect[0].t1 = ult * cache.current[1]->shiftScaleT - gSP.textureTile[1]->fult;
1087 OGL.rect[3].s1 = (lrs + 1.0f) * cache.current[1]->shiftScaleS - gSP.textureTile[1]->fuls;
1088 OGL.rect[3].t1 = (lrt + 1.0f) * cache.current[1]->shiftScaleT - gSP.textureTile[1]->fult;
1090 if ((cache.current[1]->maskS) && (fmod( OGL.rect[0].s1, cache.current[1]->width ) == 0.0f) && !(cache.current[1]->mirrorS))
1092 OGL.rect[3].s1 -= OGL.rect[0].s1;
1093 OGL.rect[0].s1 = 0.0f;
1096 if ((cache.current[1]->maskT) && (fmod( OGL.rect[0].t1, cache.current[1]->height ) == 0.0f) && !(cache.current[1]->mirrorT))
1098 OGL.rect[3].t1 -= OGL.rect[0].t1;
1099 OGL.rect[0].t1 = 0.0f;
1102 glActiveTexture( GL_TEXTURE1);
1103 if ((OGL.rect[0].s1 == 0.0f) && (OGL.rect[3].s1 <= cache.current[1]->width))
1104 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
1106 if ((OGL.rect[0].t1 == 0.0f) && (OGL.rect[3].t1 <= cache.current[1]->height))
1107 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
1109 OGL.rect[0].s1 *= cache.current[1]->scaleS;
1110 OGL.rect[0].t1 *= cache.current[1]->scaleT;
1111 OGL.rect[3].s1 *= cache.current[1]->scaleS;
1112 OGL.rect[3].t1 *= cache.current[1]->scaleT;
1115 if ((gDP.otherMode.cycleType == G_CYC_COPY) && !config.texture.forceBilinear)
1117 glActiveTexture(GL_TEXTURE0);
1118 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
1119 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
1124 OGL.rect[1].s0 = OGL.rect[0].s0;
1125 OGL.rect[1].t0 = OGL.rect[3].t0;
1126 OGL.rect[1].s1 = OGL.rect[0].s1;
1127 OGL.rect[1].t1 = OGL.rect[3].t1;
1128 OGL.rect[2].s0 = OGL.rect[3].s0;
1129 OGL.rect[2].t0 = OGL.rect[0].t0;
1130 OGL.rect[2].s1 = OGL.rect[3].s1;
1131 OGL.rect[2].t1 = OGL.rect[0].t1;
1135 OGL.rect[1].s0 = OGL.rect[3].s0;
1136 OGL.rect[1].t0 = OGL.rect[0].t0;
1137 OGL.rect[1].s1 = OGL.rect[3].s1;
1138 OGL.rect[1].t1 = OGL.rect[0].t1;
1139 OGL.rect[2].s0 = OGL.rect[0].s0;
1140 OGL.rect[2].t0 = OGL.rect[3].t0;
1141 OGL.rect[2].s1 = OGL.rect[0].s1;
1142 OGL.rect[2].t1 = OGL.rect[3].t1;
1145 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1146 OGL_UpdateViewport();
1149 void OGL_ClearDepthBuffer()
1151 if (OGL.renderingToTexture && config.ignoreOffscreenRendering) return;
1153 if ((config.updateMode == SCREEN_UPDATE_AT_1ST_PRIMITIVE) && OGL.screenUpdate)
1156 //float depth = 1.0 - (gDP.fillColor.z / ((float)0x3FFF)); // broken on OMAP3
1157 float depth = gDP.fillColor.z ;
1159 /////// paulscode, graphics bug-fixes
1160 glDisable( GL_SCISSOR_TEST );
1161 glDepthMask( GL_TRUE ); // fixes side-bar graphics glitches
1162 // glClearDepthf( depth ); // broken on Qualcomm Adreno
1163 glClearDepthf( 1.0f ); // fixes missing graphics on Qualcomm Adreno
1164 glClearColor( 0, 0, 0, 1 );
1165 glClear( GL_DEPTH_BUFFER_BIT );
1166 OGL_UpdateDepthUpdate();
1167 glEnable( GL_SCISSOR_TEST );
1171 void OGL_ClearColorBuffer( float *color )
1173 if (OGL.renderingToTexture && config.ignoreOffscreenRendering) return;
1175 if ((config.updateMode == SCREEN_UPDATE_AT_1ST_PRIMITIVE) && OGL.screenUpdate)
1178 glScissor(config.framebuffer.xpos, config.framebuffer.ypos, config.framebuffer.width, config.framebuffer.height);
1179 glClearColor( color[0], color[1], color[2], color[3] );
1180 glClear( GL_COLOR_BUFFER_BIT );
1181 OGL_UpdateScissor();
1185 int OGL_CheckError()
1187 GLenum e = glGetError();
1188 if (e != GL_NO_ERROR)
1190 printf("GL Error: ");
1193 case GL_INVALID_ENUM: printf("INVALID ENUM"); break;
1194 case GL_INVALID_VALUE: printf("INVALID VALUE"); break;
1195 case GL_INVALID_OPERATION: printf("INVALID OPERATION"); break;
1196 case GL_OUT_OF_MEMORY: printf("OUT OF MEMORY"); break;
1204 void OGL_UpdateFrameTime()
1206 unsigned ticks = ticksGetTicks();
1207 static unsigned lastFrameTicks = 0;
1208 for(int i = OGL_FRAMETIME_NUM-1; i > 0; i--) OGL.frameTime[i] = OGL.frameTime[i-1];
1209 OGL.frameTime[0] = ticks - lastFrameTicks;
1210 lastFrameTicks = ticks;
1213 void OGL_SwapBuffers()
1215 //OGL_DrawTriangles();
1216 scProgramChanged = 0;
1218 static int frames = 0;
1219 static unsigned lastTicks = 0;
1220 unsigned ticks = ticksGetTicks();
1223 if (ticks >= (lastTicks + 1000))
1226 float fps = 1000.0f * (float) frames / (ticks - lastTicks);
1227 LOG(LOG_MINIMAL, "fps = %.2f \n", fps);
1228 LOG(LOG_MINIMAL, "skipped frame = %i of %i \n", OGL.frameSkipped, frames + OGL.frameSkipped);
1230 OGL.frameSkipped = 0;
1233 LOG(LOG_MINIMAL, "time spent in draw calls per frame = %.2f ms\n", (float)TotalDrawTime / frames);
1234 LOG(LOG_MINIMAL, "average draw calls per frame = %.0f\n", (float)TotalDrawCalls / frames);
1235 LOG(LOG_MINIMAL, "average vertices per draw call = %.2f\n", (float)TotalTriangles / TotalDrawCalls);
1242 LOG(LOG_MINIMAL, "average shader changes per frame = %f\n", (float)ProgramSwaps / frames);
1246 #ifdef TEXTURECACHE_TEST
1247 LOG(LOG_MINIMAL, "texture cache time per frame: %.2f ms\n", (float)TextureCacheTime/ frames);
1248 LOG(LOG_MINIMAL, "texture cache per frame: hits=%.2f misses=%.2f\n", (float)cache.hits / frames,
1249 (float)cache.misses / frames);
1250 cache.hits = cache.misses = 0;
1251 TextureCacheTime = 0;
1261 u32 profileTicks = ticksGetTicks();
1262 static u32 profileLastTicks = 0;
1263 if (profileTicks >= (profileLastTicks + 5000))
1265 LOG(LOG_MINIMAL, "GBI PROFILE DATA: %i ms \n", profileTicks - profileLastTicks);
1266 LOG(LOG_MINIMAL, "=========================================================\n");
1267 GBI_ProfilePrint(stdout);
1268 LOG(LOG_MINIMAL, "=========================================================\n");
1270 profileLastTicks = profileTicks;
1274 if (config.framebuffer.enable)
1276 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1277 glClearColor( 0, 0, 0, 1 );
1278 glClear( GL_COLOR_BUFFER_BIT );
1280 glUseProgram(OGL.defaultProgram);
1281 glDisable(GL_SCISSOR_TEST);
1282 glDisable(GL_DEPTH_TEST);
1283 glViewport(config.window.xpos, config.window.ypos, config.window.width, config.window.height);
1285 static const float vert[] =
1287 -1.0, -1.0, +0.0, +0.0,
1288 +1.0, -1.0, +1.0, +0.0,
1289 -1.0, +1.0, +0.0, +1.0,
1290 +1.0, +1.0, +1.0, +1.0
1293 glActiveTexture(GL_TEXTURE0);
1294 glBindTexture(GL_TEXTURE_2D, OGL.framebuffer.color_buffer);
1295 if (config.framebuffer.bilinear)
1297 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1298 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1302 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1303 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1306 glEnableVertexAttribArray(0);
1307 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (float*)vert);
1308 glEnableVertexAttribArray(1);
1309 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (float*)vert + 2);
1310 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1312 Android_JNI_SwapWindow(); // paulscode, fix for black-screen bug
1314 glBindFramebuffer(GL_FRAMEBUFFER, OGL.framebuffer.fb);
1315 OGL_UpdateViewport();
1316 if (scProgramCurrent) glUseProgram(scProgramCurrent->program);
1317 OGL.renderState = RS_NONE;
1321 Android_JNI_SwapWindow(); // paulscode, fix for black-screen bug
1324 // if emulator defined a render callback function, call it before
1326 if (renderCallback) (*renderCallback)();
1328 OGL.screenUpdate = false;
1330 if (config.forceBufferClear)
1332 /////// paulscode, graphics bug-fixes
1333 float depth = gDP.fillColor.z ;
1334 glDisable( GL_SCISSOR_TEST );
1335 glDepthMask( GL_TRUE ); // fixes side-bar graphics glitches
1336 // glClearDepthf( depth ); // broken on Qualcomm Adreno
1337 glClearDepthf( 1.0f ); // fixes missing graphics on Qualcomm Adreno
1338 glClearColor( 0, 0, 0, 1 );
1339 glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );
1340 OGL_UpdateDepthUpdate();
1341 glEnable( GL_SCISSOR_TEST );
1347 void OGL_ReadScreen( void *dest, int *width, int *height )
1350 *width = config.framebuffer.width;
1352 *height = config.framebuffer.height;
1357 glReadPixels( config.framebuffer.xpos, config.framebuffer.ypos,
1358 config.framebuffer.width, config.framebuffer.height,
1359 GL_RGBA, GL_UNSIGNED_BYTE, dest );