Mercurial > repos > blastem
comparison render_sdl.c @ 449:7696d824489d opengl
Started work on OpenGL support in new branch
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 23 Jul 2013 23:01:03 -0700 |
parents | add9e2f5c0e3 |
children | c08a4efeee7f |
comparison
equal
deleted
inserted
replaced
428:006008a3f370 | 449:7696d824489d |
---|---|
2 #include <stdio.h> | 2 #include <stdio.h> |
3 #include "render.h" | 3 #include "render.h" |
4 #include "blastem.h" | 4 #include "blastem.h" |
5 #include "io.h" | 5 #include "io.h" |
6 | 6 |
7 #ifndef DISABLE_OPENGL | |
8 #include <GL/gl.h> | |
9 #endif | |
10 | |
7 SDL_Surface *screen; | 11 SDL_Surface *screen; |
8 uint8_t render_dbg = 0; | 12 uint8_t render_dbg = 0; |
9 uint8_t debug_pal = 0; | 13 uint8_t debug_pal = 0; |
14 uint8_t render_gl; | |
10 | 15 |
11 uint32_t last_frame = 0; | 16 uint32_t last_frame = 0; |
12 | 17 |
13 uint32_t min_delay; | 18 uint32_t min_delay; |
14 uint32_t frame_delay = 1000/60; | 19 uint32_t frame_delay = 1000/60; |
73 SDL_Joystick * joysticks[MAX_JOYSTICKS]; | 78 SDL_Joystick * joysticks[MAX_JOYSTICKS]; |
74 int num_joysticks; | 79 int num_joysticks; |
75 | 80 |
76 uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b) | 81 uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b) |
77 { | 82 { |
78 return SDL_MapRGB(screen->format, r, g, b); | 83 if (render_gl) { |
84 return b << 24 | g << 16 | r << 8 | 255; | |
85 } else { | |
86 return SDL_MapRGB(screen->format, r, g, b); | |
87 } | |
88 } | |
89 | |
90 GLuint textures[3], buffers[2]; | |
91 | |
92 const GLfloat vertex_data[] = { | |
93 -1.0f, -1.0f, | |
94 1.0f, -1.0f, | |
95 -1.0f, 1.0f, | |
96 1.0f, 1.0f | |
97 }; | |
98 | |
99 const GLushort element_data[] = {0, 1, 2, 3}; | |
100 | |
101 void render_alloc_surfaces(vdp_context * context) | |
102 { | |
103 if (render_gl) { | |
104 context->oddbuf = context->framebuf = malloc(320 * 240 * 4 * 2); | |
105 memset(context->oddbuf, 0, 320 * 240 * 4 * 2); | |
106 context->evenbuf = ((char *)context->oddbuf) + 320 * 240 * 4; | |
107 glGenTextures(3, textures); | |
108 for (int i = 0; i < 3; i++) | |
109 { | |
110 glBindTexture(GL_TEXTURE_2D, textures[i]); | |
111 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
112 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
113 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
114 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
115 if (i < 2) { | |
116 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, i ? context->evenbuf : context->oddbuf); | |
117 } else { | |
118 uint32_t blank = 255; | |
119 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank); | |
120 } | |
121 } | |
122 glGenBuffers(2, buffers); | |
123 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); | |
124 glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); | |
125 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[0]); | |
126 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW); | |
127 } else { | |
128 context->oddbuf = context->framebuf = malloc(320 * 240 * screen->format->BytesPerPixel * 2); | |
129 context->evenbuf = ((char *)context->oddbuf) + 320 * 240 * screen->format->BytesPerPixel; | |
130 } | |
79 } | 131 } |
80 | 132 |
81 uint8_t render_depth() | 133 uint8_t render_depth() |
82 { | 134 { |
83 return screen->format->BytesPerPixel * 8; | 135 return screen->format->BytesPerPixel * 8; |
84 } | 136 } |
85 | 137 |
86 void render_init(int width, int height, char * title, uint32_t fps) | 138 void render_init(int width, int height, char * title, uint32_t fps, uint8_t use_gl) |
87 { | 139 { |
88 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) { | 140 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) { |
89 fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); | 141 fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); |
90 exit(1); | 142 exit(1); |
91 } | 143 } |
92 atexit(SDL_Quit); | 144 atexit(SDL_Quit); |
93 atexit(render_close_audio); | 145 atexit(render_close_audio); |
94 printf("width: %d, height: %d\n", width, height); | 146 printf("width: %d, height: %d\n", width, height); |
95 screen = SDL_SetVideoMode(width, height, 32, SDL_SWSURFACE | SDL_ANYFORMAT); | 147 uint32_t flags |
96 if (!screen) { | 148 #ifndef DISABLE_OPENGL |
97 fprintf(stderr, "Unable to get SDL surface: %s\n", SDL_GetError()); | 149 if (use_gl) |
98 exit(1); | 150 { |
99 } | 151 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); |
100 if (screen->format->BytesPerPixel != 2 && screen->format->BytesPerPixel != 4) { | 152 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); |
101 fprintf(stderr, "BlastEm requires a 16-bit or 32-bit surface, SDL returned a %d-bit surface\n", screen->format->BytesPerPixel * 8); | 153 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); |
102 exit(1); | 154 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); |
103 } | 155 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); |
104 SDL_WM_SetCaption(title, title); | 156 flags = SDL_OPENGL; |
105 min_delay = 0; | 157 } else { |
106 for (int i = 0; i < 100; i++) { | 158 #else |
107 uint32_t start = SDL_GetTicks(); | 159 { |
108 SDL_Delay(1); | 160 #endif |
109 uint32_t delay = SDL_GetTicks()-start; | 161 flags = SDL_SWSURFACE | SDL_ANYFORMAT; |
110 if (delay > min_delay) { | 162 } |
111 min_delay = delay; | 163 screen = SDL_SetVideoMode(width, height, 32, flags); |
112 } | 164 if (!screen) { |
113 } | 165 fprintf(stderr, "Unable to get SDL surface: %s\n", SDL_GetError()); |
114 if (!min_delay) { | 166 exit(1); |
115 min_delay = 1; | 167 } |
116 } | 168 if (!use_gl && screen->format->BytesPerPixel != 2 && screen->format->BytesPerPixel != 4) { |
117 printf("minimum delay: %d\n", min_delay); | 169 fprintf(stderr, "BlastEm requires a 16-bit or 32-bit surface, SDL returned a %d-bit surface\n", screen->format->BytesPerPixel * 8); |
118 | 170 exit(1); |
119 frame_delay = 1000/fps; | 171 } |
120 | 172 #ifndef DISABLE_OPENGL |
121 audio_mutex = SDL_CreateMutex(); | 173 //TODO: Fallback to plain SDL if OpenGL 2.0 not available |
122 psg_cond = SDL_CreateCond(); | 174 render_gl = use_gl; |
123 ym_cond = SDL_CreateCond(); | 175 #endif |
124 audio_ready = SDL_CreateCond(); | 176 SDL_WM_SetCaption(title, title); |
125 | 177 min_delay = 0; |
126 SDL_AudioSpec desired, actual; | 178 for (int i = 0; i < 100; i++) { |
127 desired.freq = 48000; | 179 uint32_t start = SDL_GetTicks(); |
128 desired.format = AUDIO_S16SYS; | 180 SDL_Delay(1); |
129 desired.channels = 2; | 181 uint32_t delay = SDL_GetTicks()-start; |
130 desired.samples = 2048;//1024; | 182 if (delay > min_delay) { |
131 desired.callback = audio_callback; | 183 min_delay = delay; |
132 desired.userdata = NULL; | 184 } |
133 | 185 } |
134 if (SDL_OpenAudio(&desired, &actual) < 0) { | 186 if (!min_delay) { |
135 fprintf(stderr, "Unable to open SDL audio: %s\n", SDL_GetError()); | 187 min_delay = 1; |
136 exit(1); | 188 } |
137 } | 189 printf("minimum delay: %d\n", min_delay); |
138 buffer_samples = actual.samples; | 190 |
139 sample_rate = actual.freq; | 191 frame_delay = 1000/fps; |
140 printf("Initialized audio at frequency %d with a %d sample buffer\n", actual.freq, actual.samples); | 192 |
141 SDL_PauseAudio(0); | 193 audio_mutex = SDL_CreateMutex(); |
142 num_joysticks = SDL_NumJoysticks(); | 194 psg_cond = SDL_CreateCond(); |
143 if (num_joysticks > MAX_JOYSTICKS) { | 195 ym_cond = SDL_CreateCond(); |
144 num_joysticks = MAX_JOYSTICKS; | 196 audio_ready = SDL_CreateCond(); |
145 } | 197 |
146 for (int i = 0; i < num_joysticks; i++) { | 198 SDL_AudioSpec desired, actual; |
147 printf("Joystick %d: %s\n", i, SDL_JoystickName(i)); | 199 desired.freq = 48000; |
148 SDL_Joystick * joy = joysticks[i] = SDL_JoystickOpen(i); | 200 desired.format = AUDIO_S16SYS; |
149 if (joy) { | 201 desired.channels = 2; |
150 printf("\tNum Axes: %d\n\tNum Buttons: %d\n\tNum Hats: %d\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy)); | 202 desired.samples = 2048;//1024; |
151 } | 203 desired.callback = audio_callback; |
152 } | 204 desired.userdata = NULL; |
153 SDL_JoystickEventState(SDL_ENABLE); | 205 |
206 if (SDL_OpenAudio(&desired, &actual) < 0) { | |
207 fprintf(stderr, "Unable to open SDL audio: %s\n", SDL_GetError()); | |
208 exit(1); | |
209 } | |
210 buffer_samples = actual.samples; | |
211 sample_rate = actual.freq; | |
212 printf("Initialized audio at frequency %d with a %d sample buffer\n", actual.freq, actual.samples); | |
213 SDL_PauseAudio(0); | |
214 num_joysticks = SDL_NumJoysticks(); | |
215 if (num_joysticks > MAX_JOYSTICKS) { | |
216 num_joysticks = MAX_JOYSTICKS; | |
217 } | |
218 for (int i = 0; i < num_joysticks; i++) { | |
219 printf("Joystick %d: %s\n", i, SDL_JoystickName(i)); | |
220 SDL_Joystick * joy = joysticks[i] = SDL_JoystickOpen(i); | |
221 if (joy) { | |
222 printf("\tNum Axes: %d\n\tNum Buttons: %d\n\tNum Hats: %d\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy)); | |
223 } | |
224 } | |
225 SDL_JoystickEventState(SDL_ENABLE); | |
226 } | |
227 | |
228 void render_context_gl(vdp_context * context) | |
229 { | |
230 glBindTexture(GL_TEXTURE_2D, textures[context->framebuf == context->oddbuf ? 0 : 1]); | |
231 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, 240, GL_BGRA, GL_UNSIGNED_BYTE, context->framebuf);; | |
232 | |
233 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); | |
234 glClear(GL_COLOR_BUFFER_BIT); | |
235 | |
154 } | 236 } |
155 | 237 |
156 uint32_t blankbuf[320*240]; | 238 uint32_t blankbuf[320*240]; |
157 | 239 |
158 void render_context(vdp_context * context) | 240 void render_context(vdp_context * context) |
159 { | 241 { |
160 uint16_t *buf_16; | 242 uint16_t *buf_16; |
161 uint32_t *buf_32; | 243 uint32_t *buf_32; |
162 uint8_t b,g,r; | 244 uint8_t b,g,r; |
163 last_frame = SDL_GetTicks(); | 245 last_frame = SDL_GetTicks(); |
246 if (render_gl) | |
247 { | |
248 render_context_gl(context); | |
249 return; | |
250 } | |
164 if (SDL_MUSTLOCK(screen)) { | 251 if (SDL_MUSTLOCK(screen)) { |
165 if (SDL_LockSurface(screen) < 0) { | 252 if (SDL_LockSurface(screen) < 0) { |
166 return; | 253 return; |
167 } | 254 } |
168 } | 255 } |
169 uint16_t repeat_x = screen->clip_rect.w / 320; | 256 uint16_t repeat_x = screen->clip_rect.w / 320; |
170 uint16_t repeat_y = screen->clip_rect.h / 240; | 257 uint16_t repeat_y = screen->clip_rect.h / 240; |
171 if (repeat_x > repeat_y) { | 258 if (repeat_x > repeat_y) { |
172 repeat_x = repeat_y; | 259 repeat_x = repeat_y; |
173 } else { | 260 } else { |
174 repeat_y = repeat_x; | 261 repeat_y = repeat_x; |
175 } | 262 } |
176 int othermask = repeat_y >> 1; | 263 int othermask = repeat_y >> 1; |
177 | 264 |
178 if (screen->format->BytesPerPixel == 2) { | 265 if (screen->format->BytesPerPixel == 2) { |
179 uint16_t *otherbuf = (context->regs[REG_MODE_4] & BIT_INTERLACE) ? context->evenbuf : (uint16_t *)blankbuf; | 266 uint16_t *otherbuf = (context->regs[REG_MODE_4] & BIT_INTERLACE) ? context->evenbuf : (uint16_t *)blankbuf; |
180 uint16_t * oddbuf = context->oddbuf; | 267 uint16_t * oddbuf = context->oddbuf; |
181 buf_16 = (uint16_t *)screen->pixels; | 268 buf_16 = (uint16_t *)screen->pixels; |
182 for (int y = 0; y < 240; y++) { | 269 for (int y = 0; y < 240; y++) { |
183 for (int i = 0; i < repeat_y; i++,buf_16 += screen->pitch/2) { | 270 for (int i = 0; i < repeat_y; i++,buf_16 += screen->pitch/2) { |
184 uint16_t *line = buf_16; | 271 uint16_t *line = buf_16; |
185 uint16_t *src_line = (i & othermask ? otherbuf : oddbuf) + y * 320; | 272 uint16_t *src_line = (i & othermask ? otherbuf : oddbuf) + y * 320; |
186 for (int x = 0; x < 320; x++) { | 273 for (int x = 0; x < 320; x++) { |
187 uint16_t color = *(src_line++); | 274 uint16_t color = *(src_line++); |
188 for (int j = 0; j < repeat_x; j++) { | 275 for (int j = 0; j < repeat_x; j++) { |
189 *(line++) = color; | 276 *(line++) = color; |
190 } | 277 } |
191 } | 278 } |
192 } | 279 } |
193 } | 280 } |
194 } else { | 281 } else { |
195 uint32_t *otherbuf = (context->regs[REG_MODE_4] & BIT_INTERLACE) ? context->evenbuf : (uint32_t *)blankbuf; | 282 uint32_t *otherbuf = (context->regs[REG_MODE_4] & BIT_INTERLACE) ? context->evenbuf : (uint32_t *)blankbuf; |
196 uint32_t * oddbuf = context->oddbuf; | 283 uint32_t * oddbuf = context->oddbuf; |
197 buf_32 = (uint32_t *)screen->pixels; | 284 buf_32 = (uint32_t *)screen->pixels; |
198 for (int y = 0; y < 240; y++) { | 285 for (int y = 0; y < 240; y++) { |
199 for (int i = 0; i < repeat_y; i++,buf_32 += screen->pitch/4) { | 286 for (int i = 0; i < repeat_y; i++,buf_32 += screen->pitch/4) { |
200 uint32_t *line = buf_32; | 287 uint32_t *line = buf_32; |
201 uint32_t *src_line = (i & othermask ? otherbuf : oddbuf) + y * 320; | 288 uint32_t *src_line = (i & othermask ? otherbuf : oddbuf) + y * 320; |
202 for (int x = 0; x < 320; x++) { | 289 for (int x = 0; x < 320; x++) { |
203 uint32_t color = *(src_line++); | 290 uint32_t color = *(src_line++); |
204 for (int j = 0; j < repeat_x; j++) { | 291 for (int j = 0; j < repeat_x; j++) { |
205 *(line++) = color; | 292 *(line++) = color; |
206 } | 293 } |
207 } | 294 } |
208 } | 295 } |
209 } | 296 } |
210 } | 297 } |
211 if ( SDL_MUSTLOCK(screen) ) { | 298 if ( SDL_MUSTLOCK(screen) ) { |
212 SDL_UnlockSurface(screen); | 299 SDL_UnlockSurface(screen); |
213 } | 300 } |
214 SDL_UpdateRect(screen, 0, 0, screen->clip_rect.w, screen->clip_rect.h); | 301 SDL_UpdateRect(screen, 0, 0, screen->clip_rect.w, screen->clip_rect.h); |
215 if (context->regs[REG_MODE_4] & BIT_INTERLACE) | 302 if (context->regs[REG_MODE_4] & BIT_INTERLACE) |
216 { | 303 { |
217 context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; | 304 context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; |
218 } | 305 } |
219 } | 306 } |
220 | 307 |
221 int render_joystick_num_buttons(int joystick) | 308 int render_joystick_num_buttons(int joystick) |
222 { | 309 { |
223 if (joystick >= num_joysticks) { | 310 if (joystick >= num_joysticks) { |
319 while ((desired) >= SDL_GetTicks()) { | 406 while ((desired) >= SDL_GetTicks()) { |
320 } | 407 } |
321 } | 408 } |
322 } | 409 } |
323 render_context(context); | 410 render_context(context); |
324 | 411 |
325 | 412 |
326 //TODO: Figure out why this causes segfaults | 413 //TODO: Figure out why this causes segfaults |
327 /*frame_counter++; | 414 /*frame_counter++; |
328 if ((last_frame - start) > 1000) { | 415 if ((last_frame - start) > 1000) { |
329 if (start && (last_frame-start)) { | 416 if (start && (last_frame-start)) { |
330 printf("\r%f fps", ((float)frame_counter) / (((float)(last_frame-start)) / 1000.0)); | 417 printf("\r%f fps", ((float)frame_counter) / (((float)(last_frame-start)) / 1000.0)); |