Mercurial > repos > blastem
comparison render_sdl.c @ 798:062a2199daf6
Use SDL2 renderer as a fallback
author | =?UTF-8?q?Higor=20Eur=C3=ADpedes?= <heuripedes@gmail.com> |
---|---|
date | Sun, 26 Jul 2015 13:08:22 -0700 |
parents | 65181c3ee560 |
children | 0b692b5d154b |
comparison
equal
deleted
inserted
replaced
797:65181c3ee560 | 798:062a2199daf6 |
---|---|
10 #include "render.h" | 10 #include "render.h" |
11 #include "blastem.h" | 11 #include "blastem.h" |
12 #include "io.h" | 12 #include "io.h" |
13 #include "util.h" | 13 #include "util.h" |
14 | 14 |
15 #ifndef DISABLE_OPENGL | |
15 #include <GL/glew.h> | 16 #include <GL/glew.h> |
17 #endif | |
16 | 18 |
17 SDL_Window *main_window; | 19 SDL_Window *main_window; |
18 #ifdef DISABLE_OPENGL | |
19 SDL_Renderer *main_renderer; | 20 SDL_Renderer *main_renderer; |
20 SDL_Texture *main_texture; | 21 SDL_Texture *main_texture; |
21 SDL_Rect main_clip; | 22 SDL_Rect main_clip; |
22 #else | |
23 SDL_GLContext *main_context; | 23 SDL_GLContext *main_context; |
24 #endif | |
25 | 24 |
26 uint8_t render_dbg = 0; | 25 uint8_t render_dbg = 0; |
27 uint8_t debug_pal = 0; | 26 uint8_t debug_pal = 0; |
27 uint8_t render_gl = 1; | |
28 | 28 |
29 uint32_t last_frame = 0; | 29 uint32_t last_frame = 0; |
30 | 30 |
31 uint32_t min_delay; | 31 uint32_t min_delay; |
32 uint32_t frame_delay = 1000/60; | 32 uint32_t frame_delay = 1000/60; |
99 uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b) | 99 uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b) |
100 { | 100 { |
101 return 255 << 24 | r << 16 | g << 8 | b; | 101 return 255 << 24 | r << 16 | g << 8 | b; |
102 } | 102 } |
103 | 103 |
104 #ifndef DISABLE_OPENGL | |
104 GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, at_pos; | 105 GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, at_pos; |
105 | 106 |
106 GLfloat vertex_data[] = { | 107 GLfloat vertex_data[] = { |
107 -1.0f, -1.0f, | 108 -1.0f, -1.0f, |
108 1.0f, -1.0f, | 109 1.0f, -1.0f, |
152 glDeleteShader(ret); | 153 glDeleteShader(ret); |
153 return 0; | 154 return 0; |
154 } | 155 } |
155 return ret; | 156 return ret; |
156 } | 157 } |
158 #endif | |
157 | 159 |
158 void render_alloc_surfaces(vdp_context * context) | 160 void render_alloc_surfaces(vdp_context * context) |
159 { | 161 { |
160 context->oddbuf = context->framebuf = malloc(512 * 256 * 4 * 2); | 162 context->oddbuf = context->framebuf = malloc(512 * 256 * 4 * 2); |
161 memset(context->oddbuf, 0, 512 * 256 * 4 * 2); | 163 memset(context->oddbuf, 0, 512 * 256 * 4 * 2); |
162 context->evenbuf = ((char *)context->oddbuf) + 512 * 256 * 4; | 164 context->evenbuf = ((char *)context->oddbuf) + 512 * 256 * 4; |
163 | 165 |
164 #ifdef DISABLE_OPENGL | 166 #ifndef DISABLE_OPENGL |
167 if (render_gl) { | |
168 glGenTextures(3, textures); | |
169 for (int i = 0; i < 3; i++) | |
170 { | |
171 glBindTexture(GL_TEXTURE_2D, textures[i]); | |
172 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
173 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
174 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
175 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
176 if (i < 2) { | |
177 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, i ? context->evenbuf : context->oddbuf); | |
178 } else { | |
179 uint32_t blank = 255 << 24; | |
180 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank); | |
181 } | |
182 } | |
183 glGenBuffers(2, buffers); | |
184 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); | |
185 glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); | |
186 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); | |
187 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW); | |
188 tern_val def = {.ptrval = "default.v.glsl"}; | |
189 vshader = load_shader(tern_find_path_default(config, "video\0vertex_shader\0", def).ptrval, GL_VERTEX_SHADER); | |
190 def.ptrval = "default.f.glsl"; | |
191 fshader = load_shader(tern_find_path_default(config, "video\0fragment_shader\0", def).ptrval, GL_FRAGMENT_SHADER); | |
192 program = glCreateProgram(); | |
193 glAttachShader(program, vshader); | |
194 glAttachShader(program, fshader); | |
195 glLinkProgram(program); | |
196 GLint link_status; | |
197 glGetProgramiv(program, GL_LINK_STATUS, &link_status); | |
198 if (!link_status) { | |
199 fputs("Failed to link shader program\n", stderr); | |
200 exit(1); | |
201 } | |
202 un_textures[0] = glGetUniformLocation(program, "textures[0]"); | |
203 un_textures[1] = glGetUniformLocation(program, "textures[1]"); | |
204 un_width = glGetUniformLocation(program, "width"); | |
205 at_pos = glGetAttribLocation(program, "pos"); | |
206 } else { | |
207 #endif | |
165 /* height=480 to fit interlaced output */ | 208 /* height=480 to fit interlaced output */ |
166 main_texture = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 480); | 209 main_texture = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 480); |
167 #else | 210 #ifndef DISABLE_OPENGL |
168 glGenTextures(3, textures); | 211 } |
169 for (int i = 0; i < 3; i++) | |
170 { | |
171 glBindTexture(GL_TEXTURE_2D, textures[i]); | |
172 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
173 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
174 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
175 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
176 if (i < 2) { | |
177 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, i ? context->evenbuf : context->oddbuf); | |
178 } else { | |
179 uint32_t blank = 255 << 24; | |
180 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank); | |
181 } | |
182 } | |
183 glGenBuffers(2, buffers); | |
184 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); | |
185 glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); | |
186 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); | |
187 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW); | |
188 tern_val def = {.ptrval = "default.v.glsl"}; | |
189 vshader = load_shader(tern_find_path_default(config, "video\0vertex_shader\0", def).ptrval, GL_VERTEX_SHADER); | |
190 def.ptrval = "default.f.glsl"; | |
191 fshader = load_shader(tern_find_path_default(config, "video\0fragment_shader\0", def).ptrval, GL_FRAGMENT_SHADER); | |
192 program = glCreateProgram(); | |
193 glAttachShader(program, vshader); | |
194 glAttachShader(program, fshader); | |
195 glLinkProgram(program); | |
196 GLint link_status; | |
197 glGetProgramiv(program, GL_LINK_STATUS, &link_status); | |
198 if (!link_status) { | |
199 fputs("Failed to link shader program\n", stderr); | |
200 exit(1); | |
201 } | |
202 un_textures[0] = glGetUniformLocation(program, "textures[0]"); | |
203 un_textures[1] = glGetUniformLocation(program, "textures[1]"); | |
204 un_width = glGetUniformLocation(program, "width"); | |
205 at_pos = glGetAttribLocation(program, "pos"); | |
206 #endif | 212 #endif |
207 } | 213 } |
208 | 214 |
209 char * caption = NULL; | 215 char * caption = NULL; |
210 | 216 |
236 //but that doesn't seem to work right when using OpenGL, at least on Linux anyway | 242 //but that doesn't seem to work right when using OpenGL, at least on Linux anyway |
237 width = mode.w; | 243 width = mode.w; |
238 height = mode.h; | 244 height = mode.h; |
239 } | 245 } |
240 | 246 |
241 #ifdef DISABLE_OPENGL | 247 render_gl = 0; |
242 SDL_CreateWindowAndRenderer(width, height, flags, &main_window, &main_renderer); | 248 |
243 | 249 #ifndef DISABLE_OPENGL |
244 if (!main_window || !main_renderer) { | |
245 fprintf(stderr, "unable to create SDL window: %s\n", SDL_GetError()); | |
246 SDL_Quit(); | |
247 exit(1); | |
248 } | |
249 main_clip.x = main_clip.y = 0; | |
250 main_clip.w = width; | |
251 main_clip.h = height; | |
252 #else | |
253 flags |= SDL_WINDOW_OPENGL; | 250 flags |= SDL_WINDOW_OPENGL; |
254 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); | 251 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); |
255 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); | 252 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); |
256 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); | 253 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); |
257 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); | 254 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); |
264 } | 261 } |
265 main_context = SDL_GL_CreateContext(main_window); | 262 main_context = SDL_GL_CreateContext(main_window); |
266 GLenum res = glewInit(); | 263 GLenum res = glewInit(); |
267 if (res != GLEW_OK) { | 264 if (res != GLEW_OK) { |
268 fprintf(stderr, "Initialization of GLEW failed with code %d\n", res); | 265 fprintf(stderr, "Initialization of GLEW failed with code %d\n", res); |
269 SDL_Quit(); | 266 SDL_DestroyWindow(main_window); |
270 exit(1); | 267 } |
271 } | 268 |
272 if (!GLEW_VERSION_2_0) { | 269 if (GLEW_VERSION_2_0) { |
273 fputs("BlastEm requires at least OpenGL 2.0, but it is unavailable\n", stderr); | 270 render_gl = 1; |
274 SDL_Quit(); | 271 } |
275 exit(1); | 272 else { |
276 } | 273 SDL_DestroyWindow(main_window); |
277 #endif | 274 fputs("OpenGL 2.0 is unavailable, falling back to SDL2 renderer\n", stderr); |
275 #endif | |
276 SDL_CreateWindowAndRenderer(width, height, flags, &main_window, &main_renderer); | |
277 | |
278 if (!main_window || !main_renderer) { | |
279 fprintf(stderr, "unable to create SDL window: %s\n", SDL_GetError()); | |
280 SDL_Quit(); | |
281 exit(1); | |
282 } | |
283 main_clip.x = main_clip.y = 0; | |
284 main_clip.w = width; | |
285 main_clip.h = height; | |
286 #ifndef DISABLE_OPENGL | |
287 } | |
288 #endif | |
289 | |
278 SDL_GetWindowSize(main_window, &width, &height); | 290 SDL_GetWindowSize(main_window, &width, &height); |
279 printf("Window created with size: %d x %d\n", width, height); | 291 printf("Window created with size: %d x %d\n", width, height); |
280 float src_aspect = 4.0/3.0; | 292 float src_aspect = 4.0/3.0; |
281 float aspect = (float)width / height; | 293 float aspect = (float)width / height; |
282 tern_val def = {.ptrval = "normal"}; | 294 tern_val def = {.ptrval = "normal"}; |
283 int stretch = fabs(aspect - src_aspect) > 0.01 && !strcmp(tern_find_path_default(config, "video\0aspect\0", def).ptrval, "stretch"); | 295 int stretch = fabs(aspect - src_aspect) > 0.01 && !strcmp(tern_find_path_default(config, "video\0aspect\0", def).ptrval, "stretch"); |
284 | 296 |
285 #ifdef DISABLE_OPENGL | |
286 if (!stretch) { | 297 if (!stretch) { |
287 float scale_x = (float)width / 320.0; | 298 #ifndef DISABLE_OPENGL |
288 float scale_y = (float)height / 240.0; | 299 if (render_gl) { |
289 float scale = scale_x > scale_y ? scale_y : scale_x; | 300 for (int i = 0; i < 4; i++) |
290 main_clip.w = 320.0 * scale; | 301 { |
291 main_clip.h = 240.0 * scale; | 302 if (aspect > src_aspect) { |
292 main_clip.x = (width - main_clip.w) / 2; | 303 vertex_data[i*2] *= src_aspect/aspect; |
293 main_clip.y = (height - main_clip.h) / 2; | 304 } else { |
294 } | 305 vertex_data[i*2+1] *= aspect/src_aspect; |
295 #else | 306 } |
296 if (!stretch) { | 307 } |
297 for (int i = 0; i < 4; i++) | 308 } else { |
298 { | 309 #endif |
299 if (aspect > src_aspect) { | 310 float scale_x = (float)width / 320.0; |
300 vertex_data[i*2] *= src_aspect/aspect; | 311 float scale_y = (float)height / 240.0; |
301 } else { | 312 float scale = scale_x > scale_y ? scale_y : scale_x; |
302 vertex_data[i*2+1] *= aspect/src_aspect; | 313 main_clip.w = 320.0 * scale; |
303 } | 314 main_clip.h = 240.0 * scale; |
304 } | 315 main_clip.x = (width - main_clip.w) / 2; |
305 } | 316 main_clip.y = (height - main_clip.h) / 2; |
306 #endif | 317 #ifndef DISABLE_OPENGL |
318 } | |
319 #endif | |
320 } | |
321 | |
307 caption = title; | 322 caption = title; |
308 min_delay = 0; | 323 min_delay = 0; |
309 for (int i = 0; i < 100; i++) { | 324 for (int i = 0; i < 100; i++) { |
310 uint32_t start = SDL_GetTicks(); | 325 uint32_t start = SDL_GetTicks(); |
311 SDL_Delay(1); | 326 SDL_Delay(1); |
374 { | 389 { |
375 int width = context->regs[REG_MODE_4] & BIT_H40 ? 320.0f : 256.0f; | 390 int width = context->regs[REG_MODE_4] & BIT_H40 ? 320.0f : 256.0f; |
376 int height = 240; | 391 int height = 240; |
377 | 392 |
378 last_frame = SDL_GetTicks(); | 393 last_frame = SDL_GetTicks(); |
379 #ifdef DISABLE_OPENGL | 394 #ifndef DISABLE_OPENGL |
380 SDL_Rect area; | 395 if (render_gl) { |
381 | 396 glBindTexture(GL_TEXTURE_2D, textures[context->framebuf == context->oddbuf ? 0 : 1]); |
382 area.x = area.y = 0; | 397 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, 240, GL_BGRA, GL_UNSIGNED_BYTE, context->framebuf);; |
383 area.w = width; | 398 |
384 area.h = height; | 399 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
385 | 400 glClear(GL_COLOR_BUFFER_BIT); |
386 if (context->regs[REG_MODE_4] & BIT_INTERLACE) | 401 |
387 { | 402 glUseProgram(program); |
388 unsigned skip; | 403 glActiveTexture(GL_TEXTURE0); |
389 uint32_t *src = (uint32_t*)context->framebuf; | 404 glBindTexture(GL_TEXTURE_2D, textures[0]); |
390 uint8_t *dst; | 405 glUniform1i(un_textures[0], 0); |
391 int i; | 406 |
392 | 407 glActiveTexture(GL_TEXTURE1); |
393 area.h *= 2; | 408 glBindTexture(GL_TEXTURE_2D, (context->regs[REG_MODE_4] & BIT_INTERLACE) ? textures[1] : textures[2]); |
394 | 409 glUniform1i(un_textures[1], 1); |
395 SDL_LockTexture(main_texture, &area, (void**)&dst, &skip); | 410 |
396 | 411 glUniform1f(un_width, width); |
397 if (context->framebuf == context->evenbuf) | 412 |
398 dst += skip; | 413 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); |
399 | 414 glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); |
400 skip *= 2; | 415 glEnableVertexAttribArray(at_pos); |
401 | 416 |
402 for (i = 0; i < 240; ++i) | 417 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); |
403 { | 418 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0); |
404 memcpy(dst, src, width*sizeof(uint32_t)); | 419 |
405 src += 320; | 420 glDisableVertexAttribArray(at_pos); |
406 dst += skip; | 421 |
407 } | 422 SDL_GL_SwapWindow(main_window); |
408 | 423 } else { |
409 SDL_UnlockTexture(main_texture); | 424 #endif |
410 } | 425 SDL_Rect area; |
411 else /* possibly faster path for non-interlaced output */ | 426 |
412 SDL_UpdateTexture(main_texture, &area, context->framebuf, 320*sizeof(uint32_t)); | 427 area.x = area.y = 0; |
413 | 428 area.w = width; |
414 SDL_RenderClear(main_renderer); | 429 area.h = height; |
415 SDL_RenderCopy(main_renderer, main_texture, &area, &main_clip); | 430 |
416 SDL_RenderPresent(main_renderer); | 431 if (context->regs[REG_MODE_4] & BIT_INTERLACE) { |
417 #else | 432 unsigned skip; |
418 glBindTexture(GL_TEXTURE_2D, textures[context->framebuf == context->oddbuf ? 0 : 1]); | 433 uint32_t *src = (uint32_t*)context->framebuf; |
419 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, 240, GL_BGRA, GL_UNSIGNED_BYTE, context->framebuf);; | 434 uint8_t *dst; |
420 | 435 int i; |
421 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); | 436 |
422 glClear(GL_COLOR_BUFFER_BIT); | 437 area.h *= 2; |
423 | 438 |
424 glUseProgram(program); | 439 SDL_LockTexture(main_texture, &area, (void**)&dst, &skip); |
425 glActiveTexture(GL_TEXTURE0); | 440 |
426 glBindTexture(GL_TEXTURE_2D, textures[0]); | 441 if (context->framebuf == context->evenbuf) |
427 glUniform1i(un_textures[0], 0); | 442 dst += skip; |
428 | 443 |
429 glActiveTexture(GL_TEXTURE1); | 444 skip *= 2; |
430 glBindTexture(GL_TEXTURE_2D, (context->regs[REG_MODE_4] & BIT_INTERLACE) ? textures[1] : textures[2]); | 445 |
431 glUniform1i(un_textures[1], 1); | 446 for (i = 0; i < 240; ++i) { |
432 | 447 memcpy(dst, src, width*sizeof(uint32_t)); |
433 glUniform1f(un_width, width); | 448 src += 320; |
434 | 449 dst += skip; |
435 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); | 450 } |
436 glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); | 451 |
437 glEnableVertexAttribArray(at_pos); | 452 SDL_UnlockTexture(main_texture); |
438 | 453 } |
439 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); | 454 else /* possibly faster path for non-interlaced output */ |
440 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0); | 455 SDL_UpdateTexture(main_texture, &area, context->framebuf, 320*sizeof(uint32_t)); |
441 | 456 |
442 glDisableVertexAttribArray(at_pos); | 457 SDL_RenderClear(main_renderer); |
443 | 458 SDL_RenderCopy(main_renderer, main_texture, &area, &main_clip); |
444 SDL_GL_SwapWindow(main_window); | 459 SDL_RenderPresent(main_renderer); |
445 #endif | 460 #ifndef DISABLE_OPENGL |
446 if (context->regs[REG_MODE_4] & BIT_INTERLACE) | 461 } |
447 { | 462 #endif |
463 | |
464 if (context->regs[REG_MODE_4] & BIT_INTERLACE) { | |
448 context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; | 465 context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; |
449 } | 466 } |
450 } | 467 } |
451 | 468 |
452 int render_joystick_num_buttons(int joystick) | 469 int render_joystick_num_buttons(int joystick) |