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