sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_os2vman.c (14924B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
      4 
      5   This software is provided 'as-is', without any express or implied
      6   warranty.  In no event will the authors be held liable for any damages
      7   arising from the use of this software.
      8 
      9   Permission is granted to anyone to use this software for any purpose,
     10   including commercial applications, and to alter it and redistribute it
     11   freely, subject to the following restrictions:
     12 
     13   1. The origin of this software must not be misrepresented; you must not
     14      claim that you wrote the original software. If you use this software
     15      in a product, an acknowledgment in the product documentation would be
     16      appreciated but is not required.
     17   2. Altered source versions must be plainly marked as such, and must not be
     18      misrepresented as being the original software.
     19   3. This notice may not be removed or altered from any source distribution.
     20 */
     21 #include "../../SDL_internal.h"
     22 #include "../SDL_sysvideo.h"
     23 
     24 #define INCL_DOSERRORS
     25 #define INCL_DOSPROCESS
     26 #define INCL_DOSMODULEMGR
     27 #define INCL_WIN
     28 #define INCL_GPI
     29 #define INCL_GPIBITMAPS /* GPI bit map functions */
     30 #include <os2.h>
     31 #include "SDL_os2output.h"
     32 #include "SDL_os2video.h"
     33 
     34 #include "my_gradd.h"
     35 
     36 typedef struct _VODATA {
     37   PVOID    pBuffer;
     38   HRGN     hrgnVisible;
     39   ULONG    ulBPP;
     40   ULONG    ulScanLineSize;
     41   ULONG    ulWidth;
     42   ULONG    ulHeight;
     43   ULONG    ulScreenHeight;
     44   ULONG    ulScreenBytesPerLine;
     45   RECTL    rectlWin;
     46 
     47   PRECTL   pRectl;
     48   ULONG    cRectl;
     49   PBLTRECT pBltRect;
     50   ULONG    cBltRect;
     51 } VODATA;
     52 
     53 static BOOL voQueryInfo(VIDEOOUTPUTINFO *pInfo);
     54 static PVODATA voOpen();
     55 static VOID voClose(PVODATA pVOData);
     56 static BOOL voSetVisibleRegion(PVODATA pVOData, HWND hwnd,
     57                                SDL_DisplayMode *pSDLDisplayMode,
     58                                HRGN hrgnShape, BOOL fVisible);
     59 static PVOID voVideoBufAlloc(PVODATA pVOData, ULONG ulWidth, ULONG ulHeight,
     60                              ULONG ulBPP, ULONG fccColorEncoding,
     61                              PULONG pulScanLineSize);
     62 static VOID voVideoBufFree(PVODATA pVOData);
     63 static BOOL voUpdate(PVODATA pVOData, HWND hwnd, SDL_Rect *pSDLRects,
     64                      ULONG cSDLRects);
     65 
     66 OS2VIDEOOUTPUT voVMan = {
     67     voQueryInfo,
     68     voOpen,
     69     voClose,
     70     voSetVisibleRegion,
     71     voVideoBufAlloc,
     72     voVideoBufFree,
     73     voUpdate
     74 };
     75 
     76 
     77 static HMODULE  hmodVMan = NULLHANDLE;
     78 static FNVMIENTRY *pfnVMIEntry = NULL;
     79 static ULONG        ulVRAMAddress = 0;
     80 
     81 VOID APIENTRY ExitVMan(VOID)
     82 {
     83     if (ulVRAMAddress != 0 && hmodVMan != NULLHANDLE) {
     84         pfnVMIEntry(0, VMI_CMD_TERMPROC, NULL, NULL);
     85         DosFreeModule(hmodVMan);
     86     }
     87 
     88     DosExitList(EXLST_EXIT, (PFNEXITLIST)NULL);
     89 }
     90 
     91 static BOOL _vmanInit(void)
     92 {
     93     ULONG       ulRC;
     94     CHAR        acBuf[255];
     95     INITPROCOUT stInitProcOut;
     96 
     97     if (hmodVMan != NULLHANDLE) /* Already was initialized */
     98         return TRUE;
     99 
    100     /* Load vman.dll */
    101     ulRC = DosLoadModule(acBuf, sizeof(acBuf), "VMAN", &hmodVMan);
    102     if (ulRC != NO_ERROR) {
    103         debug_os2("Could not load VMAN.DLL, rc = %u : %s", ulRC, acBuf);
    104         hmodVMan = NULLHANDLE;
    105         return FALSE;
    106     }
    107 
    108     /* Get VMIEntry */
    109     ulRC = DosQueryProcAddr(hmodVMan, 0L, "VMIEntry", (PFN *)&pfnVMIEntry);
    110     if (ulRC != NO_ERROR) {
    111         debug_os2("Could not query address of pfnVMIEntry func. of VMAN.DLL, "
    112                   "rc = %u", ulRC);
    113         DosFreeModule(hmodVMan);
    114         hmodVMan = NULLHANDLE;
    115         return FALSE;
    116     }
    117 
    118     /* VMAN initialization */
    119     stInitProcOut.ulLength = sizeof(stInitProcOut);
    120     ulRC = pfnVMIEntry(0, VMI_CMD_INITPROC, NULL, &stInitProcOut);
    121     if (ulRC != RC_SUCCESS) {
    122         debug_os2("Could not initialize VMAN for this process");
    123         pfnVMIEntry = NULL;
    124         DosFreeModule(hmodVMan);
    125         hmodVMan = NULLHANDLE;
    126         return FALSE;
    127     }
    128 
    129     /* Store video memory virtual address */
    130     ulVRAMAddress = stInitProcOut.ulVRAMVirt;
    131     /* We use exit list for VMI_CMD_TERMPROC */
    132     if (DosExitList(EXLST_ADD | 0x00001000, (PFNEXITLIST)ExitVMan) != NO_ERROR) {
    133         debug_os2("DosExitList() failed");
    134     }
    135 
    136     return TRUE;
    137 }
    138 
    139 static PRECTL _getRectlArray(PVODATA pVOData, ULONG cRects)
    140 {
    141     PRECTL  pRectl;
    142 
    143     if (pVOData->cRectl >= cRects)
    144         return pVOData->pRectl;
    145 
    146     pRectl = SDL_realloc(pVOData->pRectl, cRects * sizeof(RECTL));
    147     if (pRectl == NULL)
    148         return NULL;
    149 
    150     pVOData->pRectl = pRectl;
    151     pVOData->cRectl = cRects;
    152     return pRectl;
    153 }
    154 
    155 static PBLTRECT _getBltRectArray(PVODATA pVOData, ULONG cRects)
    156 {
    157     PBLTRECT    pBltRect;
    158 
    159     if (pVOData->cBltRect >= cRects)
    160         return pVOData->pBltRect;
    161 
    162     pBltRect = SDL_realloc(pVOData->pBltRect, cRects * sizeof(BLTRECT));
    163     if (pBltRect == NULL)
    164         return NULL;
    165 
    166     pVOData->pBltRect = pBltRect;
    167     pVOData->cBltRect = cRects;
    168     return pBltRect;
    169 }
    170 
    171 
    172 static BOOL voQueryInfo(VIDEOOUTPUTINFO *pInfo)
    173 {
    174     ULONG       ulRC;
    175     GDDMODEINFO sCurModeInfo;
    176 
    177     if (!_vmanInit())
    178         return FALSE;
    179 
    180     /* Query current (desktop) mode */
    181     ulRC = pfnVMIEntry(0, VMI_CMD_QUERYCURRENTMODE, NULL, &sCurModeInfo);
    182     if (ulRC != RC_SUCCESS) {
    183         debug_os2("Could not query desktop video mode.");
    184         return FALSE;
    185     }
    186 
    187     pInfo->ulBPP             = sCurModeInfo.ulBpp;
    188     pInfo->ulHorizResolution = sCurModeInfo.ulHorizResolution;
    189     pInfo->ulVertResolution  = sCurModeInfo.ulVertResolution;
    190     pInfo->ulScanLineSize    = sCurModeInfo.ulScanLineSize;
    191     pInfo->fccColorEncoding  = sCurModeInfo.fccColorEncoding;
    192 
    193     return TRUE;
    194 }
    195 
    196 static PVODATA voOpen(void)
    197 {
    198     PVODATA pVOData;
    199 
    200     if (!_vmanInit())
    201         return NULL;
    202 
    203     pVOData = SDL_calloc(1, sizeof(VODATA));
    204     if (pVOData == NULL) {
    205         SDL_OutOfMemory();
    206         return NULL;
    207     }
    208 
    209     return pVOData;
    210 }
    211 
    212 static VOID voClose(PVODATA pVOData)
    213 {
    214     if (pVOData->pRectl != NULL)
    215         SDL_free(pVOData->pRectl);
    216 
    217     if (pVOData->pBltRect != NULL)
    218         SDL_free(pVOData->pBltRect);
    219 
    220     voVideoBufFree(pVOData);
    221 }
    222 
    223 static BOOL voSetVisibleRegion(PVODATA pVOData, HWND hwnd,
    224                                SDL_DisplayMode *pSDLDisplayMode,
    225                                HRGN hrgnShape, BOOL fVisible)
    226 {
    227     HPS   hps;
    228     BOOL  fSuccess = FALSE;
    229 
    230     hps = WinGetPS(hwnd);
    231 
    232     if (pVOData->hrgnVisible != NULLHANDLE) {
    233         GpiDestroyRegion(hps, pVOData->hrgnVisible);
    234         pVOData->hrgnVisible = NULLHANDLE;
    235     }
    236 
    237     if (fVisible) {
    238         /* Query visible rectangles */
    239         pVOData->hrgnVisible = GpiCreateRegion(hps, 0, NULL);
    240         if (pVOData->hrgnVisible == NULLHANDLE) {
    241             SDL_SetError("GpiCreateRegion() failed");
    242         } else {
    243             if (WinQueryVisibleRegion(hwnd, pVOData->hrgnVisible) == RGN_ERROR) {
    244                 GpiDestroyRegion(hps, pVOData->hrgnVisible);
    245                 pVOData->hrgnVisible = NULLHANDLE;
    246             } else {
    247                 if (hrgnShape != NULLHANDLE)
    248                     GpiCombineRegion(hps, pVOData->hrgnVisible, pVOData->hrgnVisible,
    249                                      hrgnShape, CRGN_AND);
    250                 fSuccess = TRUE;
    251             }
    252         }
    253 
    254         WinQueryWindowRect(hwnd, &pVOData->rectlWin);
    255         WinMapWindowPoints(hwnd, HWND_DESKTOP, (PPOINTL)&pVOData->rectlWin, 2);
    256 
    257         if (pSDLDisplayMode != NULL) {
    258             pVOData->ulScreenHeight = pSDLDisplayMode->h;
    259             pVOData->ulScreenBytesPerLine =
    260                      ((MODEDATA *)pSDLDisplayMode->driverdata)->ulScanLineBytes;
    261         }
    262     }
    263 
    264     WinReleasePS(hps);
    265 
    266     return fSuccess;
    267 }
    268 
    269 static PVOID voVideoBufAlloc(PVODATA pVOData, ULONG ulWidth, ULONG ulHeight,
    270                              ULONG ulBPP, ULONG fccColorEncoding,
    271                              PULONG pulScanLineSize)
    272 {
    273     ULONG ulRC;
    274     ULONG ulScanLineSize = ulWidth * (ulBPP >> 3);
    275 
    276     /* Destroy previous buffer */
    277     voVideoBufFree(pVOData);
    278 
    279     if (ulWidth == 0 || ulHeight == 0 || ulBPP == 0)
    280         return NULL;
    281 
    282     /* Bytes per line */
    283     ulScanLineSize  = (ulScanLineSize + 3) & ~3; /* 4-byte aligning */
    284     *pulScanLineSize = ulScanLineSize;
    285 
    286     ulRC = DosAllocMem(&pVOData->pBuffer,
    287                        (ulHeight * ulScanLineSize) + sizeof(ULONG),
    288                        PAG_COMMIT | PAG_EXECUTE | PAG_READ | PAG_WRITE);
    289     if (ulRC != NO_ERROR) {
    290         debug_os2("DosAllocMem(), rc = %u", ulRC);
    291         return NULL;
    292     }
    293 
    294     pVOData->ulBPP          = ulBPP;
    295     pVOData->ulScanLineSize = ulScanLineSize;
    296     pVOData->ulWidth        = ulWidth;
    297     pVOData->ulHeight       = ulHeight;
    298 
    299     return pVOData->pBuffer;
    300 }
    301 
    302 static VOID voVideoBufFree(PVODATA pVOData)
    303 {
    304     ULONG ulRC;
    305 
    306     if (pVOData->pBuffer == NULL)
    307         return;
    308 
    309     ulRC = DosFreeMem(pVOData->pBuffer);
    310     if (ulRC != NO_ERROR) {
    311         debug_os2("DosFreeMem(), rc = %u", ulRC);
    312     } else {
    313         pVOData->pBuffer = NULL;
    314     }
    315 }
    316 
    317 static BOOL voUpdate(PVODATA pVOData, HWND hwnd, SDL_Rect *pSDLRects,
    318                      ULONG cSDLRects)
    319 {
    320     PRECTL      prectlDst, prectlScan;
    321     HPS         hps;
    322     HRGN        hrgnUpdate;
    323     RGNRECT     rgnCtl;
    324     SDL_Rect    stSDLRectDef;
    325     BMAPINFO    bmiSrc;
    326     BMAPINFO    bmiDst;
    327     PPOINTL     pptlSrcOrg;
    328     PBLTRECT    pbrDst;
    329     HWREQIN     sHWReqIn;
    330     BITBLTINFO  sBitbltInfo = { 0 };
    331     ULONG       ulIdx;
    332 /*  RECTL       rectlScreenUpdate;*/
    333 
    334     if (pVOData->pBuffer == NULL)
    335         return FALSE;
    336 
    337     if (pVOData->hrgnVisible == NULLHANDLE)
    338         return TRUE;
    339 
    340     bmiSrc.ulLength = sizeof(BMAPINFO);
    341     bmiSrc.ulType = BMAP_MEMORY;
    342     bmiSrc.ulWidth = pVOData->ulWidth;
    343     bmiSrc.ulHeight = pVOData->ulHeight;
    344     bmiSrc.ulBpp = pVOData->ulBPP;
    345     bmiSrc.ulBytesPerLine = pVOData->ulScanLineSize;
    346     bmiSrc.pBits = (PBYTE)pVOData->pBuffer;
    347 
    348     bmiDst.ulLength = sizeof(BMAPINFO);
    349     bmiDst.ulType = BMAP_VRAM;
    350     bmiDst.pBits = (PBYTE)ulVRAMAddress;
    351     bmiDst.ulWidth = bmiSrc.ulWidth;
    352     bmiDst.ulHeight = bmiSrc.ulHeight;
    353     bmiDst.ulBpp = bmiSrc.ulBpp;
    354     bmiDst.ulBytesPerLine = pVOData->ulScreenBytesPerLine;
    355 
    356     /* List of update rectangles. This is the intersection of requested
    357      * rectangles and visible rectangles.  */
    358     if (cSDLRects == 0) {
    359         /* Full update requested */
    360         stSDLRectDef.x = 0;
    361         stSDLRectDef.y = 0;
    362         stSDLRectDef.w = bmiSrc.ulWidth;
    363         stSDLRectDef.h = bmiSrc.ulHeight;
    364         pSDLRects = &stSDLRectDef;
    365         cSDLRects = 1;
    366     }
    367 
    368     /* Make list of destination rectangles (prectlDst) list from the source
    369      * list (prectl).  */
    370     prectlDst = _getRectlArray(pVOData, cSDLRects);
    371     if (prectlDst == NULL) {
    372         debug_os2("Not enough memory");
    373         return FALSE;
    374     }
    375     prectlScan = prectlDst;
    376     for (ulIdx = 0; ulIdx < cSDLRects; ulIdx++, pSDLRects++, prectlScan++) {
    377         prectlScan->xLeft   = pSDLRects->x;
    378         prectlScan->yTop    = pVOData->ulHeight - pSDLRects->y;
    379         prectlScan->xRight  = prectlScan->xLeft + pSDLRects->w;
    380         prectlScan->yBottom = prectlScan->yTop - pSDLRects->h;
    381     }
    382 
    383     hps = WinGetPS(hwnd);
    384     if (hps == NULLHANDLE)
    385         return FALSE;
    386 
    387     /* Make destination region to update */
    388     hrgnUpdate = GpiCreateRegion(hps, cSDLRects, prectlDst);
    389     /* "AND" on visible and destination regions, result is region to update */
    390     GpiCombineRegion(hps, hrgnUpdate, hrgnUpdate, pVOData->hrgnVisible, CRGN_AND);
    391 
    392     /* Get rectangles of the region to update */
    393     rgnCtl.ircStart     = 1;
    394     rgnCtl.crc          = 0;
    395     rgnCtl.ulDirection  = 1;
    396     rgnCtl.crcReturned  = 0;
    397     GpiQueryRegionRects(hps, hrgnUpdate, NULL, &rgnCtl, NULL);
    398     if (rgnCtl.crcReturned == 0) {
    399         GpiDestroyRegion(hps, hrgnUpdate);
    400         WinReleasePS(hps);
    401         return TRUE;
    402     }
    403     /* We don't need prectlDst, use it again to store update regions */
    404     prectlDst = _getRectlArray(pVOData, rgnCtl.crcReturned);
    405     if (prectlDst == NULL) {
    406         debug_os2("Not enough memory");
    407         GpiDestroyRegion(hps, hrgnUpdate);
    408         WinReleasePS(hps);
    409         return FALSE;
    410     }
    411     rgnCtl.ircStart     = 1;
    412     rgnCtl.crc          = rgnCtl.crcReturned;
    413     rgnCtl.ulDirection  = 1;
    414     GpiQueryRegionRects(hps, hrgnUpdate, NULL, &rgnCtl, prectlDst);
    415     GpiDestroyRegion(hps, hrgnUpdate);
    416     WinReleasePS(hps);
    417     cSDLRects = rgnCtl.crcReturned;
    418 
    419     /* Now cRect/prectlDst is a list of regions in window (update && visible) */
    420 
    421     /* Make lists for blitting from update regions */
    422     pbrDst = _getBltRectArray(pVOData, cSDLRects);
    423     if (pbrDst == NULL) {
    424         debug_os2("Not enough memory");
    425         return FALSE;
    426     }
    427 
    428     prectlScan = prectlDst;
    429     pptlSrcOrg = (PPOINTL)prectlDst; /* Yes, this memory block will be used again */
    430     for (ulIdx = 0; ulIdx < cSDLRects; ulIdx++, prectlScan++, pptlSrcOrg++) {
    431         pbrDst[ulIdx].ulXOrg = pVOData->rectlWin.xLeft + prectlScan->xLeft;
    432         pbrDst[ulIdx].ulYOrg = pVOData->ulScreenHeight -
    433                               (pVOData->rectlWin.yBottom + prectlScan->yTop);
    434         pbrDst[ulIdx].ulXExt = prectlScan->xRight - prectlScan->xLeft;
    435         pbrDst[ulIdx].ulYExt = prectlScan->yTop - prectlScan->yBottom;
    436         pptlSrcOrg->x = prectlScan->xLeft;
    437         pptlSrcOrg->y = bmiSrc.ulHeight - prectlScan->yTop;
    438     }
    439     pptlSrcOrg = (PPOINTL)prectlDst;
    440 
    441     /* Request HW */
    442     sHWReqIn.ulLength = sizeof(HWREQIN);
    443     sHWReqIn.ulFlags = REQUEST_HW;
    444     sHWReqIn.cScrChangeRects = 1;
    445     sHWReqIn.arectlScreen = &pVOData->rectlWin;
    446     if (pfnVMIEntry(0, VMI_CMD_REQUESTHW, &sHWReqIn, NULL) != RC_SUCCESS) {
    447         debug_os2("pfnVMIEntry(,VMI_CMD_REQUESTHW,,) failed");
    448         sHWReqIn.cScrChangeRects = 0; /* for fail signal only */
    449     } else {
    450         RECTL rclSrcBounds;
    451 
    452         rclSrcBounds.xLeft = 0;
    453         rclSrcBounds.yBottom = 0;
    454         rclSrcBounds.xRight = bmiSrc.ulWidth;
    455         rclSrcBounds.yTop = bmiSrc.ulHeight;
    456 
    457         sBitbltInfo.ulLength = sizeof(BITBLTINFO);
    458         sBitbltInfo.ulBltFlags = BF_DEFAULT_STATE | BF_ROP_INCL_SRC | BF_PAT_HOLLOW;
    459         sBitbltInfo.cBlits = cSDLRects;
    460         sBitbltInfo.ulROP = ROP_SRCCOPY;
    461         sBitbltInfo.pSrcBmapInfo = &bmiSrc;
    462         sBitbltInfo.pDstBmapInfo = &bmiDst;
    463         sBitbltInfo.prclSrcBounds = &rclSrcBounds;
    464         sBitbltInfo.prclDstBounds = &pVOData->rectlWin;
    465         sBitbltInfo.aptlSrcOrg = pptlSrcOrg;
    466         sBitbltInfo.abrDst = pbrDst;
    467 
    468         /* Screen update */
    469         if (pfnVMIEntry(0, VMI_CMD_BITBLT, &sBitbltInfo, NULL) != RC_SUCCESS) {
    470             debug_os2("pfnVMIEntry(,VMI_CMD_BITBLT,,) failed");
    471             sHWReqIn.cScrChangeRects = 0; /* for fail signal only */
    472         }
    473 
    474         /* Release HW */
    475         sHWReqIn.ulFlags = 0;
    476         if (pfnVMIEntry(0, VMI_CMD_REQUESTHW, &sHWReqIn, NULL) != RC_SUCCESS) {
    477           debug_os2("pfnVMIEntry(,VMI_CMD_REQUESTHW,,) failed");
    478         }
    479     }
    480 
    481     return sHWReqIn.cScrChangeRects != 0;
    482 }
    483 
    484 /* vi: set ts=4 sw=4 expandtab: */