SDL  2.0
SDL_os2vman.c
Go to the documentation of this file.
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;
39  ULONG ulBPP;
41  ULONG ulWidth;
42  ULONG ulHeight;
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 
68  voOpen,
69  voClose,
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: */
#define SDL_SetError
#define SDL_realloc
#define SDL_free
#define SDL_calloc
#define SDL_OutOfMemory()
Definition: SDL_error.h:88
#define APIENTRY
Definition: SDL_opengl.h:139
#define debug_os2(s,...)
Definition: SDL_os2.h:38
struct _VODATA * PVODATA
Definition: SDL_os2output.h:26
VOID APIENTRY ExitVMan(VOID)
Definition: SDL_os2vman.c:81
OS2VIDEOOUTPUT voVMan
Definition: SDL_os2vman.c:66
static ULONG ulVRAMAddress
Definition: SDL_os2vman.c:79
static PVODATA voOpen()
Definition: SDL_os2vman.c:196
static BOOL voSetVisibleRegion(PVODATA pVOData, HWND hwnd, SDL_DisplayMode *pSDLDisplayMode, HRGN hrgnShape, BOOL fVisible)
Definition: SDL_os2vman.c:223
static BOOL voQueryInfo(VIDEOOUTPUTINFO *pInfo)
Definition: SDL_os2vman.c:172
static BOOL voUpdate(PVODATA pVOData, HWND hwnd, SDL_Rect *pSDLRects, ULONG cSDLRects)
Definition: SDL_os2vman.c:317
static VOID voClose(PVODATA pVOData)
Definition: SDL_os2vman.c:212
static FNVMIENTRY * pfnVMIEntry
Definition: SDL_os2vman.c:78
static PVOID voVideoBufAlloc(PVODATA pVOData, ULONG ulWidth, ULONG ulHeight, ULONG ulBPP, ULONG fccColorEncoding, PULONG pulScanLineSize)
Definition: SDL_os2vman.c:269
static VOID voVideoBufFree(PVODATA pVOData)
Definition: SDL_os2vman.c:302
static HMODULE hmodVMan
Definition: SDL_os2vman.c:77
static BOOL _vmanInit(void)
Definition: SDL_os2vman.c:91
static PRECTL _getRectlArray(PVODATA pVOData, ULONG cRects)
Definition: SDL_os2vman.c:139
static PBLTRECT _getBltRectArray(PVODATA pVOData, ULONG cRects)
Definition: SDL_os2vman.c:155
#define NULL
Definition: begin_code.h:163
#define TRUE
Definition: edid-parse.c:33
#define FALSE
Definition: edid-parse.c:34
The structure that defines a display mode.
Definition: SDL_video.h:54
void * driverdata
Definition: SDL_video.h:59
A rectangle, with the origin at the upper left (integer).
Definition: SDL_rect.h:78
int h
Definition: SDL_rect.h:80
int w
Definition: SDL_rect.h:80
int y
Definition: SDL_rect.h:79
int x
Definition: SDL_rect.h:79
ULONG fccColorEncoding
Definition: SDL_os2output.h:30
ULONG ulVertResolution
Definition: SDL_os2output.h:33
ULONG ulHorizResolution
Definition: SDL_os2output.h:32
HRGN hrgnVisible
Definition: SDL_os2vman.c:38
ULONG ulScreenHeight
Definition: SDL_os2vman.c:43
ULONG ulScreenBytesPerLine
Definition: SDL_os2vman.c:44
ULONG ulScanLineSize
Definition: SDL_os2vman.c:40
ULONG cBltRect
Definition: SDL_os2vman.c:50
ULONG ulBPP
Definition: SDL_os2vman.c:39
ULONG cRectl
Definition: SDL_os2vman.c:48
PBLTRECT pBltRect
Definition: SDL_os2vman.c:49
PRECTL pRectl
Definition: SDL_os2vman.c:47
RECTL rectlWin
Definition: SDL_os2vman.c:45