2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: GDI Driver Surace Functions
5 * FILE: subsys/win32k/eng/surface.c
6 * PROGRAMER: Jason Filby
9 * 9/11/2000: Updated to handle real pixel packed bitmaps (UPDATE TO DATE COMPLETED)
11 * - Create a GDI bitmap with all formats, perform all drawing operations on them, render to VGA surface
12 * refer to \test\microwin\src\engine\devdraw.c for info on correct pixel plotting for various formats
22 RLE_EOL
= 0, /* End of line */
23 RLE_END
= 1, /* End of bitmap */
24 RLE_DELTA
= 2 /* Delta */
27 INT FASTCALL
BitsPerFormat(ULONG Format
)
58 ULONG FASTCALL
BitmapFormat(WORD Bits
, DWORD Compression
)
94 SURFACE_Cleanup(PVOID ObjectBody
)
96 PSURFACE psurf
= (PSURFACE
)ObjectBody
;
97 PVOID pvBits
= psurf
->SurfObj
.pvBits
;
99 /* If this is an API bitmap, free the bits */
100 if (pvBits
!= NULL
&&
101 (psurf
->flFlags
& BITMAPOBJ_IS_APIBITMAP
))
103 /* Check if we have a DIB section */
106 // FIXME: IMPLEMENT ME!
107 // MmUnsecureVirtualMemory(psurf->hSecure);
108 if (psurf
->hDIBSection
)
110 /* DIB was created from a section */
113 pvBits
= (PVOID
)((ULONG_PTR
)pvBits
- psurf
->dwOffset
);
114 Status
= ZwUnmapViewOfSection(NtCurrentProcess(), pvBits
);
115 if (!NT_SUCCESS(Status
))
117 DPRINT1("Could not unmap section view!\n");
118 // Should we BugCheck here?
123 /* DIB was allocated */
124 EngFreeUserMem(pvBits
);
130 ExFreePool(psurf
->SurfObj
.pvBits
);
133 if (psurf
->hDIBPalette
!= NULL
)
135 GreDeleteObject(psurf
->hDIBPalette
);
139 if (NULL
!= psurf
->BitsLock
)
141 ExFreePoolWithTag(psurf
->BitsLock
, TAG_SURFACE
);
142 psurf
->BitsLock
= NULL
;
149 SURFACE_InitBitsLock(PSURFACE psurf
)
151 psurf
->BitsLock
= ExAllocatePoolWithTag(NonPagedPool
,
154 if (NULL
== psurf
->BitsLock
)
159 ExInitializeFastMutex(psurf
->BitsLock
);
165 SURFACE_CleanupBitsLock(PSURFACE psurf
)
167 if (NULL
!= psurf
->BitsLock
)
169 ExFreePoolWithTag(psurf
->BitsLock
, TAG_SURFACE
);
170 psurf
->BitsLock
= NULL
;
179 EngCreateDeviceBitmap(IN DHSURF dhsurf
,
186 NewBitmap
= EngCreateBitmap(Size
, DIB_GetDIBWidthBytes(Size
.cx
, BitsPerFormat(Format
)), Format
, 0, NULL
);
189 DPRINT1("EngCreateBitmap failed\n");
193 pso
= EngLockSurface((HSURF
)NewBitmap
);
196 DPRINT1("EngLockSurface failed on newly created bitmap!\n");
197 GreDeleteObject(NewBitmap
);
201 pso
->dhsurf
= dhsurf
;
202 EngUnlockSurface(pso
);
207 BOOL
DecompressBitmap(SIZEL Size
, BYTE
*CompressedBits
, BYTE
*UncompressedBits
, LONG Delta
, ULONG Format
)
214 INT height
= Size
.cy
- 1;
215 BYTE
*begin
= CompressedBits
;
216 BYTE
*bits
= CompressedBits
;
220 if (Format
== BMF_4RLE
)
222 else if(Format
!= BMF_8RLE
)
225 width
= ((Size
.cx
+ shift
) >> shift
);
231 length
= (*bits
++) >> shift
;
237 if (x
>= width
) break;
238 temp
= UncompressedBits
+ (((height
- y
) * Delta
) + x
);
253 _SEH2_YIELD(return TRUE
);
255 x
+= (*bits
++) >> shift
;
256 y
-= (*bits
++) >> shift
;
259 length
= length
>> shift
;
265 temp
= UncompressedBits
+ (((height
- y
) * Delta
) + x
);
270 if ((bits
- begin
) & 1)
278 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
280 DPRINT1("Decoding error\n");
281 _SEH2_YIELD(return FALSE
);
289 IntCreateBitmap(IN SIZEL Size
,
298 PVOID UncompressedBits
;
299 ULONG UncompressedFormat
;
304 psurf
= SURFACE_AllocSurfaceWithHandle();
309 hbmp
= psurf
->BaseObject
.hHmgr
;
311 if (! SURFACE_InitBitsLock(psurf
))
313 SURFACE_UnlockSurface(psurf
);
314 SURFACE_FreeSurfaceByHandle(hbmp
);
317 pso
= &psurf
->SurfObj
;
319 if (Format
== BMF_4RLE
)
321 pso
->lDelta
= DIB_GetDIBWidthBytes(Size
.cx
, BitsPerFormat(BMF_4BPP
));
322 pso
->cjBits
= pso
->lDelta
* Size
.cy
;
323 UncompressedFormat
= BMF_4BPP
;
324 UncompressedBits
= EngAllocMem(FL_ZERO_MEMORY
, pso
->cjBits
, TAG_DIB
);
325 DecompressBitmap(Size
, (BYTE
*)Bits
, (BYTE
*)UncompressedBits
, pso
->lDelta
, Format
);
327 else if (Format
== BMF_8RLE
)
329 pso
->lDelta
= DIB_GetDIBWidthBytes(Size
.cx
, BitsPerFormat(BMF_8BPP
));
330 pso
->cjBits
= pso
->lDelta
* Size
.cy
;
331 UncompressedFormat
= BMF_8BPP
;
332 UncompressedBits
= EngAllocMem(FL_ZERO_MEMORY
, pso
->cjBits
, TAG_DIB
);
333 DecompressBitmap(Size
, (BYTE
*)Bits
, (BYTE
*)UncompressedBits
, pso
->lDelta
, Format
);
337 pso
->lDelta
= abs(Width
);
338 pso
->cjBits
= pso
->lDelta
* Size
.cy
;
339 UncompressedBits
= Bits
;
340 UncompressedFormat
= Format
;
343 if (UncompressedBits
!= NULL
)
345 pso
->pvBits
= UncompressedBits
;
349 if (pso
->cjBits
== 0)
355 if (0 != (Flags
& BMF_USERMEM
))
357 pso
->pvBits
= EngAllocUserMem(pso
->cjBits
, 0);
361 pso
->pvBits
= EngAllocMem(0 != (Flags
& BMF_NOZEROINIT
) ?
363 pso
->cjBits
, TAG_DIB
);
365 if (pso
->pvBits
== NULL
)
367 SURFACE_UnlockSurface(psurf
);
368 SURFACE_FreeSurfaceByHandle(hbmp
);
369 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
375 if (0 == (Flags
& BMF_TOPDOWN
))
377 pso
->pvScan0
= (PVOID
)((ULONG_PTR
)pso
->pvBits
+ pso
->cjBits
- pso
->lDelta
);
378 pso
->lDelta
= - pso
->lDelta
;
382 pso
->pvScan0
= pso
->pvBits
;
385 pso
->dhsurf
= 0; /* device managed surface */
386 pso
->hsurf
= (HSURF
)hbmp
;
389 pso
->sizlBitmap
= Size
;
390 pso
->iBitmapFormat
= UncompressedFormat
;
391 pso
->iType
= STYPE_BITMAP
;
392 pso
->fjBitmap
= Flags
& (BMF_TOPDOWN
| BMF_NOZEROINIT
);
397 psurf
->dimension
.cx
= 0;
398 psurf
->dimension
.cy
= 0;
400 psurf
->hSecure
= NULL
;
401 psurf
->hDIBSection
= NULL
;
403 SURFACE_UnlockSurface(psurf
);
408 /* Name gleaned from C++ symbol information for SURFMEM::bInitDIB */
409 typedef struct _DEVBITMAPINFO
416 } DEVBITMAPINFO
, *PDEVBITMAPINFO
;
420 SURFMEM_bCreateDib(IN PDEVBITMAPINFO BitmapInfo
,
423 BOOLEAN Compressed
= FALSE
;
424 ULONG ScanLine
= 0; // Compiler is dumb
429 BOOLEAN AllocatedLocally
= FALSE
;
430 PVOID DecompressedBits
= NULL
;
433 * First, check the format so we can get the aligned scanline width.
434 * RLE and the newer fancy-smanshy JPG/PNG support do NOT have scanlines
435 * since they are compressed surfaces!
437 switch (BitmapInfo
->Format
)
440 ScanLine
= ((BitmapInfo
->Width
+ 31) & ~31) >> 3;
444 ScanLine
= ((BitmapInfo
->Width
+ 7) & ~7) >> 1;
448 ScanLine
= (BitmapInfo
->Width
+ 3) & ~3;
452 ScanLine
= ((BitmapInfo
->Width
+ 1) & ~1) << 1;
456 ScanLine
= ((BitmapInfo
->Width
* 3) + 3) & ~3;
460 ScanLine
= BitmapInfo
->Width
<< 2;
464 ScanLine
= (BitmapInfo
->Width
+ 3) & ~3;
468 ScanLine
= ((BitmapInfo
->Width
+ 7) & ~7) >> 1;
474 ASSERT(FALSE
); // ENGDDI shouldn't be creating PNGs for drivers ;-)
475 DPRINT1("No support for JPEG and PNG formats\n");
479 DPRINT1("Invalid bitmap format\n");
483 /* Save local bitmap size */
484 LocalSize
.cy
= BitmapInfo
->Height
;
485 LocalSize
.cx
= BitmapInfo
->Width
;
487 /* Does the device manage its own surface? */
490 /* We need to allocate bits for the caller, figure out the size */
493 /* Note: we should not be seeing this scenario from ENGDDI */
495 DPRINT1("RLE compressed bitmap requested with no valid bitmap bits\n");
500 /* The height times the bytes for each scanline */
501 Size
= BitmapInfo
->Height
* ScanLine
;
506 /* Check for allocation flag */
507 if (BitmapInfo
->Flags
& BMF_USERMEM
)
509 /* Get the bits from user-mode memory */
510 Bits
= EngAllocUserMem(Size
, 'mbuG');
514 /* Get kernel bits (zeroed out if requested) */
515 Bits
= EngAllocMem((BitmapInfo
->Flags
& BMF_NOZEROINIT
) ? 0 : FL_ZERO_MEMORY
,
519 AllocatedLocally
= TRUE
;
520 /* Bail out if that failed */
521 if (!Bits
) return NULL
;
526 /* Should not have asked for user memory */
527 ASSERT((BitmapInfo
->Flags
& BMF_USERMEM
) == 0);
531 DecompressedBits
= EngAllocMem(FL_ZERO_MEMORY
, BitmapInfo
->Height
* ScanLine
, TAG_DIB
);
533 if(!DecompressedBits
)
536 if(!DecompressBitmap(LocalSize
, (BYTE
*)Bits
, (BYTE
*)DecompressedBits
, ScanLine
, BitmapInfo
->Format
))
538 EngFreeMem(DecompressedBits
);
542 BitmapInfo
->Format
= (BitmapInfo
->Format
== BMF_4RLE
) ? BMF_4BPP
: BMF_8BPP
;
546 /* Allocate the actual surface object structure */
547 psurf
= SURFACE_AllocSurfaceWithHandle();
550 if(Bits
&& AllocatedLocally
)
552 if(BitmapInfo
->Flags
& BMF_USERMEM
)
553 EngFreeUserMem(Bits
);
557 if (DecompressedBits
)
558 EngFreeMem(DecompressedBits
);
562 /* Lock down the surface */
563 if (!SURFACE_InitBitsLock(psurf
))
565 /* Bail out if that failed */
566 SURFACE_UnlockSurface(psurf
);
567 SURFACE_FreeSurfaceByHandle(psurf
->BaseObject
.hHmgr
);
571 /* We should now have our surface object */
572 pso
= &psurf
->SurfObj
;
574 /* Save format and flags */
575 pso
->iBitmapFormat
= BitmapInfo
->Format
;
576 pso
->fjBitmap
= BitmapInfo
->Flags
& (BMF_TOPDOWN
| BMF_UMPDMEM
| BMF_USERMEM
);
578 /* Save size and type */
579 pso
->sizlBitmap
= LocalSize
;
580 pso
->iType
= STYPE_BITMAP
;
582 /* Device-managed surface, no flags or dimension */
587 psurf
->dimension
.cx
= 0;
588 psurf
->dimension
.cy
= 0;
589 psurf
->hSecure
= NULL
;
590 psurf
->hDIBSection
= NULL
;
595 pso
->pvBits
= DecompressedBits
;
599 /* Number of bits is based on the height times the scanline */
600 pso
->cjBits
= BitmapInfo
->Height
* ScanLine
;
601 if (BitmapInfo
->Flags
& BMF_TOPDOWN
)
603 /* For topdown, the base address starts with the bits */
604 pso
->pvScan0
= pso
->pvBits
;
605 pso
->lDelta
= ScanLine
;
609 /* Otherwise we start with the end and go up */
610 pso
->pvScan0
= (PVOID
)((ULONG_PTR
)pso
->pvBits
+ pso
->cjBits
- ScanLine
);
611 pso
->lDelta
= -ScanLine
;
614 /* Finally set the handle and uniq */
615 pso
->hsurf
= (HSURF
)psurf
->BaseObject
.hHmgr
;
618 /* Unlock and return the surface */
619 SURFACE_UnlockSurface(psurf
);
628 EngCreateBitmap(IN SIZEL Size
,
635 DEVBITMAPINFO BitmapInfo
;
637 /* Capture the parameters */
638 BitmapInfo
.Format
= Format
;
639 BitmapInfo
.Width
= Size
.cx
;
640 BitmapInfo
.Height
= Size
.cy
;
641 BitmapInfo
.Flags
= Flags
;
644 * If the display driver supports framebuffer access, use the scanline width
645 * to determine the actual width of the bitmap, and convert it to pels instead
648 if ((Bits
) && (Width
))
650 switch (BitmapInfo
.Format
)
652 /* Do the conversion for each bit depth we support */
654 BitmapInfo
.Width
= Width
* 8;
657 BitmapInfo
.Width
= Width
* 2;
660 BitmapInfo
.Width
= Width
;
663 BitmapInfo
.Width
= Width
/ 2;
666 BitmapInfo
.Width
= Width
/ 3;
669 BitmapInfo
.Width
= Width
/ 4;
674 /* Now create the surface */
675 Surface
= SURFMEM_bCreateDib(&BitmapInfo
, Bits
);
676 if (!Surface
) return 0;
678 /* Set public ownership and reutrn the handle */
679 GDIOBJ_SetOwnership(Surface
->hsurf
, NULL
);
680 return Surface
->hsurf
;
687 EngCreateDeviceSurface(IN DHSURF dhsurf
,
695 psurf
= SURFACE_AllocSurfaceWithHandle();
701 hsurf
= psurf
->BaseObject
.hHmgr
;
702 GDIOBJ_SetOwnership(hsurf
, NULL
);
704 if (!SURFACE_InitBitsLock(psurf
))
706 SURFACE_UnlockSurface(psurf
);
707 SURFACE_FreeSurfaceByHandle(hsurf
);
710 pso
= &psurf
->SurfObj
;
712 pso
->dhsurf
= dhsurf
;
714 pso
->sizlBitmap
= Size
;
715 pso
->iBitmapFormat
= Format
;
716 pso
->lDelta
= DIB_GetDIBWidthBytes(Size
.cx
, BitsPerFormat(Format
));
717 pso
->iType
= STYPE_DEVICE
;
722 SURFACE_UnlockSurface(psurf
);
741 ppdev
= (PDEVOBJ
*)hdev
;
743 /* Lock the surface */
744 psurf
= SURFACE_LockSurface(hsurf
);
749 pso
= &psurf
->SurfObj
;
751 /* Associate the hdev */
753 pso
->dhpdev
= ppdev
->dhpdev
;
755 /* Hook up specified functions */
756 psurf
->flHooks
= flHooks
;
758 SURFACE_UnlockSurface(psurf
);
781 psurf
= SURFACE_LockSurface(hsurf
);
787 ppdev
= (PDEVOBJ
*)hdev
;
788 pso
= &psurf
->SurfObj
;
789 pso
->dhsurf
= dhsurf
;
790 pso
->lDelta
= lDelta
;
791 pso
->pvScan0
= pvScan0
;
793 /* Associate the hdev */
795 pso
->dhpdev
= ppdev
->dhpdev
;
797 /* Hook up specified functions */
798 psurf
->flHooks
= flHooks
;
800 SURFACE_UnlockSurface(psurf
);
809 EngDeleteSurface(IN HSURF hsurf
)
811 GDIOBJ_SetOwnership(hsurf
, PsGetCurrentProcess());
812 SURFACE_FreeSurfaceByHandle(hsurf
);
820 EngEraseSurface(SURFOBJ
*pso
,
826 return FillSolid(pso
, Rect
, iColor
);
833 NtGdiEngLockSurface(IN HSURF hsurf
)
835 return EngLockSurface(hsurf
);
843 EngLockSurface(IN HSURF hsurf
)
845 SURFACE
*psurf
= GDIOBJ_ShareLockObj(hsurf
, GDI_OBJECT_TYPE_BITMAP
);
848 return &psurf
->SurfObj
;
858 NtGdiEngUnlockSurface(IN SURFOBJ
*pso
)
860 EngUnlockSurface(pso
);
867 EngUnlockSurface(IN SURFOBJ
*pso
)
871 SURFACE
*psurf
= CONTAINING_RECORD(pso
, SURFACE
, SurfObj
);
872 GDIOBJ_ShareUnlockObjByPtr((POBJ
)psurf
);