<commit_before>//=======================================================================
// Copyright <NAME> 2015.
// Distributed under the MIT License.
// (See accompanying file license.txt or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*
 * renderer.c
 *
 *  Created on: 10 May 2015
 *      Author: ntuckett
 */
#include "renderer.h"
#include <string.h>
#include <stdio.h>
#include "assertbrk.h"
#include "lcd.h"
#include "flash.h"
#include "systick.h"
#include "mathutil.h"
#include "fontdata.h"
#include "image.h"
#include "profiler.h"

#define DRAWLIST_BUFFER_SIZE	4608
#define DLE_FLAG_ACTIVE_MASK	0x01
#define DLE_FLAG_DRAWN_MASK		0x02
#define DLE_TYPE_MASK			0xf0

#define DLE_TYPE_VLINE	0x10
#define DLE_TYPE_HLINE	0x20
#define DLE_TYPE_RECT	0x30
#define DLE_TYPE_TXTCH	0x40
#define DLE_TYPE_IMAGE	0x50

typedef struct _DrawListEntry {
	struct _DrawListEntry*	next;
	uint8_t					flags;
	uint8_t					size;
	uint16_t				y;
} DrawListEntry;

typedef struct _LineDLE {
	DrawListEntry	dle;
	uint16_t		x;
	uint16_t		length;
	uint16_t		colour;
} LineDLE;

typedef struct _RectDLE {
	DrawListEntry	dle;
	uint16_t		x;
	uint16_t		width;
	uint16_t		height;
	uint16_t		colour;
} RectDLE;

typedef struct _GlyphDLE {
	DrawListEntry	dle;
	uint16_t		x;
	uint16_t		colour;
	const Glyph*	glyph;
	const uint8_t*	data;
} GlyphDLE;

typedef struct _ImageDLE {
	DrawListEntry	dle;
	uint16_t		x;
	const Image*	image;
	const uint16_t*	palette;
	const uint8_t*	pixels;
} ImageDLE;

uint8_t		drawListBuffer[DRAWLIST_BUFFER_SIZE];
DrawListEntry* 	activeDLEs = NULL;
DrawListEntry** activeDLETail = &activeDLEs;
DrawListEntry* 	pendingDLEs = NULL;
DrawListEntry** pendingDLETail = &pendingDLEs;

size_t		drawListEnd = 0;
uint16_t	drawListMinX = SCREEN_WIDTH;
uint16_t	drawListMinY = SCREEN_HEIGHT;
uint16_t	drawListMaxX = 0;
uint16_t	drawListMaxY = 0;
uint16_t 	pixelBuffer[SCREEN_WIDTH];
uint8_t		rowMinX[SCREEN_HEIGHT];
uint8_t		rowMaxX[SCREEN_HEIGHT];

static DrawListEntry* allocDrawListEntry(size_t bytes)
{
	if (drawListEnd + bytes < DRAWLIST_BUFFER_SIZE) {
		DrawListEntry* dle = (DrawListEntry*) (drawListBuffer + drawListEnd);
		dle->size = bytes;
		dle->next = NULL;
		drawListEnd += bytes;
		return dle;
	}
	else {
		return NULL;
	}
}

void insertPendingDrawListEntry(DrawListEntry* dle)
{
	if (pendingDLEs == NULL) {
		*pendingDLETail = dle;
		pendingDLETail = &dle->next;
	}
	else {
		DrawListEntry* candidateDLE = pendingDLEs;
		DrawListEntry** candidateDLELink = &pendingDLEs;

		while (candidateDLE && dle->y >= candidateDLE->y) {
			candidateDLELink = &candidateDLE->next;
			candidateDLE = candidateDLE->next;
		}

		*candidateDLELink = dle;
		dle->next = candidateDLE;

		if (!candidateDLE) {
			pendingDLETail = &dle->next;
		}
	}
}

static void updateDrawListBounds(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
	if (x0 > x1) {
		SWAPNUM(x0, x1);
	}

	if (y0 > y1) {
		SWAPNUM(y0, y1);
	}

	y0 = MAX(y0, 0);
	y1 = MIN(y1, SCREEN_HEIGHT);
	x0 = MAX(x0, 0);
	x1 = MIN(x1, SCREEN_WIDTH);

	if (x0 < drawListMinX) {
		drawListMinX = x0;
	}

	if (x1 > drawListMaxX) {
		drawListMaxX = x1;
	}

	if (y0 < drawListMinY) {
		drawListMinY = y0;
	}

	if (y1 > drawListMaxY) {
		drawListMaxY = y1;
	}

	for (int y = y0; y < y1; y++) {
		if (x0 < rowMinX[y]) {
			rowMinX[y] = x0;
		}

		if (x1 > rowMaxX[y]) {
			rowMaxX[y] = x1;
		}
	}
}

static void renderScanLine(uint16_t y)
{
	//PROFILE_ENTER(scanline);

	size_t undrawnCount = 0;

	DrawListEntry** lastDle = &pendingDLEs;
	DrawListEntry* dle = pendingDLEs;

	//PROFILE_ENTER(activationCheck);
	while(dle && y == dle->y) {
		DrawListEntry* nextDle = dle->next;

		if (y == dle->y) {
			*lastDle = nextDle;
			dle->next = NULL;
			*activeDLETail = dle;
			activeDLETail = &dle->next;
		}

		if (dle->next == nextDle) {
			lastDle = &dle->next;
		}
		dle = nextDle;
	}
	//PROFILE_EXIT(activationCheck);

	lastDle = &activeDLEs;
	dle = activeDLEs;

	uint16_t minX = drawListMinX;

	int fillWidth = rowMinX[y] - drawListMinX;
	uint16_t* fillPtr = pixelBuffer;

	if (((uint32_t)fillPtr) & 3) {
		*fillPtr++ = 0;
		fillWidth--;
	}

	if (fillWidth >= 2) {
		uint32_t  fillDuo = 0;
		uint32_t* fillPtrDuo = (uint32_t*)fillPtr;
		while(fillWidth > 3) {<commit_msg>Fix alignment and overflow issues with scanline pre and post fill<commit_after>//=======================================================================
// Copyright <NAME> 2015.
// Distributed under the MIT License.
// (See accompanying file license.txt or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*
 * renderer.c
 *
 *  Created on: 10 May 2015
 *      Author: ntuckett
 */
#include "renderer.h"
#include <string.h>
#include <stdio.h>
#include "assertbrk.h"
#include "lcd.h"
#include "flash.h"
#include "systick.h"
#include "mathutil.h"
#include "fontdata.h"
#include "image.h"
#include "profiler.h"

#define DRAWLIST_BUFFER_SIZE	4608
#define DLE_FLAG_ACTIVE_MASK	0x01
#define DLE_FLAG_DRAWN_MASK		0x02
#define DLE_TYPE_MASK			0xf0

#define DLE_TYPE_VLINE	0x10
#define DLE_TYPE_HLINE	0x20
#define DLE_TYPE_RECT	0x30
#define DLE_TYPE_TXTCH	0x40
#define DLE_TYPE_IMAGE	0x50

typedef struct _DrawListEntry {
	struct _DrawListEntry*	next;
	uint8_t					flags;
	uint8_t					size;
	uint16_t				y;
} DrawListEntry;

typedef struct _LineDLE {
	DrawListEntry	dle;
	uint16_t		x;
	uint16_t		length;
	uint16_t		colour;
} LineDLE;

typedef struct _RectDLE {
	DrawListEntry	dle;
	uint16_t		x;
	uint16_t		width;
	uint16_t		height;
	uint16_t		colour;
} RectDLE;

typedef struct _GlyphDLE {
	DrawListEntry	dle;
	uint16_t		x;
	uint16_t		colour;
	const Glyph*	glyph;
	const uint8_t*	data;
} GlyphDLE;

typedef struct _ImageDLE {
	DrawListEntry	dle;
	uint16_t		x;
	const Image*	image;
	const uint16_t*	palette;
	const uint8_t*	pixels;
} ImageDLE;

uint8_t		drawListBuffer[DRAWLIST_BUFFER_SIZE];
DrawListEntry* 	activeDLEs = NULL;
DrawListEntry** activeDLETail = &activeDLEs;
DrawListEntry* 	pendingDLEs = NULL;
DrawListEntry** pendingDLETail = &pendingDLEs;

size_t		drawListEnd = 0;
uint16_t	drawListMinX = SCREEN_WIDTH;
uint16_t	drawListMinY = SCREEN_HEIGHT;
uint16_t	drawListMaxX = 0;
uint16_t	drawListMaxY = 0;
uint16_t 	pixelBuffer[SCREEN_WIDTH];
uint8_t		rowMinX[SCREEN_HEIGHT];
uint8_t		rowMaxX[SCREEN_HEIGHT];

static DrawListEntry* allocDrawListEntry(size_t bytes)
{
	if (drawListEnd + bytes < DRAWLIST_BUFFER_SIZE) {
		DrawListEntry* dle = (DrawListEntry*) (drawListBuffer + drawListEnd);
		dle->size = bytes;
		dle->next = NULL;
		drawListEnd += bytes;
		return dle;
	}
	else {
		return NULL;
	}
}

void insertPendingDrawListEntry(DrawListEntry* dle)
{
	if (pendingDLEs == NULL) {
		*pendingDLETail = dle;
		pendingDLETail = &dle->next;
	}
	else {
		DrawListEntry* candidateDLE = pendingDLEs;
		DrawListEntry** candidateDLELink = &pendingDLEs;

		while (candidateDLE && dle->y >= candidateDLE->y) {
			candidateDLELink = &candidateDLE->next;
			candidateDLE = candidateDLE->next;
		}

		*candidateDLELink = dle;
		dle->next = candidateDLE;

		if (!candidateDLE) {
			pendingDLETail = &dle->next;
		}
	}
}

static void updateDrawListBounds(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
	if (x0 > x1) {
		SWAPNUM(x0, x1);
	}

	if (y0 > y1) {
		SWAPNUM(y0, y1);
	}

	y0 = MAX(y0, 0);
	y1 = MIN(y1, SCREEN_HEIGHT);
	x0 = MAX(x0, 0);
	x1 = MIN(x1, SCREEN_WIDTH);

	if (x0 < drawListMinX) {
		drawListMinX = x0;
	}

	if (x1 > drawListMaxX) {
		drawListMaxX = x1;
	}

	if (y0 < drawListMinY) {
		drawListMinY = y0;
	}

	if (y1 > drawListMaxY) {
		drawListMaxY = y1;
	}

	for (int y = y0; y < y1; y++) {
		if (x0 < rowMinX[y]) {
			rowMinX[y] = x0;
		}

		if (x1 > rowMaxX[y]) {
			rowMaxX[y] = x1;
		}
	}
}

static void renderScanLine(uint16_t y)
{
	//PROFILE_ENTER(scanline);

	size_t undrawnCount = 0;

	DrawListEntry** lastDle = &pendingDLEs;
	DrawListEntry* dle = pendingDLEs;

	//PROFILE_ENTER(activationCheck);
	while(dle && y == dle->y) {
		DrawListEntry* nextDle = dle->next;

		if (y == dle->y) {
			*lastDle = nextDle;
			dle->next = NULL;
			*activeDLETail = dle;
			activeDLETail = &dle->next;
		}

		if (dle->next == nextDle) {
			lastDle = &dle->next;
		}
		dle = nextDle;
	}
	//PROFILE_EXIT(activationCheck);

	lastDle = &activeDLEs;
	dle = activeDLEs;

	uint16_t minX = drawListMinX;

	int fillWidth = rowMinX[y] - drawListMinX;
	uint16_t* fillPtr = pixelBuffer;

	if (fillWidth >= 2) {
		uint32_t  fillDuo = 0;
		uint32_t* fillPtrDuo = (uint32_t*)fillPtr;
		while(fillWidth > 3) {
{'fraction_non_alphanumeric': 0.1505665226024997, 'fraction_numerical': 0.033407312229879686, 'mean_word_length': 4.208029197080292, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6769540', 'n_tokens_mistral': 4001, 'n_tokens_neox': 3650, 'n_words': 760}