/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * PURPOSE: GDI Driver Surace Functions * FILE: subsys/win32k/eng/surface.c * PROGRAMERS: Jason Filby * Timo Kreuzer * TESTING TO BE DONE: * - Create a GDI bitmap with all formats, perform all drawing operations on them, render to VGA surface * refer to \test\microwin\src\engine\devdraw.c for info on correct pixel plotting for various formats */ #include #define NDEBUG #include LONG giUniqueSurface = 0; UCHAR gajBitsPerFormat[11] = { 0, /* 0: unused */ 1, /* 1: BMF_1BPP */ 4, /* 2: BMF_4BPP */ 8, /* 3: BMF_8BPP */ 16, /* 4: BMF_16BPP */ 24, /* 5: BMF_24BPP */ 32, /* 6: BMF_32BPP */ 4, /* 7: BMF_4RLE */ 8, /* 8: BMF_8RLE */ 0, /* 9: BMF_JPEG */ 0, /* 10: BMF_PNG */ }; ULONG FASTCALL BitmapFormat(ULONG cBits, ULONG iCompression) { switch (iCompression) { case BI_RGB: /* Fall through */ case BI_BITFIELDS: if (cBits <= 1) return BMF_1BPP; if (cBits <= 4) return BMF_4BPP; if (cBits <= 8) return BMF_8BPP; if (cBits <= 16) return BMF_16BPP; if (cBits <= 24) return BMF_24BPP; if (cBits <= 32) return BMF_32BPP; return 0; case BI_RLE4: return BMF_4RLE; case BI_RLE8: return BMF_8RLE; default: return 0; } } BOOL NTAPI SURFACE_Cleanup(PVOID ObjectBody) { PSURFACE psurf = (PSURFACE)ObjectBody; PVOID pvBits = psurf->SurfObj.pvBits; /* Check if the surface has bits */ if (pvBits) { /* Only bitmaps can have bits */ ASSERT(psurf->SurfObj.iType == STYPE_BITMAP); /* Check if it is a DIB section */ if (psurf->hDIBSection) { /* Unmap the section view */ EngUnmapSectionView(pvBits, psurf->dwOffset, psurf->hSecure); } else if (psurf->SurfObj.fjBitmap & BMF_USERMEM) { /* Bitmap was allocated from usermode memory */ EngFreeUserMem(pvBits); } else if (psurf->SurfObj.fjBitmap & BMF_KMSECTION) { /* Bitmap was allocated from a kernel section */ if (!EngFreeSectionMem(NULL, pvBits)) { DPRINT1("EngFreeSectionMem failed for %p!\n", pvBits); // Should we BugCheck here? ASSERT(FALSE); } } else if (psurf->SurfObj.fjBitmap & BMF_POOLALLOC) { /* Free a pool allocation */ EngFreeMem(pvBits); } } /* Free palette */ if(psurf->ppal) { PALETTE_ShareUnlockPalette(psurf->ppal); } return TRUE; } PSURFACE NTAPI SURFACE_AllocSurface( _In_ USHORT iType, _In_ ULONG cx, _In_ ULONG cy, _In_ ULONG iFormat, _In_ ULONG fjBitmap, _In_opt_ ULONG cjWidth, _In_opt_ PVOID pvBits) { ULONG cBitsPixel, cjBits, cjObject; PSURFACE psurf; SURFOBJ *pso; PVOID pvSection; ASSERT(!pvBits || (iType == STYPE_BITMAP)); /* Verify format */ if ((iFormat < BMF_1BPP) || (iFormat > BMF_PNG)) { DPRINT1("Invalid bitmap format: %lu\n", iFormat); return NULL; } /* Get bits per pixel from the format */ cBitsPixel = gajBitsPerFormat[iFormat]; /* Are bits and a width in bytes given? */ if (pvBits && cjWidth) { /* Align the width (Windows compatibility, drivers expect that) */ cjWidth = WIDTH_BYTES_ALIGN32((cjWidth << 3) / cBitsPixel, cBitsPixel); } else { /* Calculate width from the bitmap width in pixels */ cjWidth = WIDTH_BYTES_ALIGN32(cx, cBitsPixel); } /* Calculate the bitmap size in bytes */ cjBits = cjWidth * cy; /* Check if we need an extra large object */ if ((iType == STYPE_BITMAP) && (pvBits == NULL) && !(fjBitmap & BMF_USERMEM) && !(fjBitmap & BMF_KMSECTION)) { /* Allocate an object large enough to hold the bits */ cjObject = sizeof(SURFACE) + cjBits; } else { /* Otherwise just allocate the SURFACE structure */ cjObject = sizeof(SURFACE); } /* Check for arithmetic overflow */ if ((cjBits < cjWidth) || (cjObject < sizeof(SURFACE))) { /* Fail! */ return NULL; } /* Allocate a SURFACE object */ psurf = (PSURFACE)GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_BITMAP, cjObject); if (!psurf) { return NULL; } /* Initialize the basic fields */ pso = &psurf->SurfObj; pso->hsurf = psurf->BaseObject.hHmgr; pso->sizlBitmap.cx = cx; pso->sizlBitmap.cy = cy; pso->iBitmapFormat = iFormat; pso->iType = iType; pso->fjBitmap = (USHORT)fjBitmap; pso->iUniq = InterlockedIncrement(&giUniqueSurface); pso->cjBits = cjBits; /* Check if we need a bitmap buffer */ if (iType == STYPE_BITMAP) { /* Check if we got one or if we need to allocate one */ if (pvBits != NULL) { /* Use the caller provided buffer */ pso->pvBits = pvBits; } else if (fjBitmap & BMF_USERMEM) { /* User mode memory was requested */ pso->pvBits = EngAllocUserMem(cjBits, 0); /* Check for failure */ if (!pso->pvBits) { GDIOBJ_vDeleteObject(&psurf->BaseObject); return NULL; } } else if (fjBitmap & BMF_KMSECTION) { /* Use a kernel mode section */ pso->pvBits = EngAllocSectionMem(&pvSection, (fjBitmap & BMF_NOZEROINIT) ? 0 : FL_ZERO_MEMORY, cjBits, TAG_DIB); /* Check for failure */ if (!pso->pvBits) { GDIOBJ_vDeleteObject(&psurf->BaseObject); return NULL; } /* Free the section already, but keep the mapping */ EngFreeSectionMem(pvSection, NULL); } else { /* Buffer is after the object */ pso->pvBits = psurf + 1; /* Zero the buffer, except requested otherwise */ if (!(fjBitmap & BMF_NOZEROINIT)) { RtlZeroMemory(pso->pvBits, cjBits); } } /* Set pvScan0 and lDelta */ if (fjBitmap & BMF_TOPDOWN) { /* Topdown is the normal way */ pso->pvScan0 = pso->pvBits; pso->lDelta = cjWidth; } else { /* Inversed bitmap (bottom up) */ pso->pvScan0 = ((PCHAR)pso->pvBits + pso->cjBits - cjWidth); pso->lDelta = -(LONG)cjWidth; } } else { /* There are no bitmap bits */ pso->pvScan0 = pso->pvBits = NULL; pso->lDelta = 0; } /* Assign a default palette and increment its reference count */ SURFACE_vSetPalette(psurf, appalSurfaceDefault[iFormat]); return psurf; } HBITMAP APIENTRY EngCreateBitmap( _In_ SIZEL sizl, _In_ LONG lWidth, _In_ ULONG iFormat, _In_ ULONG fl, _In_opt_ PVOID pvBits) { PSURFACE psurf; HBITMAP hbmp; /* Allocate a surface */ psurf = SURFACE_AllocSurface(STYPE_BITMAP, sizl.cx, sizl.cy, iFormat, fl, lWidth, pvBits); if (!psurf) { DPRINT1("SURFACE_AllocSurface failed.\n"); return NULL; } /* Get the handle for the bitmap */ hbmp = (HBITMAP)psurf->SurfObj.hsurf; /* Set public ownership */ GDIOBJ_vSetObjectOwner(&psurf->BaseObject, GDI_OBJ_HMGR_PUBLIC); /* Unlock the surface and return */ SURFACE_UnlockSurface(psurf); return hbmp; } /* * @implemented */ HBITMAP APIENTRY EngCreateDeviceBitmap( _In_ DHSURF dhsurf, _In_ SIZEL sizl, _In_ ULONG iFormat) { PSURFACE psurf; HBITMAP hbmp; /* Allocate a surface */ psurf = SURFACE_AllocSurface(STYPE_DEVBITMAP, sizl.cx, sizl.cy, iFormat, 0, 0, NULL); if (!psurf) { DPRINT1("SURFACE_AllocSurface failed.\n"); return NULL; } /* Set the device handle */ psurf->SurfObj.dhsurf = dhsurf; /* Set public ownership */ GDIOBJ_vSetObjectOwner(&psurf->BaseObject, GDI_OBJ_HMGR_PUBLIC); /* Get the handle for the bitmap */ hbmp = (HBITMAP)psurf->SurfObj.hsurf; /* Unlock the surface and return */ SURFACE_UnlockSurface(psurf); return hbmp; } HSURF APIENTRY EngCreateDeviceSurface( _In_ DHSURF dhsurf, _In_ SIZEL sizl, _In_ ULONG iFormat) { PSURFACE psurf; HSURF hsurf; /* Allocate a surface */ psurf = SURFACE_AllocSurface(STYPE_DEVICE, sizl.cx, sizl.cy, iFormat, 0, 0, NULL); if (!psurf) { DPRINT1("SURFACE_AllocSurface failed.\n"); return NULL; } /* Set the device handle */ psurf->SurfObj.dhsurf = dhsurf; /* Set public ownership */ GDIOBJ_vSetObjectOwner(&psurf->BaseObject, GDI_OBJ_HMGR_PUBLIC); /* Get the handle for the surface */ hsurf = psurf->SurfObj.hsurf; /* Unlock the surface and return */ SURFACE_UnlockSurface(psurf); return hsurf; } BOOL APIENTRY EngAssociateSurface( _In_ HSURF hsurf, _In_ HDEV hdev, _In_ FLONG flHooks) { SURFOBJ *pso; PSURFACE psurf; PDEVOBJ* ppdev; PPALETTE ppal; ppdev = (PDEVOBJ*)hdev; /* Lock the surface */ psurf = SURFACE_ShareLockSurface(hsurf); if (!psurf) { return FALSE; } pso = &psurf->SurfObj; /* Associate the hdev */ pso->hdev = hdev; pso->dhpdev = ppdev->dhpdev; /* Hook up specified functions */ psurf->flags &= ~HOOK_FLAGS; psurf->flags |= (flHooks & HOOK_FLAGS); /* Assign the PDEV's palette */ ppal = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault); SURFACE_vSetPalette(psurf, ppal); PALETTE_ShareUnlockPalette(ppal); SURFACE_ShareUnlockSurface(psurf); return TRUE; } BOOL APIENTRY EngModifySurface( _In_ HSURF hsurf, _In_ HDEV hdev, _In_ FLONG flHooks, _In_ FLONG flSurface, _In_ DHSURF dhsurf, _In_ VOID *pvScan0, _In_ LONG lDelta, _Reserved_ VOID *pvReserved) { SURFOBJ *pso; PSURFACE psurf; PDEVOBJ* ppdev; PPALETTE ppal; psurf = SURFACE_ShareLockSurface(hsurf); if (psurf == NULL) { return FALSE; } ppdev = (PDEVOBJ*)hdev; pso = &psurf->SurfObj; pso->dhsurf = dhsurf; pso->lDelta = lDelta; pso->pvScan0 = pvScan0; /* Associate the hdev */ pso->hdev = hdev; pso->dhpdev = ppdev->dhpdev; /* Hook up specified functions */ psurf->flags &= ~HOOK_FLAGS; psurf->flags |= (flHooks & HOOK_FLAGS); /* Assign the PDEV's palette */ ppal = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault); SURFACE_vSetPalette(psurf, ppal); PALETTE_ShareUnlockPalette(ppal); SURFACE_ShareUnlockSurface(psurf); return TRUE; } BOOL APIENTRY EngDeleteSurface( _In_ _Post_ptr_invalid_ HSURF hsurf) { PSURFACE psurf; psurf = SURFACE_ShareLockSurface(hsurf); if (!psurf) { DPRINT1("Could not reference surface to delete\n"); return FALSE; } GDIOBJ_vDeleteObject(&psurf->BaseObject); return TRUE; } BOOL APIENTRY EngEraseSurface( _In_ SURFOBJ *pso, _In_ RECTL *prcl, _In_ ULONG iColor) { ASSERT(pso); ASSERT(prcl); return FillSolid(pso, prcl, iColor); } /* * @implemented */ SURFOBJ * APIENTRY NtGdiEngLockSurface(IN HSURF hsurf) { return EngLockSurface(hsurf); } SURFOBJ * APIENTRY EngLockSurface( _In_ HSURF hsurf) { SURFACE *psurf = SURFACE_ShareLockSurface(hsurf); return psurf ? &psurf->SurfObj : NULL; } VOID APIENTRY NtGdiEngUnlockSurface(IN SURFOBJ *pso) { UNIMPLEMENTED; ASSERT(FALSE); } VOID APIENTRY EngUnlockSurface( _In_ _Post_ptr_invalid_ SURFOBJ *pso) { if (pso != NULL) { SURFACE *psurf = CONTAINING_RECORD(pso, SURFACE, SurfObj); SURFACE_ShareUnlockSurface(psurf); } } /* EOF */