comparison render_fbdev.c @ 1785:8f2e78db0872

Handle interlaced mode in fbdev backend
author Michael Pavone <pavone@retrodev.com>
date Thu, 14 Mar 2019 23:23:02 -0700
parents b2bffd98063d
children 2b661c1e431f
comparison
equal deleted inserted replaced
1784:72540af9c90a 1785:8f2e78db0872
428 } 428 }
429 return ret; 429 return ret;
430 } 430 }
431 #endif 431 #endif
432 432
433 static uint32_t texture_buf[513 * 512 * 2]; 433 #define MAX_FB_LINES 590
434 static uint32_t texture_buf[MAX_FB_LINES * LINEBUF_SIZE * 2];
434 #ifdef DISABLE_OPENGL 435 #ifdef DISABLE_OPENGL
435 #define RENDER_FORMAT SDL_PIXELFORMAT_ARGB8888 436 #define RENDER_FORMAT SDL_PIXELFORMAT_ARGB8888
436 #else 437 #else
437 #ifdef USE_GLES 438 #ifdef USE_GLES
438 #define INTERNAL_FORMAT GL_RGBA 439 #define INTERNAL_FORMAT GL_RGBA
1082 #endif 1083 #endif
1083 static pthread_mutex_t buffer_lock = PTHREAD_MUTEX_INITIALIZER; 1084 static pthread_mutex_t buffer_lock = PTHREAD_MUTEX_INITIALIZER;
1084 static pthread_cond_t buffer_cond = PTHREAD_COND_INITIALIZER; 1085 static pthread_cond_t buffer_cond = PTHREAD_COND_INITIALIZER;
1085 static uint8_t buffer_ready; 1086 static uint8_t buffer_ready;
1086 static uint32_t *copy_buffer; 1087 static uint32_t *copy_buffer;
1087 static uint32_t last_width, last_width_scale, last_height; 1088 static uint32_t last_width, last_width_scale, last_height, last_height_scale;
1088 static uint32_t max_multiple; 1089 static uint32_t max_multiple;
1090
1091 static uint32_t mix_pixel(uint32_t last, uint32_t cur, float ratio)
1092 {
1093 float a,b,c,d;
1094 a = (last & 255) * ratio;
1095 b = (last >> 8 & 255) * ratio;
1096 c = (last >> 16 & 255) * ratio;
1097 d = (last >> 24 & 255) * ratio;
1098 ratio = 1.0f - ratio;
1099 a += (cur & 255) * ratio;
1100 b += (cur >> 8 & 255) * ratio;
1101 c += (cur >> 16 & 255) * ratio;
1102 d += (cur >> 24 & 255) * ratio;
1103 return ((int)d) << 24 | ((int)c) << 16 | ((int)b) << 8 | ((int)a);
1104 }
1089 static void do_buffer_copy(void) 1105 static void do_buffer_copy(void)
1090 { 1106 {
1091 uint32_t width_multiple = main_width / last_width_scale; 1107 uint32_t width_multiple = main_width / last_width_scale;
1092 uint32_t height_multiple = main_height / last_height; 1108 uint32_t height_multiple = main_height / last_height_scale;
1093 uint32_t multiple = width_multiple < height_multiple ? width_multiple : height_multiple; 1109 uint32_t multiple = width_multiple < height_multiple ? width_multiple : height_multiple;
1094 if (max_multiple && multiple > max_multiple) { 1110 if (max_multiple && multiple > max_multiple) {
1095 multiple = max_multiple; 1111 multiple = max_multiple;
1096 } 1112 }
1113 height_multiple = last_height_scale * multiple / last_height;
1097 uint32_t *cur_line = framebuffer + (main_width - last_width_scale * multiple)/2; 1114 uint32_t *cur_line = framebuffer + (main_width - last_width_scale * multiple)/2;
1098 cur_line += fb_stride * (main_height - last_height * multiple) / (2 * sizeof(uint32_t)); 1115 cur_line += fb_stride * (main_height - last_height_scale * multiple) / (2 * sizeof(uint32_t));
1099 uint32_t *src_line = copy_buffer; 1116 uint32_t *src_line = copy_buffer;
1100 if (last_width == last_width_scale) { 1117 if (height_multiple * last_height == multiple * last_height_scale) {
1101 for (uint32_t y = 0; y < last_height; y++) 1118 if (last_width == last_width_scale) {
1102 { 1119 for (uint32_t y = 0; y < last_height; y++)
1103 for (uint32_t i = 0; i < multiple; i++)
1104 { 1120 {
1105 uint32_t *cur = cur_line; 1121 for (uint32_t i = 0; i < height_multiple; i++)
1106 uint32_t *src = src_line;
1107 for (uint32_t x = 0; x < last_width ; x++)
1108 { 1122 {
1109 uint32_t pixel = *(src++); 1123 uint32_t *cur = cur_line;
1110 for (uint32_t j = 0; j < multiple; j++) 1124 uint32_t *src = src_line;
1125 for (uint32_t x = 0; x < last_width ; x++)
1111 { 1126 {
1112 *(cur++) = pixel; 1127 uint32_t pixel = *(src++);
1128 for (uint32_t j = 0; j < multiple; j++)
1129 {
1130 *(cur++) = pixel;
1131 }
1113 } 1132 }
1133
1134 cur_line += fb_stride / sizeof(uint32_t);
1135 }
1136 src_line += LINEBUF_SIZE;
1137 }
1138 } else {
1139 float scale_multiple = ((float)(last_width_scale * multiple)) / (float)last_width;
1140 float remaining = 0.0f;
1141 uint32_t last_pixel = 0;
1142 for (uint32_t y = 0; y < last_height; y++)
1143 {
1144 for (uint32_t i = 0; i < height_multiple; i++)
1145 {
1146 uint32_t *cur = cur_line;
1147 uint32_t *src = src_line;
1148 for (uint32_t x = 0; x < last_width ; x++)
1149 {
1150 uint32_t pixel = *(src++);
1151 float count = scale_multiple;
1152 if (remaining > 0.0f) {
1153 *(cur++) = mix_pixel(last_pixel, pixel, remaining);
1154 count -= 1.0f - remaining;
1155 }
1156 for (; count >= 1; count -= 1.0f)
1157 {
1158 *(cur++) = pixel;
1159 }
1160 remaining = count;
1161 last_pixel = pixel;
1162 }
1163
1164 cur_line += fb_stride / sizeof(uint32_t);
1165 }
1166 src_line += LINEBUF_SIZE;
1167 }
1168 }
1169 } else {
1170 float height_scale = ((float)(last_height_scale * multiple)) / (float)last_height;
1171 float height_remaining = 0.0f;
1172 uint32_t *last_line;
1173 if (last_width == last_width_scale) {
1174 for (uint32_t y = 0; y < last_height; y++)
1175 {
1176 float hcount = height_scale;
1177 if (height_remaining > 0.0f) {
1178 uint32_t *cur = cur_line;
1179 uint32_t *src = src_line;
1180 uint32_t *last = last_line;
1181 for (uint32_t x = 0; x < last_width ; x++)
1182 {
1183 uint32_t mixed = mix_pixel(*(last++), *(src++), height_remaining);
1184 for (uint32_t j = 0; j < multiple; j++)
1185 {
1186 *(cur++) = mixed;
1187 }
1188 }
1189 hcount -= 1.0f - height_remaining;
1190 cur_line += fb_stride / sizeof(uint32_t);
1191 }
1192 for(; hcount >= 1; hcount -= 1.0f)
1193 {
1194 uint32_t *cur = cur_line;
1195 uint32_t *src = src_line;
1196 for (uint32_t x = 0; x < last_width ; x++)
1197 {
1198 uint32_t pixel = *(src++);
1199 for (uint32_t j = 0; j < multiple; j++)
1200 {
1201 *(cur++) = pixel;
1202 }
1203 }
1204
1205 cur_line += fb_stride / sizeof(uint32_t);
1206 }
1207 height_remaining = hcount;
1208 last_line = src_line;
1209 src_line += LINEBUF_SIZE;
1210 }
1211 } else {
1212 float scale_multiple = ((float)(last_width_scale * multiple)) / (float)last_width;
1213 float remaining = 0.0f;
1214 uint32_t last_pixel = 0;
1215 for (uint32_t y = 0; y < last_height; y++)
1216 {
1217 float hcount = height_scale;
1218 if (height_remaining > 0.0f) {
1219 uint32_t *cur = cur_line;
1220 uint32_t *src = src_line;
1221 uint32_t *last = last_line;
1222
1223 for (uint32_t x = 0; x < last_width; x++)
1224 {
1225 uint32_t pixel = mix_pixel(*(last++), *(src++), height_remaining);
1226 float count = scale_multiple;
1227 if (remaining > 0.0f) {
1228 *(cur++) = mix_pixel(last_pixel, pixel, remaining);
1229 count -= 1.0f - remaining;
1230 }
1231 for (; count >= 1.0f; count -= 1.0f)
1232 {
1233 *(cur++) = pixel;
1234 }
1235 remaining = count;
1236 last_pixel = pixel;
1237 }
1238 hcount -= 1.0f - height_remaining;
1239 cur_line += fb_stride / sizeof(uint32_t);
1114 } 1240 }
1115 1241
1116 cur_line += fb_stride / sizeof(uint32_t); 1242 for (; hcount >= 1.0f; hcount -= 1.0f)
1117 }
1118 src_line += LINEBUF_SIZE;
1119 }
1120 } else {
1121 float scale_multiple = ((float)(last_width_scale * multiple)) / (float)last_width;
1122 float remaining = 0.0f;
1123 uint32_t last_pixel = 0;
1124 for (uint32_t y = 0; y < last_height; y++)
1125 {
1126 for (uint32_t i = 0; i < multiple; i++)
1127 {
1128 uint32_t *cur = cur_line;
1129 uint32_t *src = src_line;
1130 for (uint32_t x = 0; x < last_width ; x++)
1131 { 1243 {
1132 uint32_t pixel = *(src++); 1244 uint32_t *cur = cur_line;
1133 float count = scale_multiple; 1245 uint32_t *src = src_line;
1134 if (remaining > 0.0f) { 1246 for (uint32_t x = 0; x < last_width ; x++)
1135 float a,b,c,d; 1247 {
1136 a = (last_pixel & 255) * remaining; 1248 uint32_t pixel = *(src++);
1137 b = (last_pixel >> 8 & 255) * remaining; 1249 float count = scale_multiple;
1138 c = (last_pixel >> 16 & 255) * remaining; 1250 if (remaining > 0.0f) {
1139 d = (last_pixel >> 24 & 255) * remaining; 1251 *(cur++) = mix_pixel(last_pixel, pixel, remaining);
1140 remaining = 1.0f - remaining; 1252 count -= 1.0f - remaining;
1141 a += (pixel & 255) * remaining; 1253 }
1142 b += (pixel >> 8 & 255) * remaining; 1254 for (; count >= 1; count -= 1.0f)
1143 c += (pixel >> 16 & 255) * remaining; 1255 {
1144 d += (pixel >> 24 & 255) * remaining; 1256 *(cur++) = pixel;
1145 count -= remaining; 1257 }
1146 uint32_t mixed = ((int)d) << 24 | ((int)c) << 16 | ((int)b) << 8 | ((int)a); 1258 remaining = count;
1147 *(cur++) = mixed; 1259 last_pixel = pixel;
1148 } 1260 }
1149 for (; count >= 1; count -= 1.0f) 1261
1150 { 1262 cur_line += fb_stride / sizeof(uint32_t);
1151 *(cur++) = pixel;
1152 }
1153 remaining = count;
1154 last_pixel = pixel;
1155 } 1263 }
1156 1264 height_remaining = hcount;
1157 cur_line += fb_stride / sizeof(uint32_t); 1265 last_line = src_line;
1158 } 1266 src_line += LINEBUF_SIZE;
1159 src_line += LINEBUF_SIZE; 1267 }
1160 } 1268 }
1161 } 1269 }
1162 } 1270 }
1163 static void *buffer_copy(void *data) 1271 static void *buffer_copy(void *data)
1164 { 1272 {
1545 void render_destroy_window(uint8_t which) 1653 void render_destroy_window(uint8_t which)
1546 { 1654 {
1547 //not supported under fbdev 1655 //not supported under fbdev
1548 } 1656 }
1549 1657
1550 uint32_t *locked_pixels; 1658 static uint8_t last_fb;
1551 uint32_t locked_pitch; 1659 static uint32_t texture_off;
1552 uint32_t texture_off;
1553 uint32_t *render_get_framebuffer(uint8_t which, int *pitch) 1660 uint32_t *render_get_framebuffer(uint8_t which, int *pitch)
1554 { 1661 {
1555 if (max_multiple == 1 && !render_gl) { 1662 if (max_multiple == 1 && !render_gl) {
1663 if (last_fb != which) {
1664 *pitch = fb_stride * 2;
1665 return framebuffer + (which == FRAMEBUFFER_EVEN ? fb_stride / sizeof(uint32_t) : 0);
1666 }
1556 *pitch = fb_stride; 1667 *pitch = fb_stride;
1557 return framebuffer; 1668 return framebuffer;
1558 } 1669 }
1670 if (!render_gl && last_fb != which) {
1671 *pitch = LINEBUF_SIZE * sizeof(uint32_t) * 2;
1672 return texture_buf + texture_off + (which == FRAMEBUFFER_EVEN ? LINEBUF_SIZE : 0);
1673 }
1559 *pitch = LINEBUF_SIZE * sizeof(uint32_t); 1674 *pitch = LINEBUF_SIZE * sizeof(uint32_t);
1560 return texture_buf + texture_off; 1675 return texture_buf + texture_off;
1561 /*
1562 #ifndef DISABLE_OPENGL
1563 if (render_gl && which <= FRAMEBUFFER_EVEN) {
1564 *pitch = LINEBUF_SIZE * sizeof(uint32_t);
1565 return texture_buf;
1566 } else {
1567 #endif
1568 if (which >= num_textures) {
1569 warning("Request for invalid framebuffer number %d\n", which);
1570 return NULL;
1571 }
1572 void *pixels;
1573 if (SDL_LockTexture(sdl_textures[which], NULL, &pixels, pitch) < 0) {
1574 warning("Failed to lock texture: %s\n", SDL_GetError());
1575 return NULL;
1576 }
1577 static uint8_t last;
1578 if (which <= FRAMEBUFFER_EVEN) {
1579 locked_pixels = pixels;
1580 if (which == FRAMEBUFFER_EVEN) {
1581 pixels += *pitch;
1582 }
1583 locked_pitch = *pitch;
1584 if (which != last) {
1585 *pitch *= 2;
1586 }
1587 last = which;
1588 }
1589 return pixels;
1590 #ifndef DISABLE_OPENGL
1591 }
1592 #endif*/
1593 } 1676 }
1594 1677
1595 uint8_t events_processed; 1678 uint8_t events_processed;
1596 #ifdef __ANDROID__ 1679 #ifdef __ANDROID__
1597 #define FPS_INTERVAL 10000 1680 #define FPS_INTERVAL 10000
1620 if (copy_use_thread) { 1703 if (copy_use_thread) {
1621 pthread_mutex_lock(&buffer_lock); 1704 pthread_mutex_lock(&buffer_lock);
1622 buffer_ready = 1; 1705 buffer_ready = 1;
1623 last_width = width; 1706 last_width = width;
1624 last_width_scale = LINEBUF_SIZE - (overscan_left[video_standard] + overscan_right[video_standard]); 1707 last_width_scale = LINEBUF_SIZE - (overscan_left[video_standard] + overscan_right[video_standard]);
1625 last_height = height; 1708 last_height = last_height_scale = height;
1626 copy_buffer = texture_buf + texture_off + overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard]; 1709 copy_buffer = texture_buf + texture_off + overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard];
1627 texture_off = texture_off ? 0 : LINEBUF_SIZE * 512; 1710 if (which != last_fb) {
1711 last_height *= 2;
1712 copy_buffer += LINEBUF_SIZE * overscan_top[video_standard];
1713 uint32_t *src = texture_buf + (texture_off ? 0 : LINEBUF_SIZE * MAX_FB_LINES) + overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard] + LINEBUF_SIZE * overscan_top[video_standard];
1714 uint32_t *dst = copy_buffer;
1715 if (which == FRAMEBUFFER_ODD) {
1716 src += LINEBUF_SIZE;
1717 dst += LINEBUF_SIZE;
1718 }
1719 for (int i = 0; i < height; i++)
1720 {
1721 memcpy(dst, src, width * sizeof(uint32_t));
1722 src += LINEBUF_SIZE * 2;
1723 dst += LINEBUF_SIZE * 2;
1724 }
1725 }
1726 texture_off = texture_off ? 0 : LINEBUF_SIZE * MAX_FB_LINES;
1628 pthread_cond_signal(&buffer_cond); 1727 pthread_cond_signal(&buffer_cond);
1629 pthread_mutex_unlock(&buffer_lock); 1728 pthread_mutex_unlock(&buffer_lock);
1630 } else { 1729 } else {
1631 last_width = width; 1730 last_width = width;
1632 last_width_scale = LINEBUF_SIZE - (overscan_left[video_standard] + overscan_right[video_standard]); 1731 last_width_scale = LINEBUF_SIZE - (overscan_left[video_standard] + overscan_right[video_standard]);
1633 last_height = height; 1732 last_height = last_height_scale = height;
1634 copy_buffer = texture_buf + texture_off + overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard]; 1733 copy_buffer = texture_buf + texture_off + overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard];
1734 if (which != last_fb) {
1735 last_height *= 2;
1736 copy_buffer += LINEBUF_SIZE * overscan_top[video_standard];
1737 }
1635 do_buffer_copy(); 1738 do_buffer_copy();
1636 } 1739 }
1637 } 1740 }
1741 last_fb = which;
1638 if (!events_processed) { 1742 if (!events_processed) {
1639 process_events(); 1743 process_events();
1640 } 1744 }
1641 events_processed = 0; 1745 events_processed = 0;
1642 #ifndef DISABLE_OPENGL 1746 #ifndef DISABLE_OPENGL