Re-enable line drawing path in render drivers

This is still used for scaled line drawing in RenderDrawLinesWithRects()
This commit is contained in:
Sam Lantinga 2022-01-08 09:02:25 -08:00
parent dca281e810
commit 18e4d9fed1
7 changed files with 301 additions and 12 deletions

View File

@ -1207,8 +1207,30 @@ D3D_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *verti
break;
}
case SDL_RENDERCMD_DRAW_LINES: /* unused */
case SDL_RENDERCMD_DRAW_LINES: {
const size_t count = cmd->data.draw.count;
const size_t first = cmd->data.draw.first;
const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
/* DirectX 9 has the same line rasterization semantics as GDI,
so we need to close the endpoint of the line with a second draw call. */
const SDL_bool close_endpoint = ((count == 2) || (verts[0].x != verts[count-1].x) || (verts[0].y != verts[count-1].y));
SetDrawState(data, cmd);
if (vbo) {
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_LINESTRIP, (UINT) (first / sizeof (Vertex)), (UINT) (count - 1));
if (close_endpoint) {
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT) ((first / sizeof (Vertex)) + (count - 1)), 1);
}
} else {
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, (UINT) (count - 1), verts, sizeof (Vertex));
if (close_endpoint) {
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, &verts[count-1], sizeof (Vertex));
}
}
break;
}
case SDL_RENDERCMD_FILL_RECTS: /* unused */
break;
@ -1545,6 +1567,7 @@ D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
renderer->QueueSetViewport = D3D_QueueSetViewport;
renderer->QueueSetDrawColor = D3D_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
renderer->QueueDrawPoints = D3D_QueueDrawPoints;
renderer->QueueDrawLines = D3D_QueueDrawPoints; /* lines and points queue vertices the same way. */
renderer->QueueGeometry = D3D_QueueGeometry;
renderer->RunCommandQueue = D3D_RunCommandQueue;
renderer->RenderReadPixels = D3D_RenderReadPixels;

View File

@ -2122,8 +2122,18 @@ D3D11_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver
break;
}
case SDL_RENDERCMD_DRAW_LINES: /* unused */
case SDL_RENDERCMD_DRAW_LINES: {
const size_t count = cmd->data.draw.count;
const size_t first = cmd->data.draw.first;
const size_t start = first / sizeof (VertexPositionColor);
const VertexPositionColor *verts = (VertexPositionColor *) (((Uint8 *) vertices) + first);
D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[SHADER_SOLID], 0, NULL, NULL, NULL);
D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, start, count);
if (verts[0].pos.x != verts[count - 1].pos.x || verts[0].pos.y != verts[count - 1].pos.y) {
D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, start + (count-1), 1);
}
break;
}
case SDL_RENDERCMD_FILL_RECTS: /* unused */
break;
@ -2376,6 +2386,7 @@ D3D11_CreateRenderer(SDL_Window * window, Uint32 flags)
renderer->QueueSetViewport = D3D11_QueueSetViewport;
renderer->QueueSetDrawColor = D3D11_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
renderer->QueueDrawPoints = D3D11_QueueDrawPoints;
renderer->QueueDrawLines = D3D11_QueueDrawPoints; /* lines and points queue vertices the same way. */
renderer->QueueGeometry = D3D11_QueueGeometry;
renderer->RunCommandQueue = D3D11_RunCommandQueue;
renderer->RenderReadPixels = D3D11_RenderReadPixels;

View File

@ -1107,6 +1107,56 @@ METAL_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL
return 0;
}
static int
METAL_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
{
const SDL_Color color = {
cmd->data.draw.r,
cmd->data.draw.g,
cmd->data.draw.b,
cmd->data.draw.a
};
SDL_assert(count >= 2); /* should have been checked at the higher level. */
const size_t vertlen = (2 * sizeof (float) + sizeof (SDL_Color)) * count;
float *verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, DEVICE_ALIGN(8), &cmd->data.draw.first);
if (!verts) {
return -1;
}
cmd->data.draw.count = count;
for (int i = 0; i < count; i++, points++) {
*(verts++) = points->x;
*(verts++) = points->y;
*((SDL_Color *)verts++) = color;
}
/* If the line segment is completely horizontal or vertical,
make it one pixel longer, to satisfy the diamond-exit rule.
We should probably do this for diagonal lines too, but we'd have to
do some trigonometry to figure out the correct pixel and generally
when we have problems with pixel perfection, it's for straight lines
that are missing a pixel that frames something and not arbitrary
angles. Maybe !!! FIXME for later, though. */
points -= 2; /* update the last line. */
verts -= 2 + 1;
const float xstart = points[0].x;
const float ystart = points[0].y;
const float xend = points[1].x;
const float yend = points[1].y;
if (ystart == yend) { /* horizontal line */
verts[0] += (xend > xstart) ? 1.0f : -1.0f;
} else if (xstart == xend) { /* vertical line */
verts[1] += (yend > ystart) ? 1.0f : -1.0f;
}
return 0;
}
static int
METAL_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
const float *xy, int xy_stride, const SDL_Color *color, int color_stride, const float *uv, int uv_stride,
@ -1372,17 +1422,15 @@ METAL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver
break;
}
case SDL_RENDERCMD_DRAW_POINTS: {
case SDL_RENDERCMD_DRAW_POINTS:
case SDL_RENDERCMD_DRAW_LINES: {
const size_t count = cmd->data.draw.count;
const MTLPrimitiveType primtype = MTLPrimitiveTypePoint;
const MTLPrimitiveType primtype = (cmd->command == SDL_RENDERCMD_DRAW_POINTS) ? MTLPrimitiveTypePoint : MTLPrimitiveTypeLineStrip;
if (SetDrawState(renderer, cmd, SDL_METAL_FRAGMENT_SOLID, CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM, mtlbufvertex, &statecache)) {
[data.mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count];
}
break;
}
case SDL_RENDERCMD_DRAW_LINES: /* unused */
break;
case SDL_RENDERCMD_FILL_RECTS: /* unused */
break;
@ -1838,6 +1886,7 @@ METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
renderer->QueueSetViewport = METAL_QueueSetViewport;
renderer->QueueSetDrawColor = METAL_QueueSetDrawColor;
renderer->QueueDrawPoints = METAL_QueueDrawPoints;
renderer->QueueDrawLines = METAL_QueueDrawLines;
renderer->QueueGeometry = METAL_QueueGeometry;
renderer->RunCommandQueue = METAL_RunCommandQueue;
renderer->RenderReadPixels = METAL_RenderReadPixels;

View File

@ -941,6 +941,47 @@ GL_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FP
return 0;
}
static int
GL_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
{
int i;
GLfloat prevx, prevy;
const size_t vertlen = (sizeof (GLfloat) * 2) * count;
GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, vertlen, 0, &cmd->data.draw.first);
if (!verts) {
return -1;
}
cmd->data.draw.count = count;
/* 0.5f offset to hit the center of the pixel. */
prevx = 0.5f + points->x;
prevy = 0.5f + points->y;
*(verts++) = prevx;
*(verts++) = prevy;
/* bump the end of each line segment out a quarter of a pixel, to provoke
the diamond-exit rule. Without this, you won't just drop the last
pixel of the last line segment, but you might also drop pixels at the
edge of any given line segment along the way too. */
for (i = 1; i < count; i++) {
const GLfloat xstart = prevx;
const GLfloat ystart = prevy;
const GLfloat xend = points[i].x + 0.5f; /* 0.5f to hit pixel center. */
const GLfloat yend = points[i].y + 0.5f;
/* bump a little in the direction we are moving in. */
const GLfloat deltax = xend - xstart;
const GLfloat deltay = yend - ystart;
const GLfloat angle = SDL_atan2f(deltay, deltax);
prevx = xend + (SDL_cosf(angle) * 0.25f);
prevy = yend + (SDL_sinf(angle) * 0.25f);
*(verts++) = prevx;
*(verts++) = prevy;
}
return 0;
}
static int
GL_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
const float *xy, int xy_stride, const SDL_Color *color, int color_stride, const float *uv, int uv_stride,
@ -1070,6 +1111,7 @@ SetDrawState(GL_RenderData *data, const SDL_RenderCommand *cmd, const GL_Shader
}
vertex_array = cmd->command == SDL_RENDERCMD_DRAW_POINTS
|| cmd->command == SDL_RENDERCMD_DRAW_LINES
|| cmd->command == SDL_RENDERCMD_GEOMETRY;
color_array = cmd->command == SDL_RENDERCMD_GEOMETRY;
texture_array = cmd->data.draw.texture != NULL;
@ -1244,8 +1286,17 @@ GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
break;
}
case SDL_RENDERCMD_DRAW_LINES: /* unused */
case SDL_RENDERCMD_DRAW_LINES: {
const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
const size_t count = cmd->data.draw.count;
SDL_assert(count >= 2);
SetDrawState(data, cmd, SHADER_SOLID);
/* SetDrawState handles glEnableClientState. */
data->glVertexPointer(2, GL_FLOAT, sizeof(float) * 2, verts);
data->glDrawArrays(GL_LINE_STRIP, 0, (GLsizei) count);
break;
}
case SDL_RENDERCMD_FILL_RECTS: /* unused */
break;
@ -1643,6 +1694,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags)
renderer->QueueSetViewport = GL_QueueSetViewport;
renderer->QueueSetDrawColor = GL_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
renderer->QueueDrawPoints = GL_QueueDrawPoints;
renderer->QueueDrawLines = GL_QueueDrawLines;
renderer->QueueGeometry = GL_QueueGeometry;
renderer->RunCommandQueue = GL_RunCommandQueue;
renderer->RenderReadPixels = GL_RenderReadPixels;

View File

@ -560,6 +560,47 @@ GLES_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_
return 0;
}
static int
GLES_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
{
int i;
GLfloat prevx, prevy;
const size_t vertlen = (sizeof (GLfloat) * 2) * count;
GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, vertlen, 0, &cmd->data.draw.first);
if (!verts) {
return -1;
}
cmd->data.draw.count = count;
/* 0.5f offset to hit the center of the pixel. */
prevx = 0.5f + points->x;
prevy = 0.5f + points->y;
*(verts++) = prevx;
*(verts++) = prevy;
/* bump the end of each line segment out a quarter of a pixel, to provoke
the diamond-exit rule. Without this, you won't just drop the last
pixel of the last line segment, but you might also drop pixels at the
edge of any given line segment along the way too. */
for (i = 1; i < count; i++) {
const GLfloat xstart = prevx;
const GLfloat ystart = prevy;
const GLfloat xend = points[i].x + 0.5f; /* 0.5f to hit pixel center. */
const GLfloat yend = points[i].y + 0.5f;
/* bump a little in the direction we are moving in. */
const GLfloat deltax = xend - xstart;
const GLfloat deltay = yend - ystart;
const GLfloat angle = SDL_atan2f(deltay, deltax);
prevx = xend + (SDL_cosf(angle) * 0.25f);
prevy = yend + (SDL_sinf(angle) * 0.25f);
*(verts++) = prevx;
*(verts++) = prevy;
}
return 0;
}
static int
GLES_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
const float *xy, int xy_stride, const SDL_Color *color, int color_stride, const float *uv, int uv_stride,
@ -809,8 +850,15 @@ GLES_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vert
break;
}
case SDL_RENDERCMD_DRAW_LINES: /* unused */
break;
case SDL_RENDERCMD_DRAW_LINES: {
const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
const size_t count = cmd->data.draw.count;
SDL_assert(count >= 2);
SetDrawState(data, cmd);
data->glVertexPointer(2, GL_FLOAT, 0, verts);
data->glDrawArrays(GL_LINE_STRIP, 0, (GLsizei) count);
break;
}
case SDL_RENDERCMD_FILL_RECTS: /* unused */
break;
@ -1074,6 +1122,7 @@ GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
renderer->QueueSetViewport = GLES_QueueSetViewport;
renderer->QueueSetDrawColor = GLES_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
renderer->QueueDrawPoints = GLES_QueueDrawPoints;
renderer->QueueDrawLines = GLES_QueueDrawLines;
renderer->QueueGeometry = GLES_QueueGeometry;
renderer->RunCommandQueue = GLES_RunCommandQueue;
renderer->RenderReadPixels = GLES_RenderReadPixels;

View File

@ -692,6 +692,63 @@ GLES2_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL
return 0;
}
static int
GLES2_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
{
const SDL_bool colorswap = (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 || renderer->target->format == SDL_PIXELFORMAT_RGB888));
int i;
GLfloat prevx, prevy;
SDL_VertexSolid *verts = (SDL_VertexSolid *) SDL_AllocateRenderVertices(renderer, count * sizeof(*verts), 0, &cmd->data.draw.first);
SDL_Color color;
color.r = cmd->data.draw.r;
color.g = cmd->data.draw.g;
color.b = cmd->data.draw.b;
color.a = cmd->data.draw.a;
if (!verts) {
return -1;
}
if (colorswap) {
Uint8 r = color.r;
color.r = color.b;
color.b = r;
}
cmd->data.draw.count = count;
/* 0.5f offset to hit the center of the pixel. */
prevx = 0.5f + points->x;
prevy = 0.5f + points->y;
verts->position.x = prevx;
verts->position.y = prevy;
verts->color = color;
verts++;
/* bump the end of each line segment out a quarter of a pixel, to provoke
the diamond-exit rule. Without this, you won't just drop the last
pixel of the last line segment, but you might also drop pixels at the
edge of any given line segment along the way too. */
for (i = 1; i < count; i++) {
const GLfloat xstart = prevx;
const GLfloat ystart = prevy;
const GLfloat xend = points[i].x + 0.5f; /* 0.5f to hit pixel center. */
const GLfloat yend = points[i].y + 0.5f;
/* bump a little in the direction we are moving in. */
const GLfloat deltax = xend - xstart;
const GLfloat deltay = yend - ystart;
const GLfloat angle = SDL_atan2f(deltay, deltax);
prevx = xend + (SDL_cosf(angle) * 0.25f);
prevy = yend + (SDL_sinf(angle) * 0.25f);
verts->position.x = prevx;
verts->position.y = prevy;
verts->color = color;
verts++;
}
return 0;
}
static int
GLES2_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
const float *xy, int xy_stride, const SDL_Color *color, int color_stride, const float *uv, int uv_stride,
@ -1126,8 +1183,39 @@ GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver
case SDL_RENDERCMD_COPY_EX: /* unused */
break;
case SDL_RENDERCMD_DRAW_LINES: /* unused */
case SDL_RENDERCMD_DRAW_LINES: {
if (SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID) == 0) {
size_t count = cmd->data.draw.count;
if (count > 2) {
/* joined lines cannot be grouped */
data->glDrawArrays(GL_LINE_STRIP, 0, (GLsizei)count);
} else {
/* let's group non joined lines */
SDL_RenderCommand *finalcmd = cmd;
SDL_RenderCommand *nextcmd = cmd->next;
SDL_BlendMode thisblend = cmd->data.draw.blend;
while (nextcmd != NULL) {
const SDL_RenderCommandType nextcmdtype = nextcmd->command;
if (nextcmdtype != SDL_RENDERCMD_DRAW_LINES) {
break; /* can't go any further on this draw call, different render command up next. */
} else if (nextcmd->data.draw.count != 2) {
break; /* can't go any further on this draw call, those are joined lines */
} else if (nextcmd->data.draw.blend != thisblend) {
break; /* can't go any further on this draw call, different blendmode copy up next. */
} else {
finalcmd = nextcmd; /* we can combine copy operations here. Mark this one as the furthest okay command. */
count += cmd->data.draw.count;
}
nextcmd = nextcmd->next;
}
data->glDrawArrays(GL_LINES, 0, (GLsizei)count);
cmd = finalcmd; /* skip any copy commands we just combined in here. */
}
}
break;
}
case SDL_RENDERCMD_DRAW_POINTS:
case SDL_RENDERCMD_GEOMETRY: {
@ -2007,6 +2095,7 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
renderer->QueueSetViewport = GLES2_QueueSetViewport;
renderer->QueueSetDrawColor = GLES2_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
renderer->QueueDrawPoints = GLES2_QueueDrawPoints;
renderer->QueueDrawLines = GLES2_QueueDrawLines;
renderer->QueueGeometry = GLES2_QueueGeometry;
renderer->RunCommandQueue = GLES2_RunCommandQueue;
renderer->RenderReadPixels = GLES2_RenderReadPixels;

View File

@ -1120,8 +1120,23 @@ PSP_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *verti
break;
}
case SDL_RENDERCMD_DRAW_LINES: /* unused */
case SDL_RENDERCMD_DRAW_LINES: {
const size_t count = cmd->data.draw.count;
const VertV *verts = (VertV *) (gpumem + cmd->data.draw.first);
const Uint8 r = cmd->data.draw.r;
const Uint8 g = cmd->data.draw.g;
const Uint8 b = cmd->data.draw.b;
const Uint8 a = cmd->data.draw.a;
PSP_BlendState state = {
.color = GU_RGBA(r,g,b,a),
.texture = NULL,
.mode = cmd->data.draw.blend,
.shadeModel = GU_FLAT
};
PSP_SetBlendState(data, &state);
sceGuDrawArray(GU_LINE_STRIP, GU_VERTEX_32BITF|GU_TRANSFORM_2D, count, 0, verts);
break;
}
case SDL_RENDERCMD_FILL_RECTS: {
const size_t count = cmd->data.draw.count;
@ -1324,6 +1339,7 @@ PSP_CreateRenderer(SDL_Window * window, Uint32 flags)
renderer->QueueSetViewport = PSP_QueueSetViewport;
renderer->QueueSetDrawColor = PSP_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
renderer->QueueDrawPoints = PSP_QueueDrawPoints;
renderer->QueueDrawLines = PSP_QueueDrawPoints; /* lines and points queue vertices the same way. */
renderer->QueueGeometry = PSP_QueueGeometry;
renderer->QueueFillRects = PSP_QueueFillRects;
renderer->QueueCopy = PSP_QueueCopy;