DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/output/output_opengl.cpp
00001 #include <sys/types.h>
00002 #include <assert.h>
00003 #include <math.h>
00004 
00005 #include "dosbox.h"
00006 #include <output/output_opengl.h>
00007 
00008 #include "sdlmain.h"
00009 
00010 using namespace std;
00011 
00012 #if C_OPENGL
00013 PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL;
00014 PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL;
00015 PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL;
00016 PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL;
00017 PFNGLMAPBUFFERARBPROC glMapBufferARB = NULL;
00018 PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL;
00019 
00020 #if C_OPENGL && !defined(C_SDL2) && DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
00021 extern unsigned int SDLDrawGenFontTextureUnitPerRow;
00022 extern unsigned int SDLDrawGenFontTextureRows;
00023 extern unsigned int SDLDrawGenFontTextureWidth;
00024 extern unsigned int SDLDrawGenFontTextureHeight;
00025 extern GLuint SDLDrawGenFontTexture;
00026 extern bool SDLDrawGenFontTextureInit;
00027 #endif
00028 
00029 SDL_OpenGL sdl_opengl;
00030 
00031 int Voodoo_OGL_GetWidth();
00032 int Voodoo_OGL_GetHeight();
00033 bool Voodoo_OGL_Active();
00034 
00035 static SDL_Surface* SetupSurfaceScaledOpenGL(Bit32u sdl_flags, Bit32u bpp) 
00036 {
00037     Bit16u fixedWidth;
00038     Bit16u fixedHeight;
00039     Bit16u windowWidth;
00040     Bit16u windowHeight;
00041 
00042     if (sdl.desktop.prevent_fullscreen) /* 3Dfx openGL do not allow resize */
00043         sdl_flags &= ~((unsigned int)SDL_RESIZABLE);
00044 
00045     if (sdl.desktop.want_type == SCREEN_OPENGL)
00046         sdl_flags |= (unsigned int)SDL_OPENGL;
00047 
00048     if (sdl.desktop.fullscreen) 
00049     {
00050         fixedWidth = sdl.desktop.full.fixed ? sdl.desktop.full.width : 0;
00051         fixedHeight = sdl.desktop.full.fixed ? sdl.desktop.full.height : 0;
00052         sdl_flags |= (unsigned int)(SDL_FULLSCREEN | SDL_HWSURFACE);
00053     }
00054     else 
00055     {
00056         fixedWidth = sdl.desktop.window.width;
00057         fixedHeight = sdl.desktop.window.height;
00058         sdl_flags |= (unsigned int)SDL_HWSURFACE;
00059     }
00060 
00061     if (fixedWidth == 0 || fixedHeight == 0) 
00062     {
00063         Bitu consider_height = menu.maxwindow ? currentWindowHeight : 0;
00064         Bitu consider_width = menu.maxwindow ? currentWindowWidth : 0;
00065         int final_height = max(consider_height, userResizeWindowHeight);
00066         int final_width = max(consider_width, userResizeWindowWidth);
00067 
00068         fixedWidth = final_width;
00069         fixedHeight = final_height;
00070     }
00071 
00072 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
00073     /* scale the menu bar if the window is large enough */
00074     {
00075         int cw = fixedWidth, ch = fixedHeight;
00076         int scale = 1;
00077 
00078         if (cw == 0)
00079             cw = (Bit16u)(sdl.draw.width*sdl.draw.scalex);
00080         if (ch == 0)
00081             ch = (Bit16u)(sdl.draw.height*sdl.draw.scaley);
00082 
00083         while ((cw / scale) >= (640 * 2) && (ch / scale) >= (400 * 2))
00084             scale++;
00085 
00086         LOG_MSG("menuScale=%d", scale);
00087         mainMenu.setScale((unsigned int)scale);
00088 
00089         if (mainMenu.isVisible())
00090             fixedHeight -= mainMenu.menuBox.h;
00091     }
00092 #endif
00093 
00094     sdl.clip.x = 0; sdl.clip.y = 0;
00095     if (Voodoo_OGL_GetWidth() != 0 && Voodoo_OGL_GetHeight() != 0 && Voodoo_OGL_Active() && sdl.desktop.prevent_fullscreen)
00096     { 
00097         /* 3Dfx openGL do not allow resize */
00098         sdl.clip.w = windowWidth = (Bit16u)Voodoo_OGL_GetWidth();
00099         sdl.clip.h = windowHeight = (Bit16u)Voodoo_OGL_GetHeight();
00100     }
00101     else if (fixedWidth && fixedHeight) 
00102     {
00103         sdl.clip.w = windowWidth = fixedWidth;
00104         sdl.clip.h = windowHeight = fixedHeight;
00105         if (render.aspect) aspectCorrectFitClip(sdl.clip.w, sdl.clip.h, sdl.clip.x, sdl.clip.y, fixedWidth, fixedHeight);
00106     }
00107     else 
00108     {
00109         windowWidth = (Bit16u)(sdl.draw.width * sdl.draw.scalex);
00110         windowHeight = (Bit16u)(sdl.draw.height * sdl.draw.scaley);
00111         if (render.aspect) aspectCorrectExtend(windowWidth, windowHeight);
00112         sdl.clip.w = windowWidth; sdl.clip.h = windowHeight;
00113     }
00114 
00115     LOG(LOG_MISC, LOG_DEBUG)("GFX_SetSize OpenGL window=%ux%u clip=x,y,w,h=%d,%d,%d,%d",
00116         (unsigned int)windowWidth,
00117         (unsigned int)windowHeight,
00118         (unsigned int)sdl.clip.x,
00119         (unsigned int)sdl.clip.y,
00120         (unsigned int)sdl.clip.w,
00121         (unsigned int)sdl.clip.h);
00122 
00123 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
00124     if (mainMenu.isVisible()) 
00125     {
00126         windowHeight += mainMenu.menuBox.h;
00127         sdl.clip.y += mainMenu.menuBox.h;
00128     }
00129 #endif
00130 
00131     sdl.surface = SDL_SetVideoMode(windowWidth, windowHeight, (int)bpp, (unsigned int)sdl_flags);
00132     sdl.deferred_resize = false;
00133     sdl.must_redraw_all = true;
00134 
00135     /* There seems to be a problem with MesaGL in Linux/X11 where
00136     * the first swap buffer we do is misplaced according to the
00137     * previous window size.
00138     *
00139     * NTS: This seems to have been fixed, which is why this is
00140     *      commented out. I guess not calling GFX_SetSize()
00141     *      with a 0x0 widthxheight helps! */
00142     //    sdl.gfx_force_redraw_count = 2;
00143 
00144     UpdateWindowDimensions();
00145     GFX_LogSDLState();
00146 
00147 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
00148     mainMenu.screenWidth = (size_t)(sdl.surface->w);
00149     mainMenu.updateRect();
00150     mainMenu.setRedraw();
00151 #endif
00152 
00153     return sdl.surface;
00154 }
00155 
00156 // output API below
00157 
00158 void OUTPUT_OPENGL_Initialize()
00159 {
00160     memset(&sdl_opengl, 0, sizeof(sdl_opengl));
00161 }
00162 
00163 void OUTPUT_OPENGL_Select()
00164 {
00165     sdl.desktop.want_type = SCREEN_OPENGL;
00166     render.aspectOffload = true;
00167 
00168 #if defined(WIN32) && !defined(C_SDL2)
00169     SDL1_hax_inhibit_WM_PAINT = 0;
00170 #endif
00171 }
00172 
00173 Bitu OUTPUT_OPENGL_GetBestMode(Bitu flags)
00174 {
00175     if (!(flags & GFX_CAN_32)) return 0; // OpenGL requires 32-bit output mode
00176     flags |= GFX_SCALING;
00177     flags &= ~(GFX_CAN_8 | GFX_CAN_15 | GFX_CAN_16);
00178     return flags;
00179 }
00180 
00181 Bitu OUTPUT_OPENGL_SetSize()
00182 {
00183     Bitu retFlags = 0;
00184 
00185     /* NTS: Apparently calling glFinish/glFlush before setup causes a segfault within
00186     *      the OpenGL library on Mac OS X. */
00187     if (sdl_opengl.inited)
00188     {
00189         glFinish();
00190         glFlush();
00191     }
00192 
00193     if (sdl_opengl.pixel_buffer_object)
00194     {
00195         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
00196         if (sdl_opengl.buffer) glDeleteBuffersARB(1, &sdl_opengl.buffer);
00197     }
00198     else if (sdl_opengl.framebuf)
00199     {
00200         free(sdl_opengl.framebuf);
00201     }
00202     sdl_opengl.framebuf = 0;
00203 
00204     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
00205 #if SDL_VERSION_ATLEAST(1, 2, 11)
00206     Section_prop* sec = static_cast<Section_prop*>(control->GetSection("vsync"));
00207     if (sec)
00208         SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, (!strcmp(sec->Get_string("vsyncmode"), "host")) ? 1 : 0);
00209 #endif
00210 
00211     SetupSurfaceScaledOpenGL(SDL_RESIZABLE, 0);
00212     if (!sdl.surface || sdl.surface->format->BitsPerPixel < 15)
00213     {
00214         LOG_MSG("SDL:OPENGL:Can't open drawing surface, are you running in 16bpp(or higher) mode?");
00215         return 0;
00216     }
00217 
00218     glFinish();
00219     glFlush();
00220 
00221     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &sdl_opengl.max_texsize);
00222 
00223     Bitu adjTexWidth = sdl.draw.width;
00224     Bitu adjTexHeight = sdl.draw.height;
00225 #if C_XBRZ
00226     // we do the same as with Direct3D: precreate pixel buffer adjusted for xBRZ
00227     if (sdl_xbrz.enable && xBRZ_SetScaleParameters(adjTexWidth, adjTexHeight, sdl.clip.w, sdl.clip.h))
00228     {
00229         adjTexWidth = adjTexWidth * sdl_xbrz.scale_factor;
00230         adjTexHeight = adjTexHeight * sdl_xbrz.scale_factor;
00231     }
00232 #endif
00233 
00234     int texsize = 2 << int_log2(adjTexWidth > adjTexHeight ? adjTexWidth : adjTexHeight);
00235     if (texsize > sdl_opengl.max_texsize) 
00236     {
00237         LOG_MSG("SDL:OPENGL:No support for texturesize of %d (max size is %d), falling back to surface", texsize, sdl_opengl.max_texsize);
00238         return 0;
00239     }
00240 
00241     /* Create the texture and display list */
00242     if (sdl_opengl.pixel_buffer_object) 
00243     {
00244         glGenBuffersARB(1, &sdl_opengl.buffer);
00245         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, sdl_opengl.buffer);
00246         glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, adjTexWidth*adjTexHeight * 4, NULL, GL_STREAM_DRAW_ARB);
00247         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
00248     }
00249     else
00250     {
00251         sdl_opengl.framebuf = calloc(adjTexWidth*adjTexHeight, 4); //32 bit color
00252     }
00253     sdl_opengl.pitch = adjTexWidth * 4;
00254 
00255     glBindTexture(GL_TEXTURE_2D, 0);
00256 
00257 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
00258     if (SDLDrawGenFontTextureInit)
00259     {
00260         glDeleteTextures(1, &SDLDrawGenFontTexture);
00261         SDLDrawGenFontTexture = (GLuint)(~0UL);
00262         SDLDrawGenFontTextureInit = 0;
00263     }
00264 #endif
00265 
00266     glViewport(0, 0, sdl.surface->w, sdl.surface->h);
00267     glDeleteTextures(1, &sdl_opengl.texture);
00268     glGenTextures(1, &sdl_opengl.texture);
00269     glBindTexture(GL_TEXTURE_2D, sdl_opengl.texture);
00270     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00271     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, 0);
00272 
00273     // No borders
00274     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00275     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00276 
00277     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, sdl_opengl.bilinear ? GL_LINEAR : GL_NEAREST);
00278     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, sdl_opengl.bilinear ? GL_LINEAR : GL_NEAREST);
00279 
00280     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texsize, texsize, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, 0);
00281 
00282     sdl_opengl.menudraw_countdown = 2; // two GL buffers
00283     sdl_opengl.clear_countdown = 2; // two GL buffers
00284 
00285     glClearColor(0.0, 0.0, 0.0, 1.0);
00286     glClear(GL_COLOR_BUFFER_BIT);
00287     // SDL_GL_SwapBuffers();
00288     // glClear(GL_COLOR_BUFFER_BIT);
00289     glShadeModel(GL_FLAT);
00290     glBlendFunc(GL_ONE, GL_ZERO);
00291     glDisable(GL_DEPTH_TEST);
00292     glDisable(GL_LIGHTING);
00293     glDisable(GL_BLEND);
00294     glDisable(GL_CULL_FACE);
00295     glDisable(GL_ALPHA_TEST);
00296     glDisable(GL_FOG);
00297     glDisable(GL_SCISSOR_TEST);
00298     glDisable(GL_STENCIL_TEST);
00299     glEnable(GL_TEXTURE_2D);
00300 
00301     glMatrixMode(GL_MODELVIEW);
00302     glLoadIdentity();
00303 
00304     glMatrixMode(GL_PROJECTION);
00305     glLoadIdentity();
00306     glOrtho(0, sdl.surface->w, sdl.surface->h, 0, -1, 1);
00307 
00308     glMatrixMode(GL_TEXTURE);
00309     glLoadIdentity();
00310     glScaled(1.0 / texsize, 1.0 / texsize, 1.0);
00311 
00312     // if (glIsList(sdl_opengl.displaylist)) 
00313     //   glDeleteLists(sdl_opengl.displaylist, 1);
00314     // sdl_opengl.displaylist = glGenLists(1);
00315     sdl_opengl.displaylist = 1;
00316 
00317     glNewList(sdl_opengl.displaylist, GL_COMPILE);
00318     glBindTexture(GL_TEXTURE_2D, sdl_opengl.texture);
00319 
00320     glBegin(GL_QUADS);
00321 
00322     glTexCoord2i(0, 0); glVertex2i(sdl.clip.x, sdl.clip.y); // lower left
00323     glTexCoord2i(adjTexWidth, 0); glVertex2i(sdl.clip.x + sdl.clip.w, sdl.clip.y); // lower right
00324     glTexCoord2i(adjTexWidth, adjTexHeight); glVertex2i(sdl.clip.x + sdl.clip.w, sdl.clip.y + sdl.clip.h); // upper right
00325     glTexCoord2i(0, adjTexHeight); glVertex2i(sdl.clip.x, sdl.clip.y + sdl.clip.h); // upper left
00326 
00327     glEnd();
00328     glEndList();
00329 
00330     glBindTexture(GL_TEXTURE_2D, 0);
00331 
00332 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
00333     void GFX_DrawSDLMenu(DOSBoxMenu &menu, DOSBoxMenu::displaylist &dl);
00334     mainMenu.setRedraw();
00335     GFX_DrawSDLMenu(mainMenu, mainMenu.display_list);
00336 
00337     // FIXME: Why do we have to reinitialize the font texture?
00338     // if (!SDLDrawGenFontTextureInit) {
00339     GLuint err = 0;
00340 
00341     glGetError(); /* read and discard last error */
00342 
00343     SDLDrawGenFontTexture = (GLuint)(~0UL);
00344     glGenTextures(1, &SDLDrawGenFontTexture);
00345     if (SDLDrawGenFontTexture == (GLuint)(~0UL) || (err = glGetError()) != 0)
00346     {
00347         LOG_MSG("WARNING: Unable to make font texture. id=%llu err=%lu",
00348             (unsigned long long)SDLDrawGenFontTexture, (unsigned long)err);
00349     }
00350     else
00351     {
00352         LOG_MSG("font texture id=%lu will make %u x %u",
00353             (unsigned long)SDLDrawGenFontTexture,
00354             (unsigned int)SDLDrawGenFontTextureWidth,
00355             (unsigned int)SDLDrawGenFontTextureHeight);
00356 
00357         SDLDrawGenFontTextureInit = 1;
00358 
00359         glBindTexture(GL_TEXTURE_2D, SDLDrawGenFontTexture);
00360 
00361         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00362         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, 0);
00363 
00364         // No borders
00365         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00366         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00367         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00368         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00369 
00370         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, SDLDrawGenFontTextureWidth, SDLDrawGenFontTextureHeight, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, 0);
00371 
00372         /* load the font */
00373         {
00374             extern Bit8u int10_font_16[256 * 16];
00375 
00376             unsigned char *bmp;
00377             uint32_t tmp[8 * 16];
00378             unsigned int x, y, c;
00379 
00380             for (c = 0; c < 256; c++) 
00381             {
00382                 bmp = int10_font_16 + (c * 16);
00383                 for (y = 0; y < 16; y++) 
00384                 {
00385                     for (x = 0; x < 8; x++) 
00386                     {
00387                         tmp[(y * 8) + x] = (bmp[y] & (0x80 >> x)) ? 0xFFFFFFFFUL : 0x00000000UL;
00388                     }
00389                 }
00390 
00391                 glTexSubImage2D(GL_TEXTURE_2D, /*level*/0, /*x*/(int)((c % 16) * 8), /*y*/(int)((c / 16) * 16),
00392                     8, 16, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, (void*)tmp);
00393             }
00394         }
00395 
00396         glBindTexture(GL_TEXTURE_2D, 0);
00397     }
00398     // }
00399 #endif
00400 
00401     glFinish();
00402     glFlush();
00403 
00404     sdl_opengl.inited = true;
00405     retFlags = GFX_CAN_32 | GFX_SCALING;
00406 
00407     if (sdl_opengl.pixel_buffer_object)
00408         retFlags |= GFX_HARDWARE;
00409 
00410     return retFlags;
00411 }
00412 
00413 bool OUTPUT_OPENGL_StartUpdate(Bit8u* &pixels, Bitu &pitch)
00414 {
00415 #if C_XBRZ    
00416     if (sdl_xbrz.enable && sdl_xbrz.scale_on) 
00417     {
00418         sdl_xbrz.renderbuf.resize(sdl.draw.width * sdl.draw.height);
00419         pixels = sdl_xbrz.renderbuf.empty() ? nullptr : reinterpret_cast<Bit8u*>(&sdl_xbrz.renderbuf[0]);
00420         pitch = sdl.draw.width * sizeof(uint32_t);
00421     }
00422     else
00423 #endif
00424     {
00425         if (sdl_opengl.pixel_buffer_object)
00426         {
00427             glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, sdl_opengl.buffer);
00428             pixels = (Bit8u *)glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
00429         }
00430         else
00431         {
00432             pixels = (Bit8u *)sdl_opengl.framebuf;
00433         }
00434         pitch = sdl_opengl.pitch;
00435     }
00436 
00437     sdl.updating = true;
00438     return true;
00439 }
00440 
00441 void OUTPUT_OPENGL_EndUpdate(const Bit16u *changedLines)
00442 {
00443     if (!(sdl.must_redraw_all && changedLines == NULL)) 
00444     {
00445         if (sdl_opengl.clear_countdown > 0)
00446         {
00447             sdl_opengl.clear_countdown--;
00448             glClearColor(0.0, 0.0, 0.0, 1.0);
00449             glClear(GL_COLOR_BUFFER_BIT);
00450         }
00451 
00452         if (sdl_opengl.menudraw_countdown > 0) 
00453         {
00454             sdl_opengl.menudraw_countdown--;
00455 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
00456             mainMenu.setRedraw();
00457             GFX_DrawSDLMenu(mainMenu, mainMenu.display_list);
00458 #endif
00459         }
00460 
00461 #if C_XBRZ
00462         if (sdl_xbrz.enable && sdl_xbrz.scale_on)
00463         {
00464             // OpenGL pixel buffer is precreated for direct xBRZ output, while xBRZ render buffer is used for rendering
00465             const int srcWidth = sdl.draw.width;
00466             const int srcHeight = sdl.draw.height;
00467 
00468             if (sdl_xbrz.renderbuf.size() == srcWidth * srcHeight && srcWidth > 0 && srcHeight > 0)
00469             {
00470                 // we assume render buffer is *not* scaled!
00471                 const uint32_t* renderBuf = &sdl_xbrz.renderbuf[0]; // help VS compiler a little + support capture by value
00472                 uint32_t* trgTex;
00473                 if (sdl_opengl.pixel_buffer_object) 
00474                 {
00475                     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, sdl_opengl.buffer);
00476                     trgTex = (uint32_t *)glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
00477                 }
00478                 else
00479                 {
00480                     trgTex = reinterpret_cast<uint32_t*>(static_cast<void*>(sdl_opengl.framebuf));
00481                 }
00482 
00483                 if (trgTex)
00484                     xBRZ_Render(renderBuf, trgTex, changedLines, srcWidth, srcHeight, sdl_xbrz.scale_factor);
00485             }
00486 
00487             // and here we go repeating some stuff with xBRZ related modifications
00488             if (sdl_opengl.pixel_buffer_object)
00489             {
00490                 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT);
00491                 glBindTexture(GL_TEXTURE_2D, sdl_opengl.texture);
00492                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
00493                     sdl.draw.width * sdl_xbrz.scale_factor, sdl.draw.height * sdl_xbrz.scale_factor, GL_BGRA_EXT,
00494                     GL_UNSIGNED_INT_8_8_8_8_REV, 0);
00495                 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
00496             }
00497             else
00498             {
00499                 glBindTexture(GL_TEXTURE_2D, sdl_opengl.texture);
00500                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
00501                     sdl.draw.width * sdl_xbrz.scale_factor, sdl.draw.height * sdl_xbrz.scale_factor, GL_BGRA_EXT,
00502 #if defined (MACOSX)
00503                     // needed for proper looking graphics on macOS 10.12, 10.13
00504                     GL_UNSIGNED_INT_8_8_8_8,
00505 #else
00506                     // works on Linux
00507                     GL_UNSIGNED_INT_8_8_8_8_REV,
00508 #endif
00509                     (Bit8u *)sdl_opengl.framebuf);
00510             }
00511             glCallList(sdl_opengl.displaylist);
00512             SDL_GL_SwapBuffers();
00513         }
00514         else
00515 #endif /*C_XBRZ*/
00516         if (sdl_opengl.pixel_buffer_object) 
00517         {
00518             if (changedLines && (changedLines[0] == sdl.draw.height))
00519                 return;
00520 
00521             glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT);
00522             glBindTexture(GL_TEXTURE_2D, sdl_opengl.texture);
00523             glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
00524                 (int)sdl.draw.width, (int)sdl.draw.height, GL_BGRA_EXT,
00525                 GL_UNSIGNED_INT_8_8_8_8_REV, (void*)0);
00526             glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
00527             glCallList(sdl_opengl.displaylist);
00528             SDL_GL_SwapBuffers();
00529         }
00530         else if (changedLines) 
00531         {
00532             if (changedLines[0] == sdl.draw.height)
00533                 return;
00534 
00535             Bitu y = 0, index = 0;
00536             glBindTexture(GL_TEXTURE_2D, sdl_opengl.texture);
00537             while (y < sdl.draw.height) 
00538             {
00539                 if (!(index & 1)) 
00540                 {
00541                     y += changedLines[index];
00542                 }
00543                 else 
00544                 {
00545                     Bit8u *pixels = (Bit8u *)sdl_opengl.framebuf + y * sdl_opengl.pitch;
00546                     Bitu height = changedLines[index];
00547                     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, (int)y,
00548                         (int)sdl.draw.width, (int)height, GL_BGRA_EXT,
00549 #if defined (MACOSX)
00550                         // needed for proper looking graphics on macOS 10.12, 10.13
00551                         GL_UNSIGNED_INT_8_8_8_8,
00552 #else
00553                         // works on Linux
00554                         GL_UNSIGNED_INT_8_8_8_8_REV,
00555 #endif
00556                         (void*)pixels);
00557                     y += height;
00558                 }
00559                 index++;
00560             }
00561             glCallList(sdl_opengl.displaylist);
00562 
00563 #if 0 /* DEBUG Prove to me that you're drawing the damn texture */
00564             glBindTexture(GL_TEXTURE_2D, SDLDrawGenFontTexture);
00565 
00566             glPushMatrix();
00567 
00568             glMatrixMode(GL_TEXTURE);
00569             glLoadIdentity();
00570             glScaled(1.0 / SDLDrawGenFontTextureWidth, 1.0 / SDLDrawGenFontTextureHeight, 1.0);
00571 
00572             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00573             glEnable(GL_ALPHA_TEST);
00574             glEnable(GL_BLEND);
00575 
00576             glBegin(GL_QUADS);
00577 
00578             glTexCoord2i(0, 0); glVertex2i(0, 0); // lower left
00579             glTexCoord2i(SDLDrawGenFontTextureWidth, 0); glVertex2i(SDLDrawGenFontTextureWidth, 0); // lower right
00580             glTexCoord2i(SDLDrawGenFontTextureWidth, SDLDrawGenFontTextureHeight); glVertex2i(SDLDrawGenFontTextureWidth, SDLDrawGenFontTextureHeight); // upper right
00581             glTexCoord2i(0, SDLDrawGenFontTextureHeight); glVertex2i(0, SDLDrawGenFontTextureHeight); // upper left
00582 
00583             glEnd();
00584 
00585             glBlendFunc(GL_ONE, GL_ZERO);
00586             glDisable(GL_ALPHA_TEST);
00587             glEnable(GL_TEXTURE_2D);
00588 
00589             glPopMatrix();
00590 
00591             glBindTexture(GL_TEXTURE_2D, sdl_opengl.texture);
00592 #endif
00593 
00594             SDL_GL_SwapBuffers();
00595         }
00596 
00597         if (!menu.hidecycles && !sdl.desktop.fullscreen) frames++;
00598     }
00599 }
00600 
00601 void OUTPUT_OPENGL_Shutdown()
00602 {
00603     // nothing to shutdown (yet?)
00604 }
00605 
00606 #endif