Skip to content

Commit 5bed8ec

Browse files
committed
Implemented render batching for D3D9
1 parent a63e848 commit 5bed8ec

File tree

1 file changed

+106
-36
lines changed

1 file changed

+106
-36
lines changed

src/render/direct3d/SDL_render_d3d.c

Lines changed: 106 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,10 +1313,7 @@ static bool D3D_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
13131313
switch (cmd->command) {
13141314
case SDL_RENDERCMD_SETDRAWCOLOR:
13151315
{
1316-
/* currently this is sent with each vertex, but if we move to
1317-
shaders, we can put this in a uniform here and reduce vertex
1318-
buffer bandwidth */
1319-
break;
1316+
break; // this isn't currently used in this render backend.
13201317
}
13211318

13221319
case SDL_RENDERCMD_SETVIEWPORT:
@@ -1377,43 +1374,74 @@ static bool D3D_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
13771374
break;
13781375
}
13791376

1380-
case SDL_RENDERCMD_DRAW_POINTS:
1381-
{
1382-
const size_t count = cmd->data.draw.count;
1383-
const size_t first = cmd->data.draw.first;
1384-
SetDrawState(data, cmd);
1385-
if (vbo) {
1386-
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT)(first / sizeof(Vertex)), (UINT)count);
1387-
} else {
1388-
const Vertex *verts = (Vertex *)(((Uint8 *)vertices) + first);
1389-
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, (UINT)count, verts, sizeof(Vertex));
1390-
}
1391-
break;
1392-
}
1393-
13941377
case SDL_RENDERCMD_DRAW_LINES:
13951378
{
1396-
const size_t count = cmd->data.draw.count;
1379+
size_t count = cmd->data.draw.count;
13971380
const size_t first = cmd->data.draw.first;
1381+
const size_t start = first / sizeof(Vertex);
13981382
const Vertex *verts = (Vertex *)(((Uint8 *)vertices) + first);
13991383

1400-
/* DirectX 9 has the same line rasterization semantics as GDI,
1401-
so we need to close the endpoint of the line with a second draw call.
1402-
NOLINTNEXTLINE(clang-analyzer-core.NullDereference): FIXME: Can verts truly not be NULL ? */
1403-
const bool close_endpoint = ((count == 2) || (verts[0].x != verts[count - 1].x) || (verts[0].y != verts[count - 1].y));
1404-
14051384
SetDrawState(data, cmd);
14061385

1407-
if (vbo) {
1408-
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_LINESTRIP, (UINT)(first / sizeof(Vertex)), (UINT)(count - 1));
1409-
if (close_endpoint) {
1410-
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT)((first / sizeof(Vertex)) + (count - 1)), 1);
1386+
// Add the final point in the line
1387+
size_t line_start = 0;
1388+
size_t line_end = line_start + count - 1;
1389+
if (count == 2 || verts[line_start].x != verts[line_end].x || verts[line_start].y != verts[line_end].y) {
1390+
if (vbo) {
1391+
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT)(start + line_end), 1);
1392+
} else {
1393+
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, &verts[line_end], sizeof(Vertex));
1394+
}
1395+
}
1396+
1397+
if (count > 2) {
1398+
// joined lines cannot be grouped
1399+
if (vbo) {
1400+
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_LINESTRIP, (UINT)start, (UINT)(count - 1));
1401+
} else {
1402+
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, (UINT)(count - 1), verts, sizeof(Vertex));
14111403
}
14121404
} else {
1413-
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, (UINT)(count - 1), verts, sizeof(Vertex));
1414-
if (close_endpoint) {
1415-
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, &verts[count - 1], sizeof(Vertex));
1405+
// let's group non joined lines
1406+
SDL_RenderCommand *finalcmd = cmd;
1407+
SDL_RenderCommand *nextcmd;
1408+
SDL_BlendMode thisblend = cmd->data.draw.blend;
1409+
1410+
for (nextcmd = cmd->next; nextcmd; nextcmd = nextcmd->next) {
1411+
const SDL_RenderCommandType nextcmdtype = nextcmd->command;
1412+
if (nextcmdtype != SDL_RENDERCMD_DRAW_LINES) {
1413+
if (nextcmdtype == SDL_RENDERCMD_SETDRAWCOLOR) {
1414+
// The vertex data has the draw color built in, ignore this
1415+
continue;
1416+
}
1417+
break; // can't go any further on this draw call, different render command up next.
1418+
} else if (nextcmd->data.draw.count != 2) {
1419+
break; // can't go any further on this draw call, those are joined lines
1420+
} else if (nextcmd->data.draw.blend != thisblend) {
1421+
break; // can't go any further on this draw call, different blendmode copy up next.
1422+
} else {
1423+
finalcmd = nextcmd; // we can combine copy operations here. Mark this one as the furthest okay command.
1424+
1425+
// Add the final point in the line
1426+
line_start = count;
1427+
line_end = line_start + nextcmd->data.draw.count - 1;
1428+
if (verts[line_start].x != verts[line_end].x || verts[line_start].y != verts[line_end].y) {
1429+
if (vbo) {
1430+
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT)(start + line_end), 1);
1431+
} else {
1432+
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, &verts[line_end], sizeof(Vertex));
1433+
}
1434+
}
1435+
count += nextcmd->data.draw.count;
1436+
}
1437+
}
1438+
1439+
if (vbo) {
1440+
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_LINELIST, (UINT)start, (UINT)(count - 1));
1441+
} else {
1442+
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINELIST, (UINT)(count - 1), verts, sizeof(Vertex));
14161443
}
1444+
cmd = finalcmd; // skip any copy commands we just combined in here.
14171445
}
14181446
break;
14191447
}
@@ -1427,17 +1455,59 @@ static bool D3D_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
14271455
case SDL_RENDERCMD_COPY_EX: // unused
14281456
break;
14291457

1458+
case SDL_RENDERCMD_DRAW_POINTS:
14301459
case SDL_RENDERCMD_GEOMETRY:
14311460
{
1432-
const size_t count = cmd->data.draw.count;
1461+
/* as long as we have the same copy command in a row, with the
1462+
same texture, we can combine them all into a single draw call. */
1463+
SDL_Texture *thistexture = cmd->data.draw.texture;
1464+
SDL_BlendMode thisblend = cmd->data.draw.blend;
1465+
SDL_ScaleMode thisscalemode = cmd->data.draw.texture_scale_mode;
1466+
SDL_TextureAddressMode thisaddressmode_u = cmd->data.draw.texture_address_mode_u;
1467+
SDL_TextureAddressMode thisaddressmode_v = cmd->data.draw.texture_address_mode_v;
1468+
const SDL_RenderCommandType thiscmdtype = cmd->command;
1469+
SDL_RenderCommand *finalcmd = cmd;
1470+
SDL_RenderCommand *nextcmd;
1471+
size_t count = cmd->data.draw.count;
14331472
const size_t first = cmd->data.draw.first;
1473+
const size_t start = first / sizeof(Vertex);
1474+
const Vertex *verts = (Vertex *)(((Uint8 *)vertices) + first);
1475+
for (nextcmd = cmd->next; nextcmd; nextcmd = nextcmd->next) {
1476+
const SDL_RenderCommandType nextcmdtype = nextcmd->command;
1477+
if (nextcmdtype != thiscmdtype) {
1478+
if (nextcmdtype == SDL_RENDERCMD_SETDRAWCOLOR) {
1479+
// The vertex data has the draw color built in, ignore this
1480+
continue;
1481+
}
1482+
break; // can't go any further on this draw call, different render command up next.
1483+
} else if (nextcmd->data.draw.texture != thistexture ||
1484+
nextcmd->data.draw.texture_scale_mode != thisscalemode ||
1485+
nextcmd->data.draw.texture_address_mode_u != thisaddressmode_u ||
1486+
nextcmd->data.draw.texture_address_mode_v != thisaddressmode_v ||
1487+
nextcmd->data.draw.blend != thisblend) {
1488+
break; // can't go any further on this draw call, different texture/blendmode copy up next.
1489+
} else {
1490+
finalcmd = nextcmd; // we can combine copy operations here. Mark this one as the furthest okay command.
1491+
count += nextcmd->data.draw.count;
1492+
}
1493+
}
1494+
14341495
SetDrawState(data, cmd);
1435-
if (vbo) {
1436-
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLELIST, (UINT)(first / sizeof(Vertex)), (UINT)count / 3);
1496+
1497+
if (thiscmdtype == SDL_RENDERCMD_GEOMETRY) {
1498+
if (vbo) {
1499+
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLELIST, (UINT)start, (UINT)count / 3);
1500+
} else {
1501+
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLELIST, (UINT)count / 3, verts, sizeof(Vertex));
1502+
}
14371503
} else {
1438-
const Vertex *verts = (Vertex *)(((Uint8 *)vertices) + first);
1439-
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLELIST, (UINT)count / 3, verts, sizeof(Vertex));
1504+
if (vbo) {
1505+
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT)start, (UINT)count);
1506+
} else {
1507+
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, (UINT)count, verts, sizeof(Vertex));
1508+
}
14401509
}
1510+
cmd = finalcmd; // skip any copy commands we just combined in here.
14411511
break;
14421512
}
14431513

0 commit comments

Comments
 (0)