comparison render_sdl.c @ 2484:ccee8dccd9cc

Add support for rendering debug windows with OpenGL in perparation for allowing Nuklear UI in them
author Michael Pavone <pavone@retrodev.com>
date Sun, 14 Apr 2024 11:40:32 -0700
parents 09c9d2c6bac0
children a0837ea61fda
comparison
equal deleted inserted replaced
2483:48ab1e3e5df5 2484:ccee8dccd9cc
27 #endif 27 #endif
28 #endif 28 #endif
29 29
30 #define MAX_EVENT_POLL_PER_FRAME 2 30 #define MAX_EVENT_POLL_PER_FRAME 2
31 31
32
33 typedef struct {
34 SDL_Window *win;
35 SDL_Renderer *renderer;
36 SDL_Texture *sdl_texture;
37 window_close_handler on_close;
38 uint32_t width;
39 uint32_t height;
40 #ifndef DISABLE_OPENGL
41 SDL_GLContext *gl_context;
42 uint32_t *texture_buf;
43 uint32_t tex_width;
44 uint32_t tex_height;
45 GLuint gl_texture;
46 GLuint vshader;
47 GLuint fshader;
48 GLuint program;
49 GLuint gl_buffers[2];
50 GLint un_texture;
51 GLint un_width;
52 GLint un_height;
53 GLint at_pos;
54 #endif
55 } extra_window;
56
32 static SDL_Window *main_window; 57 static SDL_Window *main_window;
33 static SDL_Window **extra_windows; 58 static extra_window *extras;
34 static SDL_Renderer *main_renderer; 59 static SDL_Renderer *main_renderer;
35 static SDL_Renderer **extra_renderers; 60 static SDL_Texture *sdl_textures[FRAMEBUFFER_UI + 1];
36 static SDL_Texture **sdl_textures;
37 static window_close_handler *close_handlers; 61 static window_close_handler *close_handlers;
38 static uint8_t num_textures; 62 static uint8_t num_extras;
39 static SDL_Rect main_clip; 63 static SDL_Rect main_clip;
40 static SDL_GLContext *main_context; 64 static SDL_GLContext *main_context;
41 65
42 static int main_width, main_height, windowed_width, windowed_height; 66 static int main_width, main_height, windowed_width, windowed_height;
43 67
478 static void render_alloc_surfaces() 502 static void render_alloc_surfaces()
479 { 503 {
480 if (texture_init) { 504 if (texture_init) {
481 return; 505 return;
482 } 506 }
483 if (!sdl_textures) {
484 sdl_textures= calloc(sizeof(SDL_Texture *), 3);
485 num_textures = 3;
486 }
487 texture_init = 1; 507 texture_init = 1;
488 #ifndef DISABLE_OPENGL 508 #ifndef DISABLE_OPENGL
489 if (render_gl) { 509 if (render_gl) {
490 gl_setup(); 510 gl_setup();
491 } else { 511 } else {
500 #endif 520 #endif
501 } 521 }
502 522
503 static void free_surfaces(void) 523 static void free_surfaces(void)
504 { 524 {
505 for (int i = 0; i < num_textures; i++) 525 for (int i = 0; i <= FRAMEBUFFER_UI; i++)
506 { 526 {
507 if (sdl_textures[i]) { 527 if (sdl_textures[i]) {
508 SDL_DestroyTexture(sdl_textures[i]); 528 SDL_DestroyTexture(sdl_textures[i]);
509 } 529 }
510 } 530 }
511 free(sdl_textures);
512 sdl_textures = NULL;
513 texture_init = 0; 531 texture_init = 0;
514 } 532 }
515 533
516 static char * caption = NULL; 534 static char * caption = NULL;
517 static char * fps_caption = NULL; 535 static char * fps_caption = NULL;
941 break; 959 break;
942 case SDL_WINDOWEVENT_CLOSE: 960 case SDL_WINDOWEVENT_CLOSE:
943 if (main_window && SDL_GetWindowID(main_window) == event->window.windowID) { 961 if (main_window && SDL_GetWindowID(main_window) == event->window.windowID) {
944 exit(0); 962 exit(0);
945 } else { 963 } else {
946 for (int i = 0; i < num_textures - FRAMEBUFFER_USER_START; i++) 964 for (int i = 0; i < num_extras; i++)
947 { 965 {
948 if (SDL_GetWindowID(extra_windows[i]) == event->window.windowID) { 966 if (SDL_GetWindowID(extras[i].win) == event->window.windowID) {
949 if (close_handlers[i]) { 967 if (extras[i].on_close) {
950 close_handlers[i](i + FRAMEBUFFER_USER_START); 968 extras[i].on_close(i + FRAMEBUFFER_USER_START);
951 } 969 }
952 break; 970 break;
953 } 971 }
954 } 972 }
955 } 973 }
1291 } 1309 }
1292 static int in_toggle; 1310 static int in_toggle;
1293 1311
1294 void render_config_updated(void) 1312 void render_config_updated(void)
1295 { 1313 {
1296 int n = num_textures < FRAMEBUFFER_USER_START ? num_textures : FRAMEBUFFER_USER_START; 1314 for (int i = 0; i <= FRAMEBUFFER_UI; i++)
1297 for (int i = 0; i < n; i++)
1298 { 1315 {
1299 if (sdl_textures[i]) { 1316 if (sdl_textures[i]) {
1300 SDL_DestroyTexture(sdl_textures[i]); 1317 SDL_DestroyTexture(sdl_textures[i]);
1301 sdl_textures[i] = NULL; 1318 sdl_textures[i] = NULL;
1302 } 1319 }
1471 } 1488 }
1472 #endif 1489 #endif
1473 free(path); 1490 free(path);
1474 } 1491 }
1475 1492
1493 void GLAPIENTRY gl_message_callback(GLenum source, GLenum type, GLenum id, GLenum severity, GLsizei length, const GLchar *message, const void *user)
1494 {
1495 fprintf(stderr, "GL Message: %d, %d, %d - %s\n", source, type, severity, message);
1496 }
1497
1476 uint8_t render_create_window(char *caption, uint32_t width, uint32_t height, window_close_handler close_handler) 1498 uint8_t render_create_window(char *caption, uint32_t width, uint32_t height, window_close_handler close_handler)
1477 { 1499 {
1478 uint8_t win_idx = 0xFF; 1500 uint8_t win_idx = 0xFF;
1479 for (int i = 0; i < num_textures - FRAMEBUFFER_USER_START; i++) 1501 for (int i = 0; i < num_extras; i++)
1480 { 1502 {
1481 if (!extra_windows[i]) { 1503 if (!extras[i].win) {
1482 win_idx = i; 1504 win_idx = i;
1483 break; 1505 break;
1484 } 1506 }
1485 } 1507 }
1486 1508
1487 if (win_idx == 0xFF) { 1509 if (win_idx == 0xFF) {
1488 num_textures++; 1510 num_extras++;
1489 sdl_textures = realloc(sdl_textures, num_textures * sizeof(*sdl_textures)); 1511 extras = realloc(extras, num_extras * sizeof(*extras));
1490 extra_windows = realloc(extra_windows, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*extra_windows)); 1512 win_idx = num_extras - 1;
1491 extra_renderers = realloc(extra_renderers, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*extra_renderers)); 1513 }
1492 close_handlers = realloc(close_handlers, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*close_handlers)); 1514 memset(&extras[win_idx], 0, sizeof(extra_window));
1493 win_idx = num_textures - FRAMEBUFFER_USER_START - 1; 1515 uint32_t flags = 0;
1494 } 1516 #ifndef DISABLE_OPENGL
1517 if (render_gl) {
1518 flags |= SDL_WINDOW_OPENGL;
1519 }
1520 #endif
1495 int x = SDL_WINDOWPOS_UNDEFINED; 1521 int x = SDL_WINDOWPOS_UNDEFINED;
1496 int y = SDL_WINDOWPOS_UNDEFINED; 1522 int y = SDL_WINDOWPOS_UNDEFINED;
1497 SDL_GetWindowPosition(main_window, &x, &y); 1523 SDL_GetWindowPosition(main_window, &x, &y);
1498 if (x != SDL_WINDOWPOS_UNDEFINED) { 1524 if (x != SDL_WINDOWPOS_UNDEFINED) {
1499 x += main_width; 1525 x += main_width;
1500 } 1526 }
1501 extra_windows[win_idx] = SDL_CreateWindow(caption, x, y, width, height, 0); 1527 extras[win_idx].win = SDL_CreateWindow(caption, x, y, width, height, flags);
1502 if (!extra_windows[win_idx]) { 1528 if (!extras[win_idx].win) {
1503 goto fail_window; 1529 goto fail_window;
1504 } 1530 }
1505 extra_renderers[win_idx] = SDL_CreateRenderer(extra_windows[win_idx], -1, SDL_RENDERER_ACCELERATED); 1531 extras[win_idx].width = width;
1506 if (!extra_renderers[win_idx]) { 1532 extras[win_idx].height = height;
1507 goto fail_renderer; 1533 #ifndef DISABLE_OPENGL
1508 } 1534 if (render_gl) {
1509 uint8_t texture_idx = win_idx + FRAMEBUFFER_USER_START; 1535 extras[win_idx].gl_context = SDL_GL_CreateContext(extras[win_idx].win);
1510 sdl_textures[texture_idx] = SDL_CreateTexture(extra_renderers[win_idx], SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height); 1536 SDL_GL_MakeCurrent(extras[win_idx].win, extras[win_idx].gl_context);
1511 if (!sdl_textures[texture_idx]) { 1537 glEnable(GL_DEBUG_OUTPUT);
1512 goto fail_texture; 1538 glDebugMessageCallback(gl_message_callback, NULL);
1513 } 1539 glGenTextures(1, &extras[win_idx].gl_texture);
1514 close_handlers[win_idx] = close_handler; 1540 glBindTexture(GL_TEXTURE_2D, extras[win_idx].gl_texture);
1515 return texture_idx; 1541 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1542 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1543 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1544 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1545 extras[win_idx].tex_width = width;
1546 extras[win_idx].tex_height = height;
1547 char *npot_textures = tern_find_path_default(config, "video\0npot_textures\0", (tern_val){.ptrval = "off"}, TVAL_PTR).ptrval;
1548 if (strcmp(npot_textures, "on")) {
1549 extras[win_idx].tex_width = nearest_pow2(width);
1550 extras[win_idx].tex_height = nearest_pow2(height);
1551 }
1552 extras[win_idx].texture_buf = calloc(extras[win_idx].tex_width * extras[win_idx].tex_height, sizeof(uint32_t));
1553 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, extras[win_idx].tex_width, extras[win_idx].tex_height, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, extras[win_idx].texture_buf);
1554 glGenBuffers(2, extras[win_idx].gl_buffers);
1555 glBindBuffer(GL_ARRAY_BUFFER, extras[win_idx].gl_buffers[0]);
1556 glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data_default), vertex_data_default, GL_STATIC_DRAW);
1557 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, extras[win_idx].gl_buffers[1]);
1558 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW);
1559 extras[win_idx].vshader = load_shader("extra_window.v.glsl", GL_VERTEX_SHADER);
1560 extras[win_idx].fshader = load_shader("extra_window.f.glsl", GL_FRAGMENT_SHADER);
1561 extras[win_idx].program = glCreateProgram();
1562 glAttachShader(program, extras[win_idx].vshader);
1563 glAttachShader(program, extras[win_idx].fshader);
1564 glLinkProgram(extras[win_idx].program);
1565 GLint link_status;
1566 glGetProgramiv(program, GL_LINK_STATUS, &link_status);
1567 if (!link_status) {
1568 fputs("Failed to link shader program\n", stderr);
1569 //TODO: cleanup
1570 goto sdl_renderer;
1571 }
1572 extras[win_idx].un_texture = glGetUniformLocation(program, "texture");
1573 extras[win_idx].un_width = glGetUniformLocation(program, "width");
1574 extras[win_idx].un_height = glGetUniformLocation(program, "height");
1575 extras[win_idx].at_pos = glGetAttribLocation(program, "pos");
1576 } else {
1577 sdl_renderer:
1578 #endif
1579 extras[win_idx].renderer = SDL_CreateRenderer(extras[win_idx].win, -1, SDL_RENDERER_ACCELERATED);
1580 if (!extras[win_idx].renderer) {
1581 goto fail_renderer;
1582 }
1583 extras[win_idx].sdl_texture = SDL_CreateTexture(extras[win_idx].renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height);
1584 if (!extras[win_idx].sdl_texture) {
1585 goto fail_texture;
1586 }
1587 #ifndef DISABLE_OPENGL
1588 }
1589 #endif
1590 extras[win_idx].on_close = close_handler;
1591 return win_idx + FRAMEBUFFER_USER_START;
1516 1592
1517 fail_texture: 1593 fail_texture:
1518 SDL_DestroyRenderer(extra_renderers[win_idx]); 1594 SDL_DestroyRenderer(extras[win_idx].renderer);
1519 fail_renderer: 1595 fail_renderer:
1520 SDL_DestroyWindow(extra_windows[win_idx]); 1596 SDL_DestroyWindow(extras[win_idx].win);
1521 fail_window: 1597 fail_window:
1522 num_textures--;
1523 return 0; 1598 return 0;
1524 } 1599 }
1525 1600
1526 void render_destroy_window(uint8_t which) 1601 void render_destroy_window(uint8_t which)
1527 { 1602 {
1528 uint8_t win_idx = which - FRAMEBUFFER_USER_START; 1603 uint8_t win_idx = which - FRAMEBUFFER_USER_START;
1529 //Destroying the renderers also frees the textures 1604 if (extras[win_idx].renderer) {
1530 SDL_DestroyRenderer(extra_renderers[win_idx]); 1605 //Destroying the renderers also frees the textures
1531 SDL_DestroyWindow(extra_windows[win_idx]); 1606 SDL_DestroyRenderer(extras[win_idx].renderer);
1532 1607 extras[win_idx].renderer = NULL;
1533 extra_renderers[win_idx] = NULL; 1608 }
1534 extra_windows[win_idx] = NULL; 1609 #ifndef DISABLE_OPENGL
1610 else {
1611 SDL_GL_MakeCurrent(extras[win_idx].win, extras[win_idx].gl_context);
1612 glDeleteProgram(extras[win_idx].program);
1613 glDeleteShader(extras[win_idx].vshader);
1614 glDeleteShader(extras[win_idx].fshader);
1615 glDeleteBuffers(2, extras[win_idx].gl_buffers);
1616 glDeleteTextures(1, &extras[win_idx].gl_texture);
1617 SDL_GL_DeleteContext(extras[win_idx].gl_context);
1618 }
1619 #endif
1620 SDL_DestroyWindow(extras[win_idx].win);
1621
1622 extras[win_idx].win = NULL;
1535 } 1623 }
1536 1624
1537 SDL_Texture **static_images; 1625 SDL_Texture **static_images;
1538 uint8_t num_static; 1626 uint8_t num_static;
1539 uint8_t render_static_image(uint8_t window, uint8_t *buffer, uint32_t size) 1627 uint8_t render_static_image(uint8_t window, uint8_t *buffer, uint32_t size)
1540 { 1628 {
1541 1629 window -= FRAMEBUFFER_USER_START;
1542 uint32_t width, height; 1630 uint32_t width, height;
1543 uint32_t *pixels = load_png(buffer, size, &width, &height); 1631 uint32_t *pixels = load_png(buffer, size, &width, &height);
1544 if (!pixels) { 1632 if (!pixels) {
1545 return 0xFF; 1633 return 0xFF;
1546 } 1634 }
1557 } 1645 }
1558 if (img_index == num_static) { 1646 if (img_index == num_static) {
1559 num_static *= 2; 1647 num_static *= 2;
1560 static_images = realloc(static_images, num_static * sizeof(SDL_Texture*)); 1648 static_images = realloc(static_images, num_static * sizeof(SDL_Texture*));
1561 } 1649 }
1562 static_images[img_index] = SDL_CreateTexture(extra_renderers[window - FRAMEBUFFER_USER_START], SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, width, height); 1650 static_images[img_index] = SDL_CreateTexture(extras[window].renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, width, height);
1563 SDL_UpdateTexture(static_images[img_index], NULL, pixels, sizeof(uint32_t) * width); 1651 SDL_UpdateTexture(static_images[img_index], NULL, pixels, sizeof(uint32_t) * width);
1564 free(pixels); 1652 free(pixels);
1565 return img_index; 1653 return img_index;
1566 } 1654 }
1567 1655
1568 void render_draw_image(uint8_t window, uint8_t image, int x, int y, int width, int height) 1656 void render_draw_image(uint8_t window, uint8_t image, int x, int y, int width, int height)
1569 { 1657 {
1570 SDL_Rect dst = { 1658 uint8_t win_idx = window - FRAMEBUFFER_USER_START;
1571 .x = x, 1659 if (extras[win_idx].renderer) {
1572 .y = y, 1660 SDL_Rect dst = {
1573 .w = width, 1661 .x = x,
1574 .h = height 1662 .y = y,
1575 }; 1663 .w = width,
1576 SDL_RenderCopy(extra_renderers[window - FRAMEBUFFER_USER_START], static_images[image], NULL, &dst); 1664 .h = height
1665 };
1666 SDL_RenderCopy(extras[win_idx].renderer, static_images[image], NULL, &dst);
1667 }
1668 #ifndef DISABLE_OPENGL
1669 else {
1670 //TODO: implement me
1671 }
1672 #endif
1577 } 1673 }
1578 1674
1579 void render_clear_window(uint8_t window, uint8_t r, uint8_t g, uint8_t b) 1675 void render_clear_window(uint8_t window, uint8_t r, uint8_t g, uint8_t b)
1580 { 1676 {
1581 SDL_SetRenderDrawColor(extra_renderers[window - FRAMEBUFFER_USER_START], r, g, b, 255); 1677 uint8_t win_idx = window - FRAMEBUFFER_USER_START;
1582 SDL_RenderClear(extra_renderers[window - FRAMEBUFFER_USER_START]); 1678 if (extras[win_idx].renderer) {
1679 SDL_SetRenderDrawColor(extras[win_idx].renderer, r, g, b, 255);
1680 SDL_RenderClear(extras[win_idx].renderer);
1681 }
1682 #ifndef DISABLE_OPENGL
1683 else {
1684 SDL_GL_MakeCurrent(extras[win_idx].win, extras[win_idx].gl_context);
1685 glClearColor(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f);
1686 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1687 }
1688 #endif
1583 } 1689 }
1584 1690
1585 void render_fill_rect(uint8_t window, uint8_t r, uint8_t g, uint8_t b, int x, int y, int width, int height) 1691 void render_fill_rect(uint8_t window, uint8_t r, uint8_t g, uint8_t b, int x, int y, int width, int height)
1586 { 1692 {
1587 SDL_SetRenderDrawColor(extra_renderers[window - FRAMEBUFFER_USER_START], r, g, b, 255); 1693 uint8_t win_idx = window - FRAMEBUFFER_USER_START;
1588 SDL_Rect dst = { 1694 if (extras[win_idx].renderer) {
1589 .x = x, 1695 SDL_SetRenderDrawColor(extras[win_idx].renderer, r, g, b, 255);
1590 .y = y, 1696 SDL_Rect dst = {
1591 .w = width, 1697 .x = x,
1592 .h = height 1698 .y = y,
1593 }; 1699 .w = width,
1594 SDL_RenderFillRect(extra_renderers[window - FRAMEBUFFER_USER_START], &dst); 1700 .h = height
1701 };
1702 SDL_RenderFillRect(extras[win_idx].renderer, &dst);
1703 }
1704 #ifndef DISABLE_OPENGL
1705 else {
1706 //TODO: implement me
1707 }
1708 #endif
1595 } 1709 }
1596 1710
1597 void render_window_refresh(uint8_t window) 1711 void render_window_refresh(uint8_t window)
1598 { 1712 {
1599 SDL_RenderPresent(extra_renderers[window - FRAMEBUFFER_USER_START]); 1713 uint8_t win_idx = window - FRAMEBUFFER_USER_START;
1714 if (extras[win_idx].renderer) {
1715 SDL_RenderPresent(extras[win_idx].renderer);
1716 }
1717 #ifndef DISABLE_OPENGL
1718 else {
1719 SDL_GL_SwapWindow(extras[win_idx].win);
1720 }
1721 #endif
1600 } 1722 }
1601 1723
1602 uint32_t *locked_pixels; 1724 uint32_t *locked_pixels;
1603 uint32_t locked_pitch; 1725 uint32_t locked_pitch;
1604 uint32_t *render_get_framebuffer(uint8_t which, int *pitch) 1726 uint32_t *render_get_framebuffer(uint8_t which, int *pitch)
1618 } 1740 }
1619 #ifndef DISABLE_OPENGL 1741 #ifndef DISABLE_OPENGL
1620 if (render_gl && which <= FRAMEBUFFER_EVEN) { 1742 if (render_gl && which <= FRAMEBUFFER_EVEN) {
1621 *pitch = LINEBUF_SIZE * sizeof(uint32_t); 1743 *pitch = LINEBUF_SIZE * sizeof(uint32_t);
1622 return texture_buf; 1744 return texture_buf;
1745 } else if (render_gl && which >= FRAMEBUFFER_USER_START) {
1746 uint8_t win_idx = which - FRAMEBUFFER_USER_START;
1747 *pitch = extras[win_idx].width * sizeof(uint32_t);
1748 return extras[win_idx].texture_buf;
1623 } else { 1749 } else {
1624 #endif 1750 #endif
1625 if (which == FRAMEBUFFER_UI && !sdl_textures[which]) { 1751 if (which == FRAMEBUFFER_UI && !sdl_textures[which]) {
1626 sdl_textures[which] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, main_width, main_height); 1752 sdl_textures[which] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, main_width, main_height);
1627 } 1753 }
1628 if (which >= num_textures) { 1754 SDL_Texture *tex;
1629 warning("Request for invalid framebuffer number %d\n", which); 1755 if (which >= FRAMEBUFFER_USER_START) {
1630 return NULL; 1756 uint8_t win_idx = which - FRAMEBUFFER_USER_START;
1757 if (win_idx >= num_extras || !extras[win_idx].renderer) {
1758 warning("Request for invalid framebuffer number %d\n", which);
1759 return NULL;
1760 }
1761 tex = extras[win_idx].sdl_texture;
1762 } else {
1763 tex = sdl_textures[which];
1631 } 1764 }
1632 uint8_t *pixels; 1765 uint8_t *pixels;
1633 if (SDL_LockTexture(sdl_textures[which], NULL, (void **)&pixels, pitch) < 0) { 1766 if (SDL_LockTexture(tex, NULL, (void **)&pixels, pitch) < 0) {
1634 warning("Failed to lock texture: %s\n", SDL_GetError()); 1767 warning("Failed to lock texture: %s\n", SDL_GetError());
1635 return NULL; 1768 return NULL;
1636 } 1769 }
1637 static uint8_t last; 1770 static uint8_t last;
1638 if (which <= FRAMEBUFFER_EVEN) { 1771 if (which <= FRAMEBUFFER_EVEN) {
1682 source_frame_count = frame_repeat[source_frame]; 1815 source_frame_count = frame_repeat[source_frame];
1683 //TODO: Figure out what to do about SDL Render API texture locking 1816 //TODO: Figure out what to do about SDL Render API texture locking
1684 return; 1817 return;
1685 } 1818 }
1686 1819
1687 last_width = width;
1688 uint32_t height = which <= FRAMEBUFFER_EVEN 1820 uint32_t height = which <= FRAMEBUFFER_EVEN
1689 ? (video_standard == VID_PAL ? 294 : 243) - (overscan_top[video_standard] + overscan_bot[video_standard]) 1821 ? (video_standard == VID_PAL ? 294 : 243) - (overscan_top[video_standard] + overscan_bot[video_standard])
1690 : 240; 1822 : 240;
1691 FILE *screenshot_file = NULL; 1823 FILE *screenshot_file = NULL;
1692 char *ext; 1824 char *ext;
1693 width -= overscan_left[video_standard] + overscan_right[video_standard]; 1825 if (which < FRAMEBUFFER_UI) {
1694 if (screenshot_path && which == FRAMEBUFFER_ODD) { 1826 last_width = width;
1695 screenshot_file = fopen(screenshot_path, "wb"); 1827 width -= overscan_left[video_standard] + overscan_right[video_standard];
1696 if (screenshot_file) { 1828 if (screenshot_path && which == FRAMEBUFFER_ODD) {
1829 screenshot_file = fopen(screenshot_path, "wb");
1830 if (screenshot_file) {
1697 #ifndef DISABLE_ZLIB 1831 #ifndef DISABLE_ZLIB
1698 ext = path_extension(screenshot_path); 1832 ext = path_extension(screenshot_path);
1699 #endif 1833 #endif
1700 debug_message("Saving screenshot to %s\n", screenshot_path); 1834 debug_message("Saving screenshot to %s\n", screenshot_path);
1701 } else { 1835 } else {
1702 warning("Failed to open screenshot file %s for writing\n", screenshot_path); 1836 warning("Failed to open screenshot file %s for writing\n", screenshot_path);
1703 } 1837 }
1704 free(screenshot_path); 1838 free(screenshot_path);
1705 screenshot_path = NULL; 1839 screenshot_path = NULL;
1706 } 1840 }
1707 interlaced = last_field != which; 1841 interlaced = last_field != which;
1708 buffer += overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard]; 1842 buffer += overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard];
1843 }
1709 #ifndef DISABLE_OPENGL 1844 #ifndef DISABLE_OPENGL
1710 if (render_gl && which <= FRAMEBUFFER_EVEN) { 1845 if (render_gl && which <= FRAMEBUFFER_EVEN) {
1711 SDL_GL_MakeCurrent(main_window, main_context); 1846 SDL_GL_MakeCurrent(main_window, main_context);
1712 glBindTexture(GL_TEXTURE_2D, textures[which]); 1847 glBindTexture(GL_TEXTURE_2D, textures[which]);
1713 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, LINEBUF_SIZE, height, SRC_FORMAT, GL_UNSIGNED_BYTE, buffer); 1848 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, LINEBUF_SIZE, height, SRC_FORMAT, GL_UNSIGNED_BYTE, buffer);
1733 apng = start_apng(apng_file, width, height, video_standard == VID_PAL ? 50.0 : 60.0); 1868 apng = start_apng(apng_file, width, height, video_standard == VID_PAL ? 50.0 : 60.0);
1734 } 1869 }
1735 save_png24_frame(apng_file, buffer, apng, width, height, LINEBUF_SIZE*sizeof(uint32_t)); 1870 save_png24_frame(apng_file, buffer, apng, width, height, LINEBUF_SIZE*sizeof(uint32_t));
1736 } 1871 }
1737 #endif 1872 #endif
1873 } else if (render_gl && which >= FRAMEBUFFER_USER_START) {
1874 uint8_t win_idx = which - FRAMEBUFFER_USER_START;
1875 SDL_GL_MakeCurrent(extras[win_idx].win, extras[win_idx].gl_context);
1876 glBindTexture(GL_TEXTURE_2D, extras[win_idx].gl_texture);
1877 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, extras[win_idx].width, extras[win_idx].height, SRC_FORMAT, GL_UNSIGNED_BYTE, buffer);
1738 } else { 1878 } else {
1739 #endif 1879 #endif
1740 uint32_t shot_height = height; 1880 uint32_t shot_height = height;
1741 //TODO: Support SYNC_AUDIO_THREAD/SYNC_EXTERNAL for render API framebuffers 1881 //TODO: Support SYNC_AUDIO_THREAD/SYNC_EXTERNAL for render API framebuffers
1742 if (which <= FRAMEBUFFER_EVEN && last_field != which) { 1882 if (which <= FRAMEBUFFER_EVEN && last_field != which) {
1776 } 1916 }
1777 SDL_UnlockTexture(sdl_textures[which]); 1917 SDL_UnlockTexture(sdl_textures[which]);
1778 #ifndef DISABLE_OPENGL 1918 #ifndef DISABLE_OPENGL
1779 } 1919 }
1780 #endif 1920 #endif
1781 last_height = height;
1782 if (which <= FRAMEBUFFER_EVEN) { 1921 if (which <= FRAMEBUFFER_EVEN) {
1922 last_height = height;
1783 render_update_display(); 1923 render_update_display();
1784 } else if (which == FRAMEBUFFER_UI) { 1924 } else if (which == FRAMEBUFFER_UI) {
1785 SDL_RenderCopy(main_renderer, sdl_textures[which], NULL, NULL); 1925 SDL_RenderCopy(main_renderer, sdl_textures[which], NULL, NULL);
1786 if (need_ui_fb_resize) { 1926 if (need_ui_fb_resize) {
1787 SDL_DestroyTexture(sdl_textures[which]); 1927 SDL_DestroyTexture(sdl_textures[which]);
1790 on_ui_fb_resized(); 1930 on_ui_fb_resized();
1791 } 1931 }
1792 need_ui_fb_resize = 0; 1932 need_ui_fb_resize = 0;
1793 } 1933 }
1794 } else { 1934 } else {
1795 SDL_RenderCopy(extra_renderers[which - FRAMEBUFFER_USER_START], sdl_textures[which], NULL, NULL); 1935 uint8_t win_idx = which - FRAMEBUFFER_USER_START;
1796 SDL_RenderPresent(extra_renderers[which - FRAMEBUFFER_USER_START]); 1936 if (extras[win_idx].renderer) {
1937 SDL_RenderCopy(extras[win_idx].renderer, extras[win_idx].sdl_texture, NULL, NULL);
1938 SDL_RenderPresent(extras[win_idx].renderer);
1939 }
1940 #ifndef DISABLE_OPENGL
1941 else {
1942 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
1943 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1944
1945 glUseProgram(extras[win_idx].program);
1946 glActiveTexture(GL_TEXTURE0);
1947 glBindTexture(GL_TEXTURE_2D, extras[win_idx].gl_texture);
1948 glUniform1i(extras[win_idx].un_texture, 0);
1949
1950 glUniform1f(extras[win_idx].un_width, (float)extras[win_idx].width / (float)extras[win_idx].tex_width);
1951 glUniform1f(extras[win_idx].un_height, (float)extras[win_idx].height / (float)extras[win_idx].tex_height);
1952
1953 glBindBuffer(GL_ARRAY_BUFFER, extras[win_idx].gl_buffers[0]);
1954 glVertexAttribPointer(extras[win_idx].at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0);
1955 glEnableVertexAttribArray(extras[win_idx].at_pos);
1956
1957 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, extras[win_idx].gl_buffers[1]);
1958 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0);
1959
1960 SDL_GL_SwapWindow(extras[win_idx].win);
1961 }
1962 #endif
1797 } 1963 }
1798 if (screenshot_file) { 1964 if (screenshot_file) {
1799 fclose(screenshot_file); 1965 fclose(screenshot_file);
1800 } 1966 }
1801 if (which <= FRAMEBUFFER_EVEN) { 1967 if (which <= FRAMEBUFFER_EVEN) {
1918 SDL_CondSignal(frame_ready); 2084 SDL_CondSignal(frame_ready);
1919 SDL_UnlockMutex(frame_mutex); 2085 SDL_UnlockMutex(frame_mutex);
1920 return; 2086 return;
1921 } 2087 }
1922 //TODO: Maybe fixme for render API 2088 //TODO: Maybe fixme for render API
1923 process_framebuffer(texture_buf, which, width); 2089 process_framebuffer(which < FRAMEBUFFER_USER_START ? texture_buf : extras[which - FRAMEBUFFER_USER_START].texture_buf, which, width);
1924 } 2090 }
1925 2091
1926 void render_video_loop(void) 2092 void render_video_loop(void)
1927 { 2093 {
1928 if (sync_src != SYNC_AUDIO_THREAD && sync_src != SYNC_EXTERNAL) { 2094 if (sync_src != SYNC_AUDIO_THREAD && sync_src != SYNC_EXTERNAL) {
2261 uint8_t render_get_active_framebuffer(void) 2427 uint8_t render_get_active_framebuffer(void)
2262 { 2428 {
2263 if (SDL_GetWindowFlags(main_window) & SDL_WINDOW_INPUT_FOCUS) { 2429 if (SDL_GetWindowFlags(main_window) & SDL_WINDOW_INPUT_FOCUS) {
2264 return FRAMEBUFFER_ODD; 2430 return FRAMEBUFFER_ODD;
2265 } 2431 }
2266 for (int i = 0; i < num_textures - 2; i++) 2432 for (int i = 0; i < num_extras; i++)
2267 { 2433 {
2268 if (extra_windows[i] && (SDL_GetWindowFlags(extra_windows[i]) & SDL_WINDOW_INPUT_FOCUS)) { 2434 if (extras[i].win && (SDL_GetWindowFlags(extras[i].win) & SDL_WINDOW_INPUT_FOCUS)) {
2269 return FRAMEBUFFER_USER_START + i; 2435 return FRAMEBUFFER_USER_START + i;
2270 } 2436 }
2271 } 2437 }
2272 return 0xFF; 2438 return 0xFF;
2273 } 2439 }