Skip to content

Instantly share code, notes, and snippets.

@0xABADCAFE
Created June 5, 2022 11:22
Show Gist options
  • Save 0xABADCAFE/21820334fa39b6d5bc3edff1d9a03197 to your computer and use it in GitHub Desktop.
Save 0xABADCAFE/21820334fa39b6d5bc3edff1d9a03197 to your computer and use it in GitHub Desktop.
Packed V Planar: FIGHT
/**
* 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