Exemplo n.º 1
0
void
newLife(
    LIFE_T *life,
    int32_t size)
{
    life->width = size;
    life->height = size;
    life->alignedWidth = ALIGN_TO_16(life->width);
    life->alignedHeight = ALIGN_TO_16(life->height);
    life->pitch = ALIGN_TO_16(life->width);

    life->buffer = calloc(1, life->pitch * life->alignedHeight);

    if (life->buffer == NULL)
    {
        fprintf(stderr, "life: memory exhausted\n");
        exit(EXIT_FAILURE);
    }

    life->fieldLength = life->width * life->height;

    life->field = calloc(1, life->fieldLength);

    if (life->field == NULL)
    {
        fprintf(stderr, "life: memory exhausted\n");
        exit(EXIT_FAILURE);
    }

    life->fieldNext = calloc(1, life->fieldLength);

    if (life->fieldNext == NULL)
    {
        fprintf(stderr, "life: memory exhausted\n");
        exit(EXIT_FAILURE);
    }

    struct timeval tv;
    gettimeofday(&tv, NULL);
    srand(tv.tv_usec);

    int32_t row = 0;
    for (row = 0 ; row < life->height ; row++)
    {
        int32_t col = 0;
        for (col = 0 ; col < life->width ; col++)
        {
            if (rand() > (RAND_MAX / 2))
            {
                setCell(life, col, row);
            }
            else
            {
                life->buffer[col + (row * life->alignedWidth)] = DEAD;
            }
        }
    }

    //---------------------------------------------------------------------

    VC_IMAGE_TYPE_T type = VC_IMAGE_8BPP;
    uint32_t vc_image_ptr;
    int result = 0;

    life->frontResource = 
        vc_dispmanx_resource_create(
            type,
            life->width | (life->pitch << 16),
            life->height | (life->alignedHeight << 16),
            &vc_image_ptr);
    assert(life->frontResource != 0);

    life->backResource = 
        vc_dispmanx_resource_create(
            type,
            life->width | (life->pitch << 16),
            life->height | (life->alignedHeight << 16),
            &vc_image_ptr);
    assert(life->backResource != 0);

    //---------------------------------------------------------------------

    vc_dispmanx_rect_set(&(life->bmpRect), 0, 0, life->width, life->height);

    result = vc_dispmanx_resource_write_data(life->frontResource,
                                             type,
                                             life->pitch,
                                             life->buffer,
                                             &(life->bmpRect));
    assert(result == 0);

    //---------------------------------------------------------------------

    long cores = sysconf(_SC_NPROCESSORS_ONLN);

    if (cores == -1)
    {
        cores = 1;
    }

    if (cores > LIFE_MAX_THREADS)
    {
        life->numberOfThreads = LIFE_MAX_THREADS;
    }
    else
    {
        life->numberOfThreads = cores;
    }

    pthread_barrier_init(&(life->startIterationBarrier),
                         NULL,
                         life->numberOfThreads + 1);

    pthread_barrier_init(&(life->finishedIterationBarrier),
                         NULL,
                         life->numberOfThreads + 1);

    //---------------------------------------------------------------------

    int32_t heightStep = life->height / life->numberOfThreads;
    int32_t heightStart = 0;

    int32_t thread;
    for (thread = 0 ; thread < life->numberOfThreads ; thread++)
    {
        life->heightRange[thread].startHeight = heightStart;
        life->heightRange[thread].endHeight = heightStart + heightStep;

        heightStart += heightStep;

        pthread_create(&(life->threads[thread]),
                       NULL,
                       workerLife,
                       life);
    }

    thread = life->numberOfThreads - 1;
    life->heightRange[thread].endHeight = life->height;

    //---------------------------------------------------------------------

    memcpy(life->field, life->fieldNext, life->fieldLength);
    pthread_barrier_wait(&(life->startIterationBarrier));
}
Exemplo n.º 2
0
void mempool_destroy(mempool p)
{
    struct  pool_segment *seg, *segnext;
    struct  node *niter;
    mempool piter, pprev;
    char *ptr;
    int64 i;

#ifdef MEMPOOL_DEBUG
    ShowDebug(read_message("Source.common.mempool_debug4"), p->name);
#endif

    // Unlink from global list.
    EnterSpinLock(&l_mempoolListLock);
    piter = l_mempoolList;
    pprev = l_mempoolList;
    while(1) {
        if(piter == NULL)
            break;


        if(piter == p) {
            // unlink from list,
            //
            if(pprev == l_mempoolList) {
                // this (p) is list begin. so set next as head.
                l_mempoolList = p->next;
            } else {
                // replace prevs next wuth our next.
                pprev->next = p->next;
            }
            break;
        }

        pprev = piter;
        piter = piter->next;
    }

    p->next = NULL;
    LeaveSpinLock(&l_mempoolListLock);


    // Get both locks.
    EnterSpinLock(&p->segmentLock);
    EnterSpinLock(&p->nodeLock);


    if(p->num_nodes_free != p->num_nodes_total)
        ShowWarning(read_message("Source.common.mempool_destroy"), p->name, (p->num_nodes_total - p->num_nodes_free));

    // Free All Segments (this will also free all nodes)
    // The segment pointer is the base pointer to the whole segment.
    seg = p->segments;
    while(1) {
        if(seg == NULL)
            break;

        segnext = seg->next;

        // ..
        if(p->ondealloc != NULL) {
            // walk over the segment, and call dealloc callback!
            ptr = (char *)seg;
            ptr += ALIGN_TO_16(sizeof(struct pool_segment));
            for(i = 0; i < seg->num_nodes_total; i++) {
                niter = (struct node *)ptr;
                ptr += sizeof(struct node);
                ptr += p->elem_size;
#ifdef MEMPOOLASSERT
                if(niter->magic != NODE_MAGIC) {
                    ShowError(read_message("Source.common.mempool_destroy2"), p->name, niter);
                    continue;
                }
#endif

                p->ondealloc(NODE_TO_DATA(niter));


            }
        }//endif: ondealloc callback?

        // simple ..
        aFree(seg);

        seg = segnext;
    }

    // Clear node ptr
    p->free_list = NULL;
    InterlockedExchange64(&p->num_nodes_free, 0);
    InterlockedExchange64(&p->num_nodes_total, 0);
    InterlockedExchange64(&p->num_segments, 0);
    InterlockedExchange64(&p->num_bytes_total, 0);

    LeaveSpinLock(&p->nodeLock);
    LeaveSpinLock(&p->segmentLock);

    // Free pool itself :D
    aFree(p->name);
    aFree(p);

}//end: mempool_destroy()
Exemplo n.º 3
0
mempool mempool_create(const char *name,
                       uint64 elem_size,
                       uint64 initial_count,
                       uint64 realloc_count,
                       memPoolOnNodeAllocationProc onNodeAlloc,
                       memPoolOnNodeDeallocationProc onNodeDealloc)
{
    //..
    uint64 realloc_thresh;
    mempool pool;
    pool = (mempool)aCalloc(1,  sizeof(struct mempool));

    if(pool == NULL) {
        ShowFatalError(read_message("Source.common.mempool_create"), sizeof(struct mempool));
        exit(EXIT_FAILURE);
    }

    // Check minimum initial count / realloc count requirements.
    if(initial_count < 50)
        initial_count = 50;
    if(realloc_count < 50)
        realloc_count = 50;

    // Set Reallocation threshold to 5% of realloc_count, at least 10.
    realloc_thresh = (realloc_count/100)*5; //
    if(realloc_thresh < 10)
        realloc_thresh = 10;

    // Initialize members..
    pool->name = aStrdup(name);
    pool->elem_size = ALIGN_TO_16(elem_size);
    pool->elem_realloc_step = realloc_count;
    pool->elem_realloc_thresh = realloc_thresh;
    pool->onalloc = onNodeAlloc;
    pool->ondealloc = onNodeDealloc;

    InitializeSpinLock(&pool->segmentLock);
    InitializeSpinLock(&pool->nodeLock);

    // Initial Statistic values:
    pool->num_nodes_total = 0;
    pool->num_nodes_free = 0;
    pool->num_segments = 0;
    pool->num_bytes_total = 0;
    pool->peak_nodes_used = 0;
    pool->num_realloc_events = 0;

    //
#ifdef MEMPOOL_DEBUG
    ShowDebug(read_message("Source.common.mempool_create"), pool->name,  pool->elem_size,  initial_count,  pool->elem_realloc_step);
#endif

    // Allocate first segment directly :)
    segment_allocate_add(pool, initial_count);


    // Add Pool to the global pool list
    EnterSpinLock(&l_mempoolListLock);
    pool->next = l_mempoolList;
    l_mempoolList = pool;
    LeaveSpinLock(&l_mempoolListLock);


    return pool;
}//end: mempool_create()
Exemplo n.º 4
0
static void segment_allocate_add(mempool p,  uint64 count)
{

    // Required Memory:
    //  sz( segment )
    //  count * sz( real_node_size )
    //
    //  where real node size is:
    //      ALIGN_TO_16( sz( node ) ) + p->elem_size
    //  so the nodes usable address is  nodebase + ALIGN_TO_16(sz(node))
    //
    size_t total_sz;
    struct pool_segment *seg = NULL;
    struct node *nodeList = NULL;
    struct node *node = NULL;
    char *ptr = NULL;
    uint64 i;

    total_sz = ALIGN_TO_16(sizeof(struct pool_segment))
               + ((size_t)count * (sizeof(struct node) + (size_t)p->elem_size)) ;

#ifdef MEMPOOL_DEBUG
    ShowDebug(read_message("Source.common.mempool_debug"), p->name, count, (float)total_sz/1024.f/1024.f);
#endif

    // allocate! (spin forever until weve got the memory.)
    i=0;
    while(1) {
        ptr = (char *)aMalloc(total_sz);
        if(ptr != NULL) break;

        i++; // increase failcount.
        if(!(i & 7)) {
            ShowWarning(read_message("Source.common.mempool_debug2"), (float)total_sz/1024.f/1024.f,  i);
#ifdef WIN32
            Sleep(1000);
#else
            sleep(1);
#endif
        } else {
            rathread_yield(); /// allow/force vuln. ctxswitch
        }
    }//endwhile: allocation spinloop.

    // Clear Memory.
    memset(ptr, 0x00, total_sz);

    // Initialize segment struct.
    seg = (struct pool_segment *)ptr;
    ptr += ALIGN_TO_16(sizeof(struct pool_segment));

    seg->pool = p;
    seg->num_nodes_total = count;
    seg->num_bytes = total_sz;


    // Initialze nodes!
    nodeList = NULL;
    for(i = 0; i < count; i++) {
        node = (struct node *)ptr;
        ptr += sizeof(struct node);
        ptr += p->elem_size;

        node->segment = seg;
#ifdef MEMPOOLASSERT
        node->used = false;
        node->magic = NODE_MAGIC;
#endif

        if(p->onalloc != NULL)  p->onalloc(NODE_TO_DATA(node));

        node->next = nodeList;
        nodeList = node;
    }



    // Link in Segment.
    EnterSpinLock(&p->segmentLock);
    seg->next = p->segments;
    p->segments = seg;
    LeaveSpinLock(&p->segmentLock);

    // Link in Nodes
    EnterSpinLock(&p->nodeLock);
    nodeList->next = p->free_list;
    p->free_list = nodeList;
    LeaveSpinLock(&p->nodeLock);


    // Increase Stats:
    InterlockedExchangeAdd64(&p->num_nodes_total,  count);
    InterlockedExchangeAdd64(&p->num_nodes_free,   count);
    InterlockedIncrement64(&p->num_segments);
    InterlockedExchangeAdd64(&p->num_bytes_total,   total_sz);

}//end: segment_allocate_add()
Exemplo n.º 5
0
bool initImage(
    IMAGE_T *image,
    VC_IMAGE_TYPE_T type,
    int32_t width,
    int32_t height,
    bool dither)
{
    switch (type)
    {
    case VC_IMAGE_4BPP:

        image->bitsPerPixel = 4;
        image->setPixelDirect = NULL;
        image->getPixelDirect = NULL;
        image->setPixelIndexed = setPixel4BPP;
        image->getPixelIndexed = getPixel4BPP;

        break;

    case VC_IMAGE_8BPP:

        image->bitsPerPixel = 8;
        image->setPixelDirect = NULL;
        image->getPixelDirect = NULL;
        image->setPixelIndexed = setPixel8BPP;
        image->getPixelIndexed = getPixel8BPP;

        break;

    case VC_IMAGE_RGB565:

        image->bitsPerPixel = 16;

        if (dither)
        {
            image->setPixelDirect = setPixelDitheredRGB565;
        }
        else
        {
            image->setPixelDirect = setPixelRGB565;
        }
        image->getPixelDirect = getPixelRGB565;
        image->setPixelIndexed = NULL;
        image->getPixelIndexed = NULL;

        break;

    case VC_IMAGE_RGB888:

        image->bitsPerPixel = 24;
        image->setPixelDirect = setPixelRGB888;
        image->getPixelDirect = getPixelRGB888;
        image->setPixelIndexed = NULL;
        image->getPixelIndexed = NULL;

        break;

    case VC_IMAGE_RGBA16:

        image->bitsPerPixel = 16;
        if (dither)
        {
            image->setPixelDirect = setPixelDitheredRGBA16;
        }
        else
        {
            image->setPixelDirect = setPixelRGBA16;
        }
        image->getPixelDirect = getPixelRGBA16;
        image->setPixelIndexed = NULL;
        image->getPixelIndexed = NULL;

        break;

    case VC_IMAGE_RGBA32:

        image->bitsPerPixel = 32;
        image->setPixelDirect = setPixelRGBA32;
        image->getPixelDirect = getPixelRGBA32;
        image->setPixelIndexed = NULL;
        image->getPixelIndexed = NULL;

        break;

    default:

        fprintf(stderr, "image: unknown type (%d)\n", type);
        return false;

        break;
    }

    image->type = type;
    image->width = width;
    image->height = height;
    image->pitch = (ALIGN_TO_16(width) * image->bitsPerPixel) / 8;
    image->alignedHeight = ALIGN_TO_16(height);
    image->size = image->pitch * image->alignedHeight;

    image->buffer = calloc(1, image->size);

    if (image->buffer == NULL)
    {
        fprintf(stderr, "image: memory exhausted\n");
        return false;
    }

    return true;
}
Exemplo n.º 6
0
int
main(
    int argc,
    char *argv[])
{
    int opt = 0;

    bool writeToStdout = false;
    char *pngName = DEFAULT_NAME;
    int32_t requestedWidth = 0;
    int32_t requestedHeight = 0;
    uint32_t displayNumber = DEFAULT_DISPLAY_NUMBER;
    int compression = Z_DEFAULT_COMPRESSION;
    int delay = DEFAULT_DELAY;

    VC_IMAGE_TYPE_T imageType = VC_IMAGE_RGBA32;
    int8_t dmxBytesPerPixel  = 4;

    int result = 0;

    program = basename(argv[0]);

    //-------------------------------------------------------------------

    char *sopts = "c:d:D:Hh:p:w:s";

    struct option lopts[] =
    {
        { "compression", required_argument, NULL, 'c' },
        { "delay", required_argument, NULL, 'd' },
        { "display", required_argument, NULL, 'D' },
        { "height", required_argument, NULL, 'h' },
        { "help", no_argument, NULL, 'H' },
        { "pngname", required_argument, NULL, 'p' },
        { "width", required_argument, NULL, 'w' },
        { "stdout", no_argument, NULL, 's' },
        { NULL, no_argument, NULL, 0 }
    };

    while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1)
    {
        switch (opt)
        {
        case 'c':

            compression = atoi(optarg);

            if ((compression < 0) || (compression > 9))
            {
                compression = Z_DEFAULT_COMPRESSION;
            }

            break;

        case 'd':

            delay = atoi(optarg);
            break;

        case 'D':

            displayNumber = atoi(optarg);
            break;

        case 'h':

            requestedHeight = atoi(optarg);
            break;

        case 'p':

            pngName = optarg;
            break;

        case 'w':

            requestedWidth = atoi(optarg);
            break;

        case 's':

            writeToStdout = true;
            break;

        case 'H':
        default:

            usage();

            if (opt == 'H')
            {
                exit(EXIT_SUCCESS);
            }
            else
            {
                exit(EXIT_FAILURE);
            }

            break;
        }
    }

    //-------------------------------------------------------------------

    bcm_host_init();

    //-------------------------------------------------------------------
    //
    // When the display is rotate (either 90 or 270 degrees) we need to
    // swap the width and height of the snapshot
    //

    char response[1024];
    int displayRotated = 0;

    if (vc_gencmd(response, sizeof(response), "get_config int") == 0)
    {
        vc_gencmd_number_property(response,
                                  "display_rotate",
                                  &displayRotated);
    }

    //-------------------------------------------------------------------

    if (delay)
    {
        sleep(delay);
    }

    //-------------------------------------------------------------------

    DISPMANX_DISPLAY_HANDLE_T displayHandle
        = vc_dispmanx_display_open(displayNumber);

    if (displayHandle == 0)
    {
        fprintf(stderr,
                "%s: unable to open display %d\n",
                program,
                displayNumber);

        exit(EXIT_FAILURE);
    }

    DISPMANX_MODEINFO_T modeInfo;
    result = vc_dispmanx_display_get_info(displayHandle, &modeInfo);

    if (result != 0)
    {
        fprintf(stderr, "%s: unable to get display information\n", program);
        exit(EXIT_FAILURE);
    }

    int32_t pngWidth = modeInfo.width;
    int32_t pngHeight = modeInfo.height;

    if (requestedWidth > 0)
    {
        pngWidth = requestedWidth;

        if (requestedHeight == 0)
        {
            double numerator = modeInfo.height * requestedWidth;
            double denominator = modeInfo.width;

            pngHeight = (int32_t)ceil(numerator / denominator);
        }
    }

    if (requestedHeight > 0)
    {
        pngHeight = requestedHeight;

        if (requestedWidth == 0)
        {
            double numerator = modeInfo.width * requestedHeight;
            double denominator = modeInfo.height;

            pngWidth = (int32_t)ceil(numerator / denominator);
        }
    }

    //-------------------------------------------------------------------
    // only need to check low bit of displayRotated (value of 1 or 3).
    // If the display is rotated either 90 or 270 degrees (value 1 or 3)
    // the width and height need to be transposed.

    int32_t dmxWidth = pngWidth;
    int32_t dmxHeight = pngHeight;

    if (displayRotated & 1)
    {
        dmxWidth = pngHeight;
        dmxHeight = pngWidth;
    }

    int32_t dmxPitch = dmxBytesPerPixel * ALIGN_TO_16(dmxWidth);

    void *dmxImagePtr = malloc(dmxPitch * dmxHeight);

    if (dmxImagePtr == NULL)
    {
        fprintf(stderr, "%s: unable to allocated image buffer\n", program);
        exit(EXIT_FAILURE);
    }

    //-------------------------------------------------------------------

    uint32_t vcImagePtr = 0;
    DISPMANX_RESOURCE_HANDLE_T resourceHandle;
    resourceHandle = vc_dispmanx_resource_create(imageType,
                                                 dmxWidth,
                                                 dmxHeight,
                                                 &vcImagePtr);

    result = vc_dispmanx_snapshot(displayHandle,
                                  resourceHandle,
                                  DISPMANX_NO_ROTATE);

    if (result != 0)
    {
        vc_dispmanx_resource_delete(resourceHandle);
        vc_dispmanx_display_close(displayHandle);

        fprintf(stderr, "%s: vc_dispmanx_snapshot() failed\n", program);
        exit(EXIT_FAILURE);
    }

    VC_RECT_T rect;
    result = vc_dispmanx_rect_set(&rect, 0, 0, dmxWidth, dmxHeight);

    if (result != 0)
    {
        vc_dispmanx_resource_delete(resourceHandle);
        vc_dispmanx_display_close(displayHandle);

        fprintf(stderr, "%s: vc_dispmanx_rect_set() failed\n", program);
        exit(EXIT_FAILURE);
    }

    result = vc_dispmanx_resource_read_data(resourceHandle,
                                            &rect,
                                            dmxImagePtr,
                                            dmxPitch);


    if (result != 0)
    {
        vc_dispmanx_resource_delete(resourceHandle);
        vc_dispmanx_display_close(displayHandle);

        fprintf(stderr,
                "%s: vc_dispmanx_resource_read_data() failed\n",
                program);

        exit(EXIT_FAILURE);
    }

    vc_dispmanx_resource_delete(resourceHandle);
    vc_dispmanx_display_close(displayHandle);

    //-------------------------------------------------------------------
    // Convert from RGBA (32 bit) to RGB (24 bit)

    int8_t pngBytesPerPixel = 3;
    int32_t pngPitch = pngBytesPerPixel * pngWidth;
    void *pngImagePtr = malloc(pngPitch * pngHeight);

    int32_t j = 0;
    for (j = 0 ; j < pngHeight ; j++)
    {
        int32_t dmxXoffset = 0;
        int32_t dmxYoffset = 0;

        switch (displayRotated & 3)
        {
        case 0: // 0 degrees

            if (displayRotated & 0x20000) // flip vertical
            {
                dmxYoffset = (dmxHeight - j - 1) * dmxPitch;
            }
            else
            {
                dmxYoffset = j * dmxPitch;
            }

            break;

        case 1: // 90 degrees


            if (displayRotated & 0x20000) // flip vertical
            {
                dmxXoffset = j * dmxBytesPerPixel;
            }
            else
            {
                dmxXoffset = (dmxWidth - j - 1) * dmxBytesPerPixel;
            }

            break;

        case 2: // 180 degrees

            if (displayRotated & 0x20000) // flip vertical
            {
                dmxYoffset = j * dmxPitch;
            }
            else
            {
                dmxYoffset = (dmxHeight - j - 1) * dmxPitch;
            }

            break;

        case 3: // 270 degrees

            if (displayRotated & 0x20000) // flip vertical
            {
                dmxXoffset = (dmxWidth - j - 1) * dmxBytesPerPixel;
            }
            else
            {
                dmxXoffset = j * dmxBytesPerPixel;
            }

            break;
        }

        int32_t i = 0;
        for (i = 0 ; i < pngWidth ; i++)
        {
            uint8_t *pngPixelPtr = pngImagePtr
                                 + (i * pngBytesPerPixel)
                                 + (j * pngPitch);

            switch (displayRotated & 3)
            {
            case 0: // 0 degrees

                if (displayRotated & 0x10000) // flip horizontal
                {
                    dmxXoffset = (dmxWidth - i - 1) * dmxBytesPerPixel;
                }
                else
                {
                    dmxXoffset = i * dmxBytesPerPixel;
                }

                break;

            case 1: // 90 degrees

                if (displayRotated & 0x10000) // flip horizontal
                {
                    dmxYoffset = (dmxHeight - i - 1) * dmxPitch;
                }
                else
                {
                    dmxYoffset = i * dmxPitch;
                }

                break;

            case 2: // 180 degrees

                if (displayRotated & 0x10000) // flip horizontal
                {
                    dmxXoffset = i * dmxBytesPerPixel;
                }
                else
                {
                    dmxXoffset = (dmxWidth - i - 1) * dmxBytesPerPixel;
                }

                break;

            case 3: // 270 degrees

                if (displayRotated & 0x10000) // flip horizontal
                {
                    dmxYoffset = i * dmxPitch;
                }
                else
                {
                    dmxYoffset = (dmxHeight - i - 1) * dmxPitch;
                }

                break;
            }

            uint8_t *dmxPixelPtr = dmxImagePtr + dmxXoffset + dmxYoffset;

            memcpy(pngPixelPtr, dmxPixelPtr, 3);
        }
    }

    free(dmxImagePtr);
    dmxImagePtr = NULL;

    //-------------------------------------------------------------------

    png_structp pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
                                                 NULL,
                                                 NULL,
                                                 NULL);

    if (pngPtr == NULL)
    {
        fprintf(stderr,
                "%s: unable to allocated PNG write structure\n",
                program);

        exit(EXIT_FAILURE);
    }

    png_infop infoPtr = png_create_info_struct(pngPtr);

    if (infoPtr == NULL)
    {
        fprintf(stderr,
                "%s: unable to allocated PNG info structure\n",
                program);

        exit(EXIT_FAILURE);
    }

    if (setjmp(png_jmpbuf(pngPtr)))
    {
        fprintf(stderr, "%s: unable to create PNG\n", program);
        exit(EXIT_FAILURE);
    }

    FILE *pngfp = NULL;

    if (writeToStdout)
    {
        pngfp = stdout;
    }
    else
    {
        pngfp = fopen(pngName, "wb");

        if (pngfp == NULL)
        {
            fprintf(stderr,
                    "%s: unable to create %s - %s\n",
                    program,
                    pngName,
                    strerror(errno));

            exit(EXIT_FAILURE);
        }
    }

    png_init_io(pngPtr, pngfp);

    png_set_IHDR(
        pngPtr,
        infoPtr,
        pngWidth,
        pngHeight,
        8,
        PNG_COLOR_TYPE_RGB,
        PNG_INTERLACE_NONE,
        PNG_COMPRESSION_TYPE_BASE,
        PNG_FILTER_TYPE_BASE);

    if (compression != Z_DEFAULT_COMPRESSION)
    {
        png_set_compression_level(pngPtr, compression);
    }

    png_write_info(pngPtr, infoPtr);

    int y = 0;
    for (y = 0; y < pngHeight; y++)
    {
        png_write_row(pngPtr, pngImagePtr + (pngPitch * y));
    }

    png_write_end(pngPtr, NULL);
    png_destroy_write_struct(&pngPtr, &infoPtr);

    if (pngfp != stdout)
    {
        fclose(pngfp);
    }

    //-------------------------------------------------------------------

    free(pngImagePtr);
    pngImagePtr = NULL;

    return 0;
}