Implemented render batching for D3D9
This commit is contained in:
@@ -1313,10 +1313,7 @@ static bool D3D_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
|
|||||||
switch (cmd->command) {
|
switch (cmd->command) {
|
||||||
case SDL_RENDERCMD_SETDRAWCOLOR:
|
case SDL_RENDERCMD_SETDRAWCOLOR:
|
||||||
{
|
{
|
||||||
/* currently this is sent with each vertex, but if we move to
|
break; // this isn't currently used in this render backend.
|
||||||
shaders, we can put this in a uniform here and reduce vertex
|
|
||||||
buffer bandwidth */
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case SDL_RENDERCMD_SETVIEWPORT:
|
case SDL_RENDERCMD_SETVIEWPORT:
|
||||||
@@ -1377,43 +1374,74 @@ static bool D3D_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SDL_RENDERCMD_DRAW_POINTS:
|
|
||||||
{
|
|
||||||
const size_t count = cmd->data.draw.count;
|
|
||||||
const size_t first = cmd->data.draw.first;
|
|
||||||
SetDrawState(data, cmd);
|
|
||||||
if (vbo) {
|
|
||||||
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT)(first / sizeof(Vertex)), (UINT)count);
|
|
||||||
} else {
|
|
||||||
const Vertex *verts = (Vertex *)(((Uint8 *)vertices) + first);
|
|
||||||
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, (UINT)count, verts, sizeof(Vertex));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_RENDERCMD_DRAW_LINES:
|
case SDL_RENDERCMD_DRAW_LINES:
|
||||||
{
|
{
|
||||||
const size_t count = cmd->data.draw.count;
|
size_t count = cmd->data.draw.count;
|
||||||
const size_t first = cmd->data.draw.first;
|
const size_t first = cmd->data.draw.first;
|
||||||
|
const size_t start = first / sizeof(Vertex);
|
||||||
const Vertex *verts = (Vertex *)(((Uint8 *)vertices) + 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.
|
|
||||||
NOLINTNEXTLINE(clang-analyzer-core.NullDereference): FIXME: Can verts truly not be NULL ? */
|
|
||||||
const bool close_endpoint = ((count == 2) || (verts[0].x != verts[count - 1].x) || (verts[0].y != verts[count - 1].y));
|
|
||||||
|
|
||||||
SetDrawState(data, cmd);
|
SetDrawState(data, cmd);
|
||||||
|
|
||||||
if (vbo) {
|
// Add the final point in the line
|
||||||
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_LINESTRIP, (UINT)(first / sizeof(Vertex)), (UINT)(count - 1));
|
size_t line_start = 0;
|
||||||
if (close_endpoint) {
|
size_t line_end = line_start + count - 1;
|
||||||
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT)((first / sizeof(Vertex)) + (count - 1)), 1);
|
if (count == 2 || verts[line_start].x != verts[line_end].x || verts[line_start].y != verts[line_end].y) {
|
||||||
|
if (vbo) {
|
||||||
|
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT)(start + line_end), 1);
|
||||||
|
} else {
|
||||||
|
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, &verts[line_end], sizeof(Vertex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 2) {
|
||||||
|
// joined lines cannot be grouped
|
||||||
|
if (vbo) {
|
||||||
|
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_LINESTRIP, (UINT)start, (UINT)(count - 1));
|
||||||
|
} else {
|
||||||
|
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, (UINT)(count - 1), verts, sizeof(Vertex));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, (UINT)(count - 1), verts, sizeof(Vertex));
|
// let's group non joined lines
|
||||||
if (close_endpoint) {
|
SDL_RenderCommand *finalcmd = cmd;
|
||||||
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, &verts[count - 1], sizeof(Vertex));
|
SDL_RenderCommand *nextcmd;
|
||||||
|
SDL_BlendMode thisblend = cmd->data.draw.blend;
|
||||||
|
|
||||||
|
for (nextcmd = cmd->next; nextcmd; nextcmd = nextcmd->next) {
|
||||||
|
const SDL_RenderCommandType nextcmdtype = nextcmd->command;
|
||||||
|
if (nextcmdtype != SDL_RENDERCMD_DRAW_LINES) {
|
||||||
|
if (nextcmdtype == SDL_RENDERCMD_SETDRAWCOLOR) {
|
||||||
|
// The vertex data has the draw color built in, ignore this
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
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.
|
||||||
|
|
||||||
|
// Add the final point in the line
|
||||||
|
line_start = count;
|
||||||
|
line_end = line_start + nextcmd->data.draw.count - 1;
|
||||||
|
if (verts[line_start].x != verts[line_end].x || verts[line_start].y != verts[line_end].y) {
|
||||||
|
if (vbo) {
|
||||||
|
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT)(start + line_end), 1);
|
||||||
|
} else {
|
||||||
|
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, &verts[line_end], sizeof(Vertex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count += nextcmd->data.draw.count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vbo) {
|
||||||
|
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_LINELIST, (UINT)start, (UINT)(count - 1));
|
||||||
|
} else {
|
||||||
|
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINELIST, (UINT)(count - 1), verts, sizeof(Vertex));
|
||||||
|
}
|
||||||
|
cmd = finalcmd; // skip any copy commands we just combined in here.
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1427,17 +1455,59 @@ static bool D3D_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
|
|||||||
case SDL_RENDERCMD_COPY_EX: // unused
|
case SDL_RENDERCMD_COPY_EX: // unused
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SDL_RENDERCMD_DRAW_POINTS:
|
||||||
case SDL_RENDERCMD_GEOMETRY:
|
case SDL_RENDERCMD_GEOMETRY:
|
||||||
{
|
{
|
||||||
const size_t count = cmd->data.draw.count;
|
/* as long as we have the same copy command in a row, with the
|
||||||
|
same texture, we can combine them all into a single draw call. */
|
||||||
|
SDL_Texture *thistexture = cmd->data.draw.texture;
|
||||||
|
SDL_BlendMode thisblend = cmd->data.draw.blend;
|
||||||
|
SDL_ScaleMode thisscalemode = cmd->data.draw.texture_scale_mode;
|
||||||
|
SDL_TextureAddressMode thisaddressmode_u = cmd->data.draw.texture_address_mode_u;
|
||||||
|
SDL_TextureAddressMode thisaddressmode_v = cmd->data.draw.texture_address_mode_v;
|
||||||
|
const SDL_RenderCommandType thiscmdtype = cmd->command;
|
||||||
|
SDL_RenderCommand *finalcmd = cmd;
|
||||||
|
SDL_RenderCommand *nextcmd;
|
||||||
|
size_t count = cmd->data.draw.count;
|
||||||
const size_t first = cmd->data.draw.first;
|
const size_t first = cmd->data.draw.first;
|
||||||
SetDrawState(data, cmd);
|
const size_t start = first / sizeof(Vertex);
|
||||||
if (vbo) {
|
const Vertex *verts = (Vertex *)(((Uint8 *)vertices) + first);
|
||||||
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLELIST, (UINT)(first / sizeof(Vertex)), (UINT)count / 3);
|
for (nextcmd = cmd->next; nextcmd; nextcmd = nextcmd->next) {
|
||||||
} else {
|
const SDL_RenderCommandType nextcmdtype = nextcmd->command;
|
||||||
const Vertex *verts = (Vertex *)(((Uint8 *)vertices) + first);
|
if (nextcmdtype != thiscmdtype) {
|
||||||
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLELIST, (UINT)count / 3, verts, sizeof(Vertex));
|
if (nextcmdtype == SDL_RENDERCMD_SETDRAWCOLOR) {
|
||||||
|
// The vertex data has the draw color built in, ignore this
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break; // can't go any further on this draw call, different render command up next.
|
||||||
|
} else if (nextcmd->data.draw.texture != thistexture ||
|
||||||
|
nextcmd->data.draw.texture_scale_mode != thisscalemode ||
|
||||||
|
nextcmd->data.draw.texture_address_mode_u != thisaddressmode_u ||
|
||||||
|
nextcmd->data.draw.texture_address_mode_v != thisaddressmode_v ||
|
||||||
|
nextcmd->data.draw.blend != thisblend) {
|
||||||
|
break; // can't go any further on this draw call, different texture/blendmode copy up next.
|
||||||
|
} else {
|
||||||
|
finalcmd = nextcmd; // we can combine copy operations here. Mark this one as the furthest okay command.
|
||||||
|
count += nextcmd->data.draw.count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetDrawState(data, cmd);
|
||||||
|
|
||||||
|
if (thiscmdtype == SDL_RENDERCMD_GEOMETRY) {
|
||||||
|
if (vbo) {
|
||||||
|
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLELIST, (UINT)start, (UINT)count / 3);
|
||||||
|
} else {
|
||||||
|
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLELIST, (UINT)count / 3, verts, sizeof(Vertex));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (vbo) {
|
||||||
|
IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT)start, (UINT)count);
|
||||||
|
} else {
|
||||||
|
IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, (UINT)count, verts, sizeof(Vertex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd = finalcmd; // skip any copy commands we just combined in here.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user