render: simplify vertex and uniform data allocation. Improves performance of various SDL_Render functions (bug #4764).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 5b0c1bf..6e7ec61 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -202,8 +202,6 @@ DebugLogRenderCommands(const SDL_RenderCommand *cmd)
static int
FlushRenderCommands(SDL_Renderer *renderer)
{
- SDL_AllocVertGap *prevgap = &renderer->vertex_data_gaps;
- SDL_AllocVertGap *gap = prevgap;
int retval;
SDL_assert((renderer->render_commands == NULL) == (renderer->render_commands_tail == NULL));
@@ -217,14 +215,6 @@ FlushRenderCommands(SDL_Renderer *renderer)
retval = renderer->RunCommandQueue(renderer, renderer->render_commands, renderer->vertex_data, renderer->vertex_data_used);
- while (gap) {
- prevgap = gap;
- gap = gap->next;
- }
- prevgap->next = renderer->vertex_data_gaps_pool;
- renderer->vertex_data_gaps_pool = renderer->vertex_data_gaps.next;
- renderer->vertex_data_gaps.next = NULL;
-
/* Move the whole render command queue to the unused pool so we can reuse them next time. */
if (renderer->render_commands_tail != NULL) {
renderer->render_commands_tail->next = renderer->render_commands_pool;
@@ -263,79 +253,23 @@ SDL_RenderFlush(SDL_Renderer * renderer)
return FlushRenderCommands(renderer);
}
-static SDL_AllocVertGap *
-AllocateVertexGap(SDL_Renderer *renderer)
-{
- SDL_AllocVertGap *retval = renderer->vertex_data_gaps_pool;
- if (retval) {
- renderer->vertex_data_gaps_pool = retval->next;
- retval->next = NULL;
- } else {
- retval = (SDL_AllocVertGap *) SDL_malloc(sizeof (SDL_AllocVertGap));
- if (!retval) {
- SDL_OutOfMemory();
- }
- }
- return retval;
-}
-
-
void *
SDL_AllocateRenderVertices(SDL_Renderer *renderer, const size_t numbytes, const size_t alignment, size_t *offset)
{
const size_t needed = renderer->vertex_data_used + numbytes + alignment;
- size_t aligner, aligned;
- void *retval;
-
- SDL_AllocVertGap *prevgap = &renderer->vertex_data_gaps;
- SDL_AllocVertGap *gap = prevgap->next;
- while (gap) {
- const size_t gapoffset = gap->offset;
- aligner = (alignment && ((gap->offset % alignment) != 0)) ? (alignment - (gap->offset % alignment)) : 0;
- aligned = gapoffset + aligner;
-
- /* Can we use this gap? */
- if ((aligner < gap->len) && ((gap->len - aligner) >= numbytes)) {
- /* we either finished this gap off, trimmed the left, trimmed the right, or split it into two gaps. */
- if (gap->len == numbytes) { /* finished it off, remove it */
- SDL_assert(aligned == gapoffset);
- prevgap->next = gap->next;
- gap->next = renderer->vertex_data_gaps_pool;
- renderer->vertex_data_gaps_pool = gap;
- } else if (aligned == gapoffset) { /* trimmed the left */
- gap->offset += numbytes;
- gap->len -= numbytes;
- } else if (((aligned - gapoffset) + numbytes) == gap->len) { /* trimmed the right */
- gap->len -= numbytes;
- } else { /* split into two gaps */
- SDL_AllocVertGap *newgap = AllocateVertexGap(renderer);
- if (!newgap) {
- return NULL;
- }
- newgap->offset = aligned + numbytes;
- newgap->len = gap->len - (aligner + numbytes);
- newgap->next = gap->next;
- // gap->offset doesn't change.
- gap->len = aligner;
- gap->next = newgap;
- }
+ size_t current_offset = renderer->vertex_data_used;
- if (offset) {
- *offset = aligned;
- }
- return ((Uint8 *) renderer->vertex_data) + aligned;
- }
-
- /* Try the next gap */
- prevgap = gap;
- gap = gap->next;
- }
+ size_t aligner = (alignment && ((current_offset & (alignment - 1)) != 0)) ? (alignment - (current_offset & (alignment - 1))) : 0;
+ size_t aligned = current_offset + aligner;
- /* no gaps with enough space; get a new piece of the vertex buffer */
- while (needed > renderer->vertex_data_allocation) {
+ if (renderer->vertex_data_allocation < needed) {
const size_t current_allocation = renderer->vertex_data ? renderer->vertex_data_allocation : 1024;
- const size_t newsize = current_allocation * 2;
- void *ptr = SDL_realloc(renderer->vertex_data, newsize);
+ size_t newsize = current_allocation * 2;
+ void *ptr;
+ while (newsize < needed) {
+ newsize *= 2;
+ }
+ ptr = SDL_realloc(renderer->vertex_data, newsize);
if (ptr == NULL) {
SDL_OutOfMemory();
return NULL;
@@ -344,27 +278,13 @@ SDL_AllocateRenderVertices(SDL_Renderer *renderer, const size_t numbytes, const
renderer->vertex_data_allocation = newsize;
}
- aligner = (alignment && ((renderer->vertex_data_used % alignment) != 0)) ? (alignment - (renderer->vertex_data_used % alignment)) : 0;
- aligned = renderer->vertex_data_used + aligner;
-
- retval = ((Uint8 *) renderer->vertex_data) + aligned;
if (offset) {
*offset = aligned;
}
- if (aligner) { /* made a new gap... */
- SDL_AllocVertGap *newgap = AllocateVertexGap(renderer);
- if (newgap) { /* just let it slide as lost space if malloc fails. */
- newgap->offset = renderer->vertex_data_used;
- newgap->len = aligner;
- newgap->next = NULL;
- prevgap->next = newgap;
- }
- }
-
renderer->vertex_data_used += aligner + numbytes;
- return retval;
+ return ((Uint8 *) renderer->vertex_data) + aligned;
}
static SDL_RenderCommand *
@@ -3177,8 +3097,6 @@ void
SDL_DestroyRenderer(SDL_Renderer * renderer)
{
SDL_RenderCommand *cmd;
- SDL_AllocVertGap *gap;
- SDL_AllocVertGap *nextgap;
CHECK_RENDERER_MAGIC(renderer, );
@@ -3203,16 +3121,6 @@ SDL_DestroyRenderer(SDL_Renderer * renderer)
SDL_free(renderer->vertex_data);
- for (gap = renderer->vertex_data_gaps.next; gap; gap = nextgap) {
- nextgap = gap->next;
- SDL_free(gap);
- }
-
- for (gap = renderer->vertex_data_gaps_pool; gap; gap = nextgap) {
- nextgap = gap->next;
- SDL_free(gap);
- }
-
/* Free existing textures for this renderer */
while (renderer->textures) {
SDL_Texture *tex = renderer->textures; (void) tex;
diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h
index 9386562..dedd642 100644
--- a/src/render/SDL_sysrender.h
+++ b/src/render/SDL_sysrender.h
@@ -110,13 +110,6 @@ typedef struct SDL_RenderCommand
struct SDL_RenderCommand *next;
} SDL_RenderCommand;
-typedef struct SDL_AllocVertGap
-{
- size_t offset;
- size_t len;
- struct SDL_AllocVertGap *next;
-} SDL_AllocVertGap;
-
/* Define the SDL renderer structure */
struct SDL_Renderer
@@ -226,8 +219,6 @@ struct SDL_Renderer
void *vertex_data;
size_t vertex_data_used;
size_t vertex_data_allocation;
- SDL_AllocVertGap vertex_data_gaps;
- SDL_AllocVertGap *vertex_data_gaps_pool;
void *driverdata;
};