Created
June 5, 2022 11:22
-
-
Save 0xABADCAFE/21820334fa39b6d5bc3edff1d9a03197 to your computer and use it in GitHub Desktop.
Packed V Planar: FIGHT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Packed Vs Planar | |
* | |
* gcc -std=c99 -Wall -W -Werror -O3 pvp.c -o pvp | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#ifdef __LP64__ | |
typedef signed char int8; | |
typedef signed short int int16; | |
typedef signed int int32; | |
typedef signed long int int64; | |
typedef unsigned char uint8; | |
typedef unsigned short int uint16; | |
typedef unsigned int uint32; | |
typedef unsigned long int uint64; | |
typedef float float32; | |
typedef double float64; | |
#define FS16 "hd" | |
#define FU16 "hu" | |
#define FS32 "d" | |
#define FU32 "u" | |
#define FS64 "ld" | |
#define FU64 "lu" | |
#else | |
typedef signed char int8; | |
typedef signed short int int16; | |
typedef signed long int int32; | |
typedef signed long long int int64; | |
typedef unsigned char uint8; | |
typedef unsigned short int uint16; | |
typedef unsigned long int uint32; | |
typedef unsigned long long int uint64; | |
typedef float float32; | |
typedef double float64; | |
#define FS16 "hd" | |
#define FU16 "hu" | |
#define FS32 "ld" | |
#define FU32 "lu" | |
#define FS64 "lld" | |
#define FU64 "llu" | |
#endif | |
enum { | |
MIN_DIMENSION = 8, | |
MAX_DIMENSION = 65536, | |
}; | |
/** | |
* Basic depth enumeration | |
*/ | |
typedef enum { | |
BPP_1 = 1, | |
BPP_2 = 2, | |
BPP_3 = 3, | |
BPP_4 = 4, | |
BPP_5 = 5, | |
BPP_6 = 6, | |
BPP_7 = 7, | |
BPP_8 = 8 | |
} Depth; | |
/** | |
* Basic Bitmap properties | |
*/ | |
typedef struct { | |
/** | |
* User requested dimensions, in pixels | |
*/ | |
uint32 uWidth; | |
uint32 uHeight; | |
Depth eDepth; | |
/** | |
* Allocator calculated dimensions. Ensures each row aligns to a 32-bit boundary, regardless | |
* of the requested depth and width. | |
*/ | |
uint32 uAlignedWidth; | |
uint32 uBytesPerRow; | |
} BitmapProperties; | |
/** | |
* Basic data pointer for pixel data access. | |
*/ | |
typedef union { | |
uint8* u8; | |
uint16* u16; | |
uint32* u32; | |
uint64* u64; | |
void* any; | |
} DataPtr; | |
/** | |
* Planar Bitmap. Structure is open-ended so do not assume the size. The correct stucture size | |
* depends on the number of bits per pixel, with a pointer per plane. | |
* | |
* Each plane has a 32-bit aligned width so that each row begins on a 32-bit boundary. | |
*/ | |
typedef struct { | |
BitmapProperties oProperties; | |
DataPtr pPlaneData[1]; | |
} PlanarBitmap; | |
/** | |
* Packed Bitmap. The pixel data is in a single allocation. The width is aligned such that each | |
* row begins on a 32-bit boundary. | |
*/ | |
typedef struct { | |
BitmapProperties oProperties; | |
DataPtr pPackedData; | |
} PackedBitmap; | |
/*************************************************************************************************/ | |
/** | |
* Allocates a PlanarBitmap. Returns NULL if the allocation fails for any reason. | |
* | |
* @param uint32 uWidth | |
* @param uint32 uHeight | |
* @param Depth eDepth | |
* @return PlanarBitmap* | |
*/ | |
PlanarBitmap* AllocatePlanar(uint32 uWidth, uint32 uHeight, Depth eDepth); | |
/** | |
* Free a PlanarBitmap. Null safe. | |
* | |
* @param PlanarBitmap | |
*/ | |
void FreePlanar(PlanarBitmap* pBitmap); | |
/** | |
* Allocates a packed PlanarBitmap. Returns NULL if the allocation fails for any reason. | |
* | |
* @param uint32 uWidth | |
* @param uint32 uHeight | |
* @param Depth eDepth | |
* @return PackedBitmap* | |
*/ | |
PackedBitmap* AllocatePacked(uint32 uWidth, uint32 uHeight, Depth eDepth); | |
/** | |
* Free a PackedBitmap. Null safe. | |
* | |
* @param PackedBitmap | |
*/ | |
void FreePacked(PackedBitmap* pBitmap); | |
/*************************************************************************************************/ | |
int main(void) { | |
for (Depth i = BPP_1; i <= BPP_8; ++i) { | |
PlanarBitmap* pPlanar = AllocatePlanar(100, 100, i); | |
FreePlanar(pPlanar); | |
PackedBitmap* pPacked = AllocatePacked(100, 100, i); | |
FreePacked(pPacked); | |
} | |
return 0; | |
} | |
/*************************************************************************************************/ | |
bool CheckDimensions(uint32 uWidth, uint32 uHeight) { | |
if ( | |
uWidth < MIN_DIMENSION || | |
uWidth > MAX_DIMENSION || | |
uHeight < MIN_DIMENSION || | |
uHeight > MAX_DIMENSION | |
) { | |
fprintf( | |
stderr, | |
"Invalid dimensions %" FU32 " x %" FU32 "\n", | |
uWidth, | |
uHeight | |
); | |
return false; | |
} | |
return true; | |
} | |
PlanarBitmap* AllocatePlanar(uint32 uWidth, uint32 uHeight, Depth eDepth) { | |
if (CheckDimensions(uWidth, uHeight)) { | |
uint32 uAlignedWidth = (uWidth + 31) & ~31; | |
size_t uPlaneSize = (uAlignedWidth * uHeight) >> 3; | |
size_t uStructSize = sizeof(PlanarBitmap) + sizeof(DataPtr) * (eDepth - 1); | |
size_t uTotalAlloc = uStructSize + uPlaneSize * eDepth; | |
PlanarBitmap* pBitmap = (PlanarBitmap*)malloc(uTotalAlloc); | |
fprintf( | |
stderr, | |
"AllocatePlanar()\n\tRequested: %" FU32 " x %" FU32 " x %d BPP\n" | |
"\tAligned width : %" FU32 "\n" | |
"\tPlane Size : %zu bytes\n" | |
"\tStruct Size : %zu bytes\n" | |
"\tTotal Size : %zu bytes\n" | |
"\tAllocated at : %p\n", | |
uWidth, | |
uHeight, | |
eDepth, | |
uAlignedWidth, | |
uPlaneSize, | |
uStructSize, | |
uTotalAlloc, | |
pBitmap | |
); | |
if (pBitmap) { | |
pBitmap->oProperties.uWidth = uWidth; | |
pBitmap->oProperties.uHeight = uHeight; | |
pBitmap->oProperties.eDepth = eDepth; | |
pBitmap->oProperties.uAlignedWidth = uAlignedWidth; | |
pBitmap->oProperties.uBytesPerRow = uAlignedWidth >> 3; | |
DataPtr pPlane; | |
pPlane.any = pBitmap; | |
pPlane.u8 += sizeof(PlanarBitmap) + sizeof(DataPtr) * (eDepth - 1); | |
for (int i=0; i < (int)eDepth; ++i) { | |
pBitmap->pPlaneData[i].u8 = pPlane.u8; | |
fprintf( | |
stderr, | |
"\t\tPlane[%d] @ %p\n", | |
i, | |
pPlane.u8 | |
); | |
pPlane.u8 += uPlaneSize; | |
} | |
} | |
return pBitmap; | |
} | |
return NULL; | |
} | |
void FreePlanar(PlanarBitmap* pBitmap) { | |
if (pBitmap) { | |
free(pBitmap); | |
} | |
} | |
PackedBitmap* AllocatePacked(uint32 uWidth, uint32 uHeight, Depth eDepth) { | |
if (CheckDimensions(uWidth, uHeight)) { | |
uint32 uAlignMask; | |
switch (eDepth) { | |
case BPP_2: | |
case BPP_6: | |
uAlignMask = 15; | |
break; | |
case BPP_4: | |
uAlignMask = 7; | |
break; | |
case BPP_8: | |
uAlignMask = 3; | |
break; | |
default: | |
uAlignMask = 31; | |
break; | |
} | |
uint32 uAlignedWidth = (uWidth + uAlignMask) & ~uAlignMask; | |
uint32 uBytesPerRow = (uAlignedWidth * eDepth) >> 3; | |
size_t uPackedSize = uBytesPerRow * uHeight; | |
size_t uStructSize = sizeof(PackedBitmap); | |
size_t uTotalAlloc = uStructSize + uPackedSize; | |
PackedBitmap* pBitmap = (PackedBitmap*)malloc(uTotalAlloc); | |
fprintf( | |
stderr, | |
"AllocatePacked()\n\tRequested: %" FU32 " x %" FU32 " x %d BPP\n" | |
"\tAligned width : %" FU32 "\n" | |
"\tPacked Size : %zu bytes\n" | |
"\tStruct Size : %zu bytes\n" | |
"\tTotal Size : %zu bytes\n" | |
"\tAllocated at : %p\n", | |
uWidth, | |
uHeight, | |
eDepth, | |
uAlignedWidth, | |
uPackedSize, | |
uStructSize, | |
uTotalAlloc, | |
pBitmap | |
); | |
if (pBitmap) { | |
pBitmap->oProperties.uWidth = uWidth; | |
pBitmap->oProperties.uHeight = uHeight; | |
pBitmap->oProperties.eDepth = eDepth; | |
pBitmap->oProperties.uAlignedWidth = uAlignedWidth; | |
pBitmap->oProperties.uBytesPerRow = uBytesPerRow; | |
pBitmap->pPackedData.u8 = ((uint8*)pBitmap) + uStructSize; | |
} | |
return pBitmap; | |
} | |
return NULL; | |
} | |
void FreePacked(PackedBitmap* pBitmap) { | |
if (pBitmap) { | |
free(pBitmap); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment