Made rasterization by scanlines thread-safe
renderPushTriangle can now be called concurrently
This commit is contained in:
parent
edde8442f5
commit
9d13f46fe6
1 changed files with 67 additions and 65 deletions
|
@ -51,12 +51,8 @@ struct RenderArea
|
||||||
int pixel_count;
|
int pixel_count;
|
||||||
int pixel_done;
|
int pixel_done;
|
||||||
RenderFragment* pixels;
|
RenderFragment* pixels;
|
||||||
ScanPoint* scanline_up;
|
|
||||||
ScanPoint* scanline_down;
|
|
||||||
int fragment_callbacks_count;
|
int fragment_callbacks_count;
|
||||||
FragmentCallback fragment_callbacks[64];
|
FragmentCallback fragment_callbacks[64];
|
||||||
int scanline_left;
|
|
||||||
int scanline_right;
|
|
||||||
Color background_color;
|
Color background_color;
|
||||||
volatile int dirty_left;
|
volatile int dirty_left;
|
||||||
volatile int dirty_right;
|
volatile int dirty_right;
|
||||||
|
@ -69,7 +65,16 @@ struct RenderArea
|
||||||
RenderCallbackUpdate callback_update;
|
RenderCallbackUpdate callback_update;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
|
ScanPoint* up;
|
||||||
|
ScanPoint* down;
|
||||||
|
int left;
|
||||||
|
int right;
|
||||||
|
} RenderScanlines;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
int startx;
|
int startx;
|
||||||
int endx;
|
int endx;
|
||||||
int starty;
|
int starty;
|
||||||
|
@ -109,10 +114,6 @@ RenderArea* renderCreateArea(Renderer* renderer)
|
||||||
result->pixel_count = 1;
|
result->pixel_count = 1;
|
||||||
result->pixels = malloc(sizeof(RenderFragment));
|
result->pixels = malloc(sizeof(RenderFragment));
|
||||||
result->fragment_callbacks_count = 0;
|
result->fragment_callbacks_count = 0;
|
||||||
result->scanline_up = malloc(sizeof(ScanPoint));
|
|
||||||
result->scanline_down = malloc(sizeof(ScanPoint));
|
|
||||||
result->scanline_left = 0;
|
|
||||||
result->scanline_right = 0;
|
|
||||||
result->background_color = COLOR_TRANSPARENT;
|
result->background_color = COLOR_TRANSPARENT;
|
||||||
result->dirty_left = 1;
|
result->dirty_left = 1;
|
||||||
result->dirty_right = -1;
|
result->dirty_right = -1;
|
||||||
|
@ -132,8 +133,6 @@ void renderDeleteArea(RenderArea* area)
|
||||||
colorProfileDelete(area->hdr_mapping);
|
colorProfileDelete(area->hdr_mapping);
|
||||||
mutexDestroy(area->lock);
|
mutexDestroy(area->lock);
|
||||||
free(area->pixels);
|
free(area->pixels);
|
||||||
free(area->scanline_up);
|
|
||||||
free(area->scanline_down);
|
|
||||||
free(area);
|
free(area);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,11 +155,6 @@ void renderSetParams(RenderArea* area, RenderParams params)
|
||||||
area->pixels = realloc(area->pixels, sizeof(RenderFragment) * width * height);
|
area->pixels = realloc(area->pixels, sizeof(RenderFragment) * width * height);
|
||||||
area->pixel_count = width * height;
|
area->pixel_count = width * height;
|
||||||
|
|
||||||
area->scanline_left = 0;
|
|
||||||
area->scanline_right = width - 1;
|
|
||||||
area->scanline_up = realloc(area->scanline_up, sizeof(ScanPoint) * width);
|
|
||||||
area->scanline_down = realloc(area->scanline_down, sizeof(ScanPoint) * width);
|
|
||||||
|
|
||||||
area->dirty_left = width;
|
area->dirty_left = width;
|
||||||
area->dirty_right = -1;
|
area->dirty_right = -1;
|
||||||
area->dirty_down = height;
|
area->dirty_down = height;
|
||||||
|
@ -182,18 +176,6 @@ void renderSetBackgroundColor(RenderArea* area, Color* col)
|
||||||
area->background_color = *col;
|
area->background_color = *col;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _clearScanLines(RenderArea* area)
|
|
||||||
{
|
|
||||||
int x;
|
|
||||||
for (x = area->scanline_left; x <= area->scanline_right; x++)
|
|
||||||
{
|
|
||||||
area->scanline_up[x].y = -1;
|
|
||||||
area->scanline_down[x].y = area->params.height * area->params.antialias;
|
|
||||||
}
|
|
||||||
area->scanline_left = area->params.width * area->params.antialias;
|
|
||||||
area->scanline_right = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void renderClear(RenderArea* area)
|
void renderClear(RenderArea* area)
|
||||||
{
|
{
|
||||||
RenderFragment* pixel;
|
RenderFragment* pixel;
|
||||||
|
@ -218,10 +200,6 @@ void renderClear(RenderArea* area)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
area->scanline_left = 0;
|
|
||||||
area->scanline_right = area->params.width * area->params.antialias - 1;
|
|
||||||
_clearScanLines(area);
|
|
||||||
|
|
||||||
area->callback_start(area->params.width, area->params.height, area->background_color);
|
area->callback_start(area->params.width, area->params.height, area->background_color);
|
||||||
|
|
||||||
area->dirty_left = area->params.width * area->params.antialias;
|
area->dirty_left = area->params.width * area->params.antialias;
|
||||||
|
@ -396,7 +374,7 @@ static void _scanInterpolate(CameraDefinition* camera, ScanPoint* v1, ScanPoint*
|
||||||
result->callback = v1->callback;
|
result->callback = v1->callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _pushScanPoint(RenderArea* area, ScanPoint* point)
|
static void _pushScanPoint(RenderArea* area, RenderScanlines* scanlines, ScanPoint* point)
|
||||||
{
|
{
|
||||||
point->x = (int)floor(point->pixel.x);
|
point->x = (int)floor(point->pixel.x);
|
||||||
point->y = (int)floor(point->pixel.y);
|
point->y = (int)floor(point->pixel.y);
|
||||||
|
@ -406,36 +384,36 @@ static void _pushScanPoint(RenderArea* area, ScanPoint* point)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (point->x > area->scanline_right)
|
if (point->x > scanlines->right)
|
||||||
{
|
{
|
||||||
area->scanline_right = point->x;
|
scanlines->right = point->x;
|
||||||
area->scanline_up[area->scanline_right] = *point;
|
scanlines->up[scanlines->right] = *point;
|
||||||
area->scanline_down[area->scanline_right] = *point;
|
scanlines->down[scanlines->right] = *point;
|
||||||
if (point->x < area->scanline_left)
|
if (point->x < scanlines->left)
|
||||||
{
|
{
|
||||||
area->scanline_left = point->x;
|
scanlines->left = point->x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (point->x < area->scanline_left)
|
else if (point->x < scanlines->left)
|
||||||
{
|
{
|
||||||
area->scanline_left = point->x;
|
scanlines->left = point->x;
|
||||||
area->scanline_up[area->scanline_left] = *point;
|
scanlines->up[scanlines->left] = *point;
|
||||||
area->scanline_down[area->scanline_left] = *point;
|
scanlines->down[scanlines->left] = *point;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (point->y > area->scanline_up[point->x].y)
|
if (point->y > scanlines->up[point->x].y)
|
||||||
{
|
{
|
||||||
area->scanline_up[point->x] = *point;
|
scanlines->up[point->x] = *point;
|
||||||
}
|
}
|
||||||
if (point->y < area->scanline_down[point->x].y)
|
if (point->y < scanlines->down[point->x].y)
|
||||||
{
|
{
|
||||||
area->scanline_down[point->x] = *point;
|
scanlines->down[point->x] = *point;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _pushScanLineEdge(RenderArea* area, ScanPoint* point1, ScanPoint* point2)
|
static void _pushScanLineEdge(RenderArea* area, RenderScanlines* scanlines, ScanPoint* point1, ScanPoint* point2)
|
||||||
{
|
{
|
||||||
double dx, fx;
|
double dx, fx;
|
||||||
ScanPoint diff, point;
|
ScanPoint diff, point;
|
||||||
|
@ -445,7 +423,7 @@ static void _pushScanLineEdge(RenderArea* area, ScanPoint* point1, ScanPoint* po
|
||||||
|
|
||||||
if (endx < startx)
|
if (endx < startx)
|
||||||
{
|
{
|
||||||
_pushScanLineEdge(area, point2, point1);
|
_pushScanLineEdge(area, scanlines, point2, point1);
|
||||||
}
|
}
|
||||||
else if (endx < 0 || startx >= area->params.width * area->params.antialias)
|
else if (endx < 0 || startx >= area->params.width * area->params.antialias)
|
||||||
{
|
{
|
||||||
|
@ -453,8 +431,8 @@ static void _pushScanLineEdge(RenderArea* area, ScanPoint* point1, ScanPoint* po
|
||||||
}
|
}
|
||||||
else if (startx == endx)
|
else if (startx == endx)
|
||||||
{
|
{
|
||||||
_pushScanPoint(area, point1);
|
_pushScanPoint(area, scanlines, point1);
|
||||||
_pushScanPoint(area, point2);
|
_pushScanPoint(area, scanlines, point2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -485,24 +463,24 @@ static void _pushScanLineEdge(RenderArea* area, ScanPoint* point1, ScanPoint* po
|
||||||
|
|
||||||
/*point.pixel.x = (double)curx;*/
|
/*point.pixel.x = (double)curx;*/
|
||||||
|
|
||||||
_pushScanPoint(area, &point);
|
_pushScanPoint(area, scanlines, &point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _renderScanLines(RenderArea* area)
|
static void _renderScanLines(RenderArea* area, RenderScanlines* scanlines)
|
||||||
{
|
{
|
||||||
int x, starty, endy, cury;
|
int x, starty, endy, cury;
|
||||||
ScanPoint diff;
|
ScanPoint diff;
|
||||||
double dy, fy;
|
double dy, fy;
|
||||||
ScanPoint up, down, current;
|
ScanPoint up, down, current;
|
||||||
|
|
||||||
if (area->scanline_right > 0)
|
if (scanlines->right > 0)
|
||||||
{
|
{
|
||||||
for (x = area->scanline_left; x <= area->scanline_right; x++)
|
for (x = scanlines->left; x <= scanlines->right; x++)
|
||||||
{
|
{
|
||||||
up = area->scanline_up[x];
|
up = scanlines->up[x];
|
||||||
down = area->scanline_down[x];
|
down = scanlines->down[x];
|
||||||
|
|
||||||
starty = down.y;
|
starty = down.y;
|
||||||
endy = up.y;
|
endy = up.y;
|
||||||
|
@ -560,27 +538,51 @@ void renderPushTriangle(RenderArea* area, Vector3 pixel1, Vector3 pixel2, Vector
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Prepare fragment callback */
|
||||||
|
mutexAcquire(area->lock);
|
||||||
|
point1.callback = _pushCallback(area, fragment_callback);
|
||||||
|
mutexRelease(area->lock);
|
||||||
|
|
||||||
|
/* Prepare vertices */
|
||||||
point1.pixel = pixel1;
|
point1.pixel = pixel1;
|
||||||
point1.location = location1;
|
point1.location = location1;
|
||||||
point1.callback = _pushCallback(area, fragment_callback);
|
|
||||||
|
|
||||||
point2.pixel = pixel2;
|
point2.pixel = pixel2;
|
||||||
point2.location = location2;
|
point2.location = location2;
|
||||||
point2.callback = _pushCallback(area, fragment_callback);
|
point2.callback = point1.callback;
|
||||||
|
|
||||||
point3.pixel = pixel3;
|
point3.pixel = pixel3;
|
||||||
point3.location = location3;
|
point3.location = location3;
|
||||||
point3.callback = _pushCallback(area, fragment_callback);
|
point3.callback = point1.callback;
|
||||||
|
|
||||||
_clearScanLines(area);
|
/* Prepare scanlines */
|
||||||
|
RenderScanlines scanlines;
|
||||||
|
int x;
|
||||||
|
int width = area->params.width * area->params.antialias;
|
||||||
|
scanlines.left = width;
|
||||||
|
scanlines.right = -1;
|
||||||
|
scanlines.up = malloc(sizeof(ScanPoint) * width);
|
||||||
|
scanlines.down = malloc(sizeof(ScanPoint) * width);
|
||||||
|
for (x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
/* TODO Do not initialize whole width each time, init only when needed on point push */
|
||||||
|
scanlines.up[x].y = -1;
|
||||||
|
scanlines.down[x].y = area->params.height * area->params.antialias;
|
||||||
|
}
|
||||||
|
|
||||||
_pushScanLineEdge(area, &point1, &point2);
|
/* Render edges in scanlines */
|
||||||
_pushScanLineEdge(area, &point2, &point3);
|
_pushScanLineEdge(area, &scanlines, &point1, &point2);
|
||||||
_pushScanLineEdge(area, &point3, &point1);
|
_pushScanLineEdge(area, &scanlines, &point2, &point3);
|
||||||
|
_pushScanLineEdge(area, &scanlines, &point3, &point1);
|
||||||
|
|
||||||
|
/* Commit scanlines to area */
|
||||||
mutexAcquire(area->lock);
|
mutexAcquire(area->lock);
|
||||||
_renderScanLines(area);
|
_renderScanLines(area, &scanlines);
|
||||||
mutexRelease(area->lock);
|
mutexRelease(area->lock);
|
||||||
|
|
||||||
|
/* Free scalines */
|
||||||
|
free(scanlines.up);
|
||||||
|
free(scanlines.down);
|
||||||
}
|
}
|
||||||
|
|
||||||
Color renderGetPixel(RenderArea* area, int x, int y)
|
Color renderGetPixel(RenderArea* area, int x, int y)
|
||||||
|
|
Loading…
Reference in a new issue