DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/output/output_surface.cpp
00001 #include <sys/types.h>
00002 #include <assert.h>
00003 #include <math.h>
00004 
00005 #include "dosbox.h"
00006 #include "sdlmain.h"
00007 #include "vga.h"
00008 
00009 using namespace std;
00010 
00011 // output API below
00012 
00013 void OUTPUT_SURFACE_Initialize()
00014 {
00015     // nothing to initialize (yet?)
00016 }
00017 
00018 void OUTPUT_SURFACE_Select()
00019 {
00020     sdl.desktop.want_type = SCREEN_SURFACE;
00021     render.aspectOffload = false;
00022 
00023 #if defined(WIN32) && !defined(C_SDL2)
00024     SDL1_hax_inhibit_WM_PAINT = 0;
00025 #endif
00026 }
00027 
00028 bool OUTPUT_SURFACE_StartUpdate(Bit8u* &pixels, Bitu &pitch)
00029 {
00030 #if C_XBRZ
00031     if (sdl_xbrz.enable && sdl_xbrz.scale_on)
00032     {
00033         sdl_xbrz.renderbuf.resize(sdl.draw.width * sdl.draw.height);
00034         pixels = sdl_xbrz.renderbuf.empty() ? nullptr : reinterpret_cast<Bit8u*>(&sdl_xbrz.renderbuf[0]);
00035         pitch = sdl.draw.width * sizeof(uint32_t);
00036     }
00037     else
00038 #endif
00039 #if C_SURFACE_POSTRENDER_ASPECT
00040         if (render.aspect == ASPECT_NEAREST || render.aspect == ASPECT_BILINEAR)
00041         {
00042             sdl.aspectbuf.resize(sdl.draw.width * sdl.draw.height);
00043             pixels = sdl.aspectbuf.empty() ? nullptr : reinterpret_cast<Bit8u*>(&sdl.aspectbuf[0]);
00044             pitch = sdl.draw.width * sizeof(uint32_t);
00045         }
00046         else
00047 #endif
00048         {
00049             if (sdl.blit.surface)
00050             {
00051                 if (SDL_MUSTLOCK(sdl.blit.surface) && SDL_LockSurface(sdl.blit.surface))
00052                     return false;
00053                 pixels = (Bit8u *)sdl.blit.surface->pixels;
00054                 pitch = sdl.blit.surface->pitch;
00055             }
00056             else
00057             {
00058                 if (SDL_MUSTLOCK(sdl.surface) && SDL_LockSurface(sdl.surface))
00059                     return false;
00060                 pixels = (Bit8u *)sdl.surface->pixels;
00061                 pixels += sdl.clip.y * sdl.surface->pitch;
00062                 pixels += sdl.clip.x * sdl.surface->format->BytesPerPixel;
00063                 pitch = sdl.surface->pitch;
00064             }
00065         }
00066 
00067     GFX_SDL_Overscan();
00068     sdl.updating = true;
00069     return true;
00070 }
00071 
00072 void OUTPUT_SURFACE_EndUpdate(const Bit16u *changedLines)
00073 {
00074 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
00075     GFX_DrawSDLMenu(mainMenu, mainMenu.display_list);
00076 #endif
00077 #if C_XBRZ
00078     if (sdl_xbrz.enable && sdl_xbrz.scale_on)
00079     {
00080         const Bit32u srcWidth = sdl.draw.width;
00081         const Bit32u srcHeight = sdl.draw.height;
00082         if (sdl_xbrz.renderbuf.size() == (unsigned int)srcWidth * (unsigned int)srcHeight && srcWidth > 0 && srcHeight > 0)
00083         {
00084             // please use sdl.clip to keep screen positioning consistent with the rest of the emulator
00085             int clipWidth = sdl.clip.w;
00086             int clipHeight = sdl.clip.h;
00087             int clipX = sdl.clip.x;
00088             int clipY = sdl.clip.y;
00089 
00090             // 1. xBRZ-scale render buffer into xbrz pixel buffer
00091             unsigned int xbrzWidth = 0;
00092             unsigned int xbrzHeight = 0;
00093             uint32_t* xbrzBuf;
00094             xbrzWidth = srcWidth * (unsigned int)sdl_xbrz.scale_factor;
00095             xbrzHeight = srcHeight * (unsigned int)sdl_xbrz.scale_factor;
00096             sdl_xbrz.pixbuf.resize(xbrzWidth * xbrzHeight);
00097 
00098             const uint32_t* renderBuf = &sdl_xbrz.renderbuf[0]; // help VS compiler a little + support capture by value
00099             xbrzBuf = &sdl_xbrz.pixbuf[0];
00100             xBRZ_Render(renderBuf, xbrzBuf, changedLines, (int)srcWidth, (int)srcHeight, sdl_xbrz.scale_factor);
00101 
00102             // 2. nearest neighbor/bilinear scale xbrz buffer into output surface clipping area
00103             const bool mustLock = SDL_MUSTLOCK(sdl.surface);
00104             if (mustLock) SDL_LockSurface(sdl.surface);
00105             if (sdl.surface->pixels) // if locking fails, this can be nullptr, also check if we really need to draw
00106             {
00107                 uint32_t* clipTrg = reinterpret_cast<uint32_t*>(static_cast<char*>(sdl.surface->pixels) + clipY * sdl.surface->pitch + (unsigned int)clipX * sizeof(uint32_t));
00108                 xBRZ_PostScale(&xbrzBuf[0], (int)xbrzWidth, (int)xbrzHeight, (int)(xbrzWidth * sizeof(uint32_t)),
00109                     &clipTrg[0], clipWidth, clipHeight, sdl.surface->pitch, 
00110                     sdl_xbrz.postscale_bilinear, sdl_xbrz.task_granularity);
00111             }
00112 
00113             if (mustLock) SDL_UnlockSurface(sdl.surface);
00114             if (!menu.hidecycles && !sdl.desktop.fullscreen) frames++;
00115 #if defined(C_SDL2)
00116             SDL_UpdateWindowSurface(sdl.window);
00117 #else
00118             SDL_Flip(sdl.surface);
00119 #endif
00120         }
00121     }
00122     else
00123 #endif /*C_XBRZ*/
00124 #if C_SURFACE_POSTRENDER_ASPECT
00125     if (render.aspect == ASPECT_NEAREST || render.aspect == ASPECT_BILINEAR) {
00126         // here we go, adjusting source aspect ratio
00127         int clipWidth = sdl.clip.w;
00128         int clipHeight = sdl.clip.h;
00129         int clipX = sdl.clip.x;
00130         int clipY = sdl.clip.y;
00131 
00132         const bool mustLock = SDL_MUSTLOCK(sdl.surface);
00133         if (mustLock) SDL_LockSurface(sdl.surface);
00134         if (sdl.surface->pixels) // if locking fails, this can be nullptr, also check if we really need to draw
00135         {
00136             uint32_t* clipTrg = reinterpret_cast<uint32_t*>(static_cast<char*>(sdl.surface->pixels) + clipY * sdl.surface->pitch + clipX * sizeof(uint32_t));
00137             xBRZ_PostScale(&sdl.aspectbuf[0], sdl.draw.width, sdl.draw.height, sdl.draw.width * sizeof(uint32_t),
00138                 &clipTrg[0], clipWidth, clipHeight, sdl.surface->pitch,
00139                 (render.aspect == ASPECT_BILINEAR), C_SURFACE_POSTRENDER_ASPECT_BATCH_SIZE);
00140         }
00141 
00142         if (mustLock) SDL_UnlockSurface(sdl.surface);
00143         if (!menu.hidecycles && !sdl.desktop.fullscreen) frames++;
00144 #if defined(C_SDL2)
00145         SDL_UpdateWindowSurfaceRects(sdl.window, sdl.updateRects, 1);
00146 #else
00147         SDL_Flip(sdl.surface);
00148 #endif
00149     }
00150     else
00151 #endif /*C_SURFACE_POSTRENDER_ASPECT*/
00152     {
00153         if (SDL_MUSTLOCK(sdl.surface)) {
00154             if (sdl.blit.surface) {
00155                 SDL_UnlockSurface(sdl.blit.surface);
00156                 int Blit = SDL_BlitSurface(sdl.blit.surface, 0, sdl.surface, &sdl.clip);
00157                 LOG(LOG_MISC, LOG_WARN)("BlitSurface returned %d", Blit);
00158             }
00159             else {
00160                 SDL_UnlockSurface(sdl.surface);
00161             }
00162             if (changedLines && (changedLines[0] == sdl.draw.height))
00163                 return;
00164             if (!menu.hidecycles && !sdl.desktop.fullscreen) frames++;
00165 #if defined(C_SDL2)
00166             SDL_UpdateWindowSurface(sdl.window);
00167 #else
00168             SDL_Flip(sdl.surface);
00169 #endif
00170         }
00171         else if (sdl.must_redraw_all) {
00172 #if defined(C_SDL2)
00173             if (changedLines != NULL) SDL_UpdateWindowSurface(sdl.window);
00174 #else
00175             if (changedLines != NULL) SDL_Flip(sdl.surface);
00176 #endif
00177         }
00178         else if (changedLines) {
00179             if (changedLines[0] == sdl.draw.height)
00180                 return;
00181             if (!menu.hidecycles && !sdl.desktop.fullscreen) frames++;
00182             Bitu y = 0, index = 0, rectCount = 0;
00183             while (y < sdl.draw.height) {
00184                 if (!(index & 1)) {
00185                     y += changedLines[index];
00186                 }
00187                 else {
00188                     SDL_Rect *rect = &sdl.updateRects[rectCount++];
00189                     rect->x = sdl.clip.x;
00190                     rect->y = sdl.clip.y + (int)y;
00191                     rect->w = (Bit16u)sdl.draw.width;
00192                     rect->h = changedLines[index];
00193                     y += changedLines[index];
00194                     SDL_rect_cliptoscreen(*rect);
00195                 }
00196                 index++;
00197             }
00198             if (rectCount) {
00199 #if defined(C_SDL2)
00200                 SDL_UpdateWindowSurfaceRects(sdl.window, sdl.updateRects, (int)rectCount);
00201 #else
00202                 SDL_UpdateRects(sdl.surface, (int)rectCount, sdl.updateRects);
00203 #endif
00204             }
00205         }
00206     }
00207 }
00208 
00209 void OUTPUT_SURFACE_Shutdown()
00210 {
00211     // nothing to shutdown (yet?)
00212 }