comparison render_sdl.c @ 1184:b1147418254a

Overscan is now configurable
author Michael Pavone <pavone@retrodev.com>
date Wed, 18 Jan 2017 23:43:36 -0800
parents e758ddbf0624
children 6a4503fad67e
comparison
equal deleted inserted replaced
1183:8d8c71ebbbce 1184:b1147418254a
131 { 131 {
132 return 255 << 24 | r << 16 | g << 8 | b; 132 return 255 << 24 | r << 16 | g << 8 | b;
133 } 133 }
134 134
135 #ifndef DISABLE_OPENGL 135 #ifndef DISABLE_OPENGL
136 static GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, at_pos; 136 static GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, un_height, at_pos;
137 137
138 static GLfloat vertex_data[] = { 138 static GLfloat vertex_data[] = {
139 -1.0f, -1.0f, 139 -1.0f, -1.0f,
140 1.0f, -1.0f, 140 1.0f, -1.0f,
141 -1.0f, 1.0f, 141 -1.0f, 1.0f,
209 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 209 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
210 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 210 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
211 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 211 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
212 if (i < 2) { 212 if (i < 2) {
213 //TODO: Fixme for PAL + invalid display mode 213 //TODO: Fixme for PAL + invalid display mode
214 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, texture_buf); 214 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 512, 0, GL_BGRA, GL_UNSIGNED_BYTE, texture_buf);
215 } else { 215 } else {
216 uint32_t blank = 255 << 24; 216 uint32_t blank = 255 << 24;
217 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank); 217 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank);
218 } 218 }
219 } 219 }
237 exit(1); 237 exit(1);
238 } 238 }
239 un_textures[0] = glGetUniformLocation(program, "textures[0]"); 239 un_textures[0] = glGetUniformLocation(program, "textures[0]");
240 un_textures[1] = glGetUniformLocation(program, "textures[1]"); 240 un_textures[1] = glGetUniformLocation(program, "textures[1]");
241 un_width = glGetUniformLocation(program, "width"); 241 un_width = glGetUniformLocation(program, "width");
242 un_height = glGetUniformLocation(program, "height");
242 at_pos = glGetAttribLocation(program, "pos"); 243 at_pos = glGetAttribLocation(program, "pos");
243 } else { 244 } else {
244 #endif 245 #endif
245 246
246 //TODO: Fixme for PAL + invalid display mode 247 //TODO: Fixme for invalid display mode
247 sdl_textures[0] = sdl_textures[1] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 480); 248 sdl_textures[0] = sdl_textures[1] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 588);
248 #ifndef DISABLE_OPENGL 249 #ifndef DISABLE_OPENGL
249 } 250 }
250 #endif 251 #endif
251 } 252 }
252 253
262 SDL_DestroyTexture(sdl_textures[i]); 263 SDL_DestroyTexture(sdl_textures[i]);
263 } 264 }
264 } 265 }
265 } 266 }
266 267
268 static uint32_t overscan_top[NUM_VID_STD] = {2, 21};
269 static uint32_t overscan_bot[NUM_VID_STD] = {1, 17};
270 static vid_std video_standard = VID_NTSC;
271 static char *vid_std_names[NUM_VID_STD] = {"ntsc", "pal"};
267 void render_init(int width, int height, char * title, uint8_t fullscreen) 272 void render_init(int width, int height, char * title, uint8_t fullscreen)
268 { 273 {
269 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) { 274 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) {
270 fatal_error("Unable to init SDL: %s\n", SDL_GetError()); 275 fatal_error("Unable to init SDL: %s\n", SDL_GetError());
271 } 276 }
289 is_fullscreen = fullscreen; 294 is_fullscreen = fullscreen;
290 295
291 render_gl = 0; 296 render_gl = 0;
292 tern_val def = {.ptrval = "off"}; 297 tern_val def = {.ptrval = "off"};
293 char *vsync = tern_find_path_default(config, "video\0vsync\0", def).ptrval; 298 char *vsync = tern_find_path_default(config, "video\0vsync\0", def).ptrval;
299
300 tern_val video_node = {.ptrval = NULL};
301 tern_find(config, "video", &video_node);
302 tern_node *video = tern_get_node(video_node);
303 if (video)
304 {
305 for (int i = 0; i < NUM_VID_STD; i++)
306 {
307 video_node.ptrval = NULL;
308 tern_find(video, vid_std_names[i], &video_node);
309 tern_node *std_settings = tern_get_node(video_node);
310 if (std_settings) {
311 char *val = tern_find_path_default(std_settings, "overscan\0top\0", (tern_val){.ptrval = NULL}).ptrval;
312 if (val) {
313 overscan_top[i] = atoi(val);
314 }
315 val = tern_find_path_default(std_settings, "overscan\0bottom\0", (tern_val){.ptrval = NULL}).ptrval;
316 if (val) {
317 overscan_bot[i] = atoi(val);
318 }
319 }
320 }
321 }
294 322
295 #ifndef DISABLE_OPENGL 323 #ifndef DISABLE_OPENGL
296 flags |= SDL_WINDOW_OPENGL; 324 flags |= SDL_WINDOW_OPENGL;
297 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); 325 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
298 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); 326 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
416 SDL_JoystickEventState(SDL_ENABLE); 444 SDL_JoystickEventState(SDL_ENABLE);
417 445
418 atexit(render_quit); 446 atexit(render_quit);
419 } 447 }
420 448
449 void render_set_video_standard(vid_std std)
450 {
451 video_standard = std;
452 }
453
421 void render_update_caption(char *title) 454 void render_update_caption(char *title)
422 { 455 {
423 caption = title; 456 caption = title;
424 free(fps_caption); 457 free(fps_caption);
425 fps_caption = NULL; 458 fps_caption = NULL;
470 #endif 503 #endif
471 504
472 void render_framebuffer_updated(uint8_t which, int width) 505 void render_framebuffer_updated(uint8_t which, int width)
473 { 506 {
474 static uint8_t last; 507 static uint8_t last;
508 uint32_t height = which <= FRAMEBUFFER_EVEN
509 ? (video_standard == VID_NTSC ? 243 : 294) - (overscan_top[video_standard] + overscan_bot[video_standard])
510 : 240;
475 #ifndef DISABLE_OPENGL 511 #ifndef DISABLE_OPENGL
476 if (render_gl && which <= FRAMEBUFFER_EVEN) { 512 if (render_gl && which <= FRAMEBUFFER_EVEN) {
477 glBindTexture(GL_TEXTURE_2D, textures[which]); 513 glBindTexture(GL_TEXTURE_2D, textures[which]);
478 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, 240, GL_BGRA, GL_UNSIGNED_BYTE, texture_buf); 514 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, height, GL_BGRA, GL_UNSIGNED_BYTE, texture_buf + 320 * overscan_top[video_standard]);
479 515
480 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 516 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
481 glClear(GL_COLOR_BUFFER_BIT); 517 glClear(GL_COLOR_BUFFER_BIT);
482 518
483 glUseProgram(program); 519 glUseProgram(program);
488 glActiveTexture(GL_TEXTURE1); 524 glActiveTexture(GL_TEXTURE1);
489 glBindTexture(GL_TEXTURE_2D, textures[last != which ? 1 : scanlines ? 2 : 0]); 525 glBindTexture(GL_TEXTURE_2D, textures[last != which ? 1 : scanlines ? 2 : 0]);
490 glUniform1i(un_textures[1], 1); 526 glUniform1i(un_textures[1], 1);
491 527
492 glUniform1f(un_width, width); 528 glUniform1f(un_width, width);
529 glUniform1f(un_height, height);
493 530
494 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); 531 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
495 glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); 532 glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0);
496 glEnableVertexAttribArray(at_pos); 533 glEnableVertexAttribArray(at_pos);
497 534
501 glDisableVertexAttribArray(at_pos); 538 glDisableVertexAttribArray(at_pos);
502 539
503 SDL_GL_SwapWindow(main_window); 540 SDL_GL_SwapWindow(main_window);
504 } else { 541 } else {
505 #endif 542 #endif
506 uint32_t height = 240;
507 if (which <= FRAMEBUFFER_EVEN && last != which) { 543 if (which <= FRAMEBUFFER_EVEN && last != which) {
508 uint8_t *cur_dst = (uint8_t *)locked_pixels; 544 uint8_t *cur_dst = (uint8_t *)locked_pixels;
509 uint8_t *cur_saved = (uint8_t *)texture_buf; 545 uint8_t *cur_saved = (uint8_t *)texture_buf;
510 uint32_t dst_off = which == FRAMEBUFFER_EVEN ? 0 : locked_pitch; 546 uint32_t dst_off = which == FRAMEBUFFER_EVEN ? 0 : locked_pitch;
511 uint32_t src_off = which == FRAMEBUFFER_EVEN ? locked_pitch : 0; 547 uint32_t src_off = which == FRAMEBUFFER_EVEN ? locked_pitch : 0;
512 for (int i = 0; i < 240; ++i) 548 for (int i = 0; i < height; ++i)
513 { 549 {
514 //copy saved line from other field 550 //copy saved line from other field
515 memcpy(cur_dst + dst_off, cur_saved, locked_pitch); 551 memcpy(cur_dst + dst_off, cur_saved, locked_pitch);
516 //save line from this field to buffer for next frame 552 //save line from this field to buffer for next frame
517 memcpy(cur_saved, cur_dst + src_off, locked_pitch); 553 memcpy(cur_saved, cur_dst + src_off, locked_pitch);
521 height = 480; 557 height = 480;
522 } 558 }
523 SDL_UnlockTexture(sdl_textures[which]); 559 SDL_UnlockTexture(sdl_textures[which]);
524 SDL_Rect src_clip = { 560 SDL_Rect src_clip = {
525 .x = 0, 561 .x = 0,
526 .y = 0, 562 .y = overscan_top[video_standard],
527 .w = width, 563 .w = width,
528 .h = height 564 .h = height
529 }; 565 };
530 SDL_RenderCopy(main_renderer, sdl_textures[which], &src_clip, &main_clip); 566 SDL_RenderCopy(main_renderer, sdl_textures[which], &src_clip, &main_clip);
531 SDL_RenderPresent(main_renderer); 567 SDL_RenderPresent(main_renderer);