Mercurial > repos > blastem
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 } |