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