Made rasterization by scanlines thread-safe

renderPushTriangle can now be called concurrently
This commit is contained in:
Michaël Lemaire 2013-07-07 00:32:01 +02:00
parent edde8442f5
commit 9d13f46fe6

View file

@ -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)