Bug in the way SDL handles Texture indexing

Let’s say we want to fill a texture, width*height, with red. We draw the red pixel from left to right, bottom to top, then we rendercopy it to the window directly. (So bottom now becomes top).

This is the C code I’m using, and it’s making a mess.

void main(){
	int width = 14;
	int height = 16;

	int pitch = width*3;
	uint8_t *pixels;

	if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
		fprintf(stderr, "SDL_Init Error: %s\n", SDL_GetError());
		return EXIT_FAILURE;
	}

	SDL_Window * window = SDL_CreateWindow(
		"(Rendering first frame)", 
		SDL_WINDOWPOS_UNDEFINED, 
		SDL_WINDOWPOS_UNDEFINED, 
		width*10, 
		height*10, 
		SDL_WINDOW_RESIZABLE
	);

	SDL_Renderer * renderer;
	renderer = SDL_CreateRenderer(
		window,
		-1,
		SDL_RENDERER_ACCELERATED
	);

	SDL_Texture * buffer = SDL_CreateTexture(
		renderer,
		SDL_PIXELFORMAT_RGB24, // char red, char blue, char green
		SDL_TEXTUREACCESS_STREAMING, 
		width, height
	);

	for (int i = 0; i < width*height; ++i)	
	{
		SDL_LockTexture (buffer, NULL, (void **) &pixels, &pitch);

		int x = i%width;
		int y = height - i/width -1; // always rounds down because of C int division, go bottom to top
		printf("x:%d\ty:%d\ti:%d\n", x, y, i);
			

		int index = i*3;
		pixels[index]   = 255; // red
		pixels[index+1] = 0;   // green
		pixels[index+2] = 0;   // blue

		SDL_Delay(10);
		SDL_UnlockTexture(buffer);	
		SDL_RenderCopy(renderer, buffer, NULL, NULL);
		SDL_RenderPresent(renderer);
	}
	
	// I will spare you all the free()
}

I expect a window to pop up that slowly fills red. Instead I get this abomination, note that the bottom row isn’t even fully filled in at the end! How is it even possible that I get different colors? You would think that the step size is mismatched for the array, for instance the array has groups of 3 (r,g,b) but I go in step of 4. Well that’s clearly not the case, as it’s just a simple `for i = 0; i++) loop. Note that I multiply i by 3 to get the array index. By all means this should just work.

Screenshot_2020-01-07_23-10-15

stdout: (note how ZERO pixels are skipped)

x:0	y:15	i:0
x:1	y:15	i:1
x:2	y:15	i:2
x:3	y:15	i:3
x:4	y:15	i:4
x:5	y:15	i:5
x:6	y:15	i:6
x:7	y:15	i:7
x:8	y:15	i:8
x:9	y:15	i:9
x:10	y:15	i:10
x:11	y:15	i:11
x:12	y:15	i:12
x:13	y:15	i:13
x:0	y:14	i:14
x:1	y:14	i:15
x:2	y:14	i:16
x:3	y:14	i:17
x:4	y:14	i:18
x:5	y:14	i:19
x:6	y:14	i:20
x:7	y:14	i:21
x:8	y:14	i:22
x:9	y:14	i:23
x:10	y:14	i:24
x:11	y:14	i:25
x:12	y:14	i:26
x:13	y:14	i:27
x:0	y:13	i:28
x:1	y:13	i:29
x:2	y:13	i:30
x:3	y:13	i:31
x:4	y:13	i:32
x:5	y:13	i:33
x:6	y:13	i:34
x:7	y:13	i:35
x:8	y:13	i:36
x:9	y:13	i:37
x:10	y:13	i:38
x:11	y:13	i:39
x:12	y:13	i:40
x:13	y:13	i:41
x:0	y:12	i:42
x:1	y:12	i:43
x:2	y:12	i:44
x:3	y:12	i:45
x:4	y:12	i:46
x:5	y:12	i:47
x:6	y:12	i:48
x:7	y:12	i:49
x:8	y:12	i:50
x:9	y:12	i:51
x:10	y:12	i:52
x:11	y:12	i:53
x:12	y:12	i:54
x:13	y:12	i:55
x:0	y:11	i:56
x:1	y:11	i:57
x:2	y:11	i:58
x:3	y:11	i:59
x:4	y:11	i:60
x:5	y:11	i:61
x:6	y:11	i:62
x:7	y:11	i:63
x:8	y:11	i:64
x:9	y:11	i:65
x:10	y:11	i:66
x:11	y:11	i:67
x:12	y:11	i:68
x:13	y:11	i:69
x:0	y:10	i:70
x:1	y:10	i:71
x:2	y:10	i:72
x:3	y:10	i:73
x:4	y:10	i:74
x:5	y:10	i:75
x:6	y:10	i:76
x:7	y:10	i:77
x:8	y:10	i:78
x:9	y:10	i:79
x:10	y:10	i:80
x:11	y:10	i:81
x:12	y:10	i:82
x:13	y:10	i:83
x:0	y:9	i:84
x:1	y:9	i:85
x:2	y:9	i:86
x:3	y:9	i:87
x:4	y:9	i:88
x:5	y:9	i:89
x:6	y:9	i:90
x:7	y:9	i:91
x:8	y:9	i:92
x:9	y:9	i:93
x:10	y:9	i:94
x:11	y:9	i:95
x:12	y:9	i:96
x:13	y:9	i:97
x:0	y:8	i:98
x:1	y:8	i:99
x:2	y:8	i:100
x:3	y:8	i:101
x:4	y:8	i:102
x:5	y:8	i:103
x:6	y:8	i:104
x:7	y:8	i:105
x:8	y:8	i:106
x:9	y:8	i:107
x:10	y:8	i:108
x:11	y:8	i:109
x:12	y:8	i:110
x:13	y:8	i:111
x:0	y:7	i:112
x:1	y:7	i:113
x:2	y:7	i:114
x:3	y:7	i:115
x:4	y:7	i:116
x:5	y:7	i:117
x:6	y:7	i:118
x:7	y:7	i:119
x:8	y:7	i:120
x:9	y:7	i:121
x:10	y:7	i:122
x:11	y:7	i:123
x:12	y:7	i:124
x:13	y:7	i:125
x:0	y:6	i:126
x:1	y:6	i:127
x:2	y:6	i:128
x:3	y:6	i:129
x:4	y:6	i:130
x:5	y:6	i:131
x:6	y:6	i:132
x:7	y:6	i:133
x:8	y:6	i:134
x:9	y:6	i:135
x:10	y:6	i:136
x:11	y:6	i:137
x:12	y:6	i:138
x:13	y:6	i:139
x:0	y:5	i:140
x:1	y:5	i:141
x:2	y:5	i:142
x:3	y:5	i:143
x:4	y:5	i:144
x:5	y:5	i:145
x:6	y:5	i:146
x:7	y:5	i:147
x:8	y:5	i:148
x:9	y:5	i:149
x:10	y:5	i:150
x:11	y:5	i:151
x:12	y:5	i:152
x:13	y:5	i:153
x:0	y:4	i:154
x:1	y:4	i:155
x:2	y:4	i:156
x:3	y:4	i:157
x:4	y:4	i:158
x:5	y:4	i:159
x:6	y:4	i:160
x:7	y:4	i:161
x:8	y:4	i:162
x:9	y:4	i:163
x:10	y:4	i:164
x:11	y:4	i:165
x:12	y:4	i:166
x:13	y:4	i:167
x:0	y:3	i:168
x:1	y:3	i:169
x:2	y:3	i:170
x:3	y:3	i:171
x:4	y:3	i:172
x:5	y:3	i:173
x:6	y:3	i:174
x:7	y:3	i:175
x:8	y:3	i:176
x:9	y:3	i:177
x:10	y:3	i:178
x:11	y:3	i:179
x:12	y:3	i:180
x:13	y:3	i:181
x:0	y:2	i:182
x:1	y:2	i:183
x:2	y:2	i:184
x:3	y:2	i:185
x:4	y:2	i:186
x:5	y:2	i:187
x:6	y:2	i:188
x:7	y:2	i:189
x:8	y:2	i:190
x:9	y:2	i:191
x:10	y:2	i:192
x:11	y:2	i:193
x:12	y:2	i:194
x:13	y:2	i:195
x:0	y:1	i:196
x:1	y:1	i:197
x:2	y:1	i:198
x:3	y:1	i:199
x:4	y:1	i:200
x:5	y:1	i:201
x:6	y:1	i:202
x:7	y:1	i:203
x:8	y:1	i:204
x:9	y:1	i:205
x:10	y:1	i:206
x:11	y:1	i:207
x:12	y:1	i:208
x:13	y:1	i:209
x:0	y:0	i:210
x:1	y:0	i:211
x:2	y:0	i:212
x:3	y:0	i:213
x:4	y:0	i:214
x:5	y:0	i:215
x:6	y:0	i:216
x:7	y:0	i:217
x:8	y:0	i:218
x:9	y:0	i:219
x:10	y:0	i:220
x:11	y:0	i:221
x:12	y:0	i:222
x:13	y:0	i:223

Now, it doesn’t always do this! If I pick a resolution of say 16x16 it will work as expected! WHY?

It is mismatched, because you are ignoring the pitch value returned from SDL_LockTexture()! Only if the pitch is equal to width*3 are the pixels close-packed in the way your code is assuming, but I bet it isn’t!

You need to modify the code which fills the array to take account of the pitch, something like this:

int index = (i / width) * pitch + (i % width) * 3 ;

1 Like

Hold on, does sdl store a texture internally as a bitmap? That would explain why I only get this issue on certain resolutions, because bitmaps need a certain data width filled up every row.

Your solution fixed my problem, thank you!

Typically, with a 24-bpp PIXELFORMAT, each individual line is DWORD-aligned. So if width*3 isn’t an exact multiple of 4 there are padding bytes between one line and the next. If width*3 is an exact multiple of 4 no padding is required, which is why you don’t see the problem with certain widths.

1 Like