+#define p(x) px[(x)*2 >> 2] = px[((x)*2 >> 2) + 1]\r
+ // 16-bit modes\r
+ uint32_t *px = (uint32_t *)((short *)g_screen_ptr + scr_offs);\r
+ uint32_t col_g = (led_reg & 2) ? 0x06000600 : 0;\r
+ uint32_t col_r = (led_reg & 1) ? 0xc000c000 : 0;\r
+ p(pitch*0) = p(pitch*1) = p(pitch*2) = col_g;\r
+ p(pitch*0 + led_offs) = p(pitch*1 + led_offs) = p(pitch*2 + led_offs) = col_r;\r
+#undef p\r
+}\r
+\r
+static void draw_pico_ptr(void)\r
+{\r
+ int up = (PicoPicohw.pen_pos[0]|PicoPicohw.pen_pos[1]) & 0x8000;\r
+ int o = (up ? 0x0000 : 0xffff), _ = (up ? 0xffff : 0x0000);\r
+ int pitch = g_screen_ppitch;\r
+ u16 *p = g_screen_ptr;\r
+ int x = pico_pen_x, y = pico_pen_y;\r
+ // storyware pages are actually squished, 2:1\r
+ int h = (pico_inp_mode == 1 ? 160 : out_h);\r
+ if (h < 224) y++;\r
+\r
+ x = (x * out_w * ((1ULL<<32) / 320 + 1)) >> 32;\r
+ y = (y * h * ((1ULL<<32) / 224 + 1)) >> 32;\r
+ p += (screen_y+y)*pitch + (screen_x+x);\r
+\r
+ p[-pitch-1] ^= o; p[-pitch] ^= _; p[-pitch+1] ^= _; p[-pitch+2] ^= o;\r
+ p[-1] ^= _; p[0] ^= o; p[1] ^= o; p[2] ^= _;\r
+ p[pitch-1] ^= _; p[pitch] ^= o; p[pitch+1] ^= o; p[pitch+2] ^= _;\r
+ p[2*pitch-1]^= o; p[2*pitch]^= _; p[2*pitch+1]^= _; p[2*pitch+2]^= o;\r
+}\r
+\r
+/* render/screen buffer handling:\r
+ * In 16 bit mode, render output is directly placed in the screen buffer.\r
+ * SW scaling is handled in renderer (x) and in vscaling callbacks here (y).\r
+ * In 8 bit modes, output goes to the internal Draw2FB buffer in alternate\r
+ * renderer format (8 pix overscan at left/top/bottom), left aligned (DIS_32C).\r
+ * It is converted to 16 bit and SW scaled in pemu_finalize_frame.\r
+ *\r
+ * HW scaling always aligns the image to the left/top, since selecting an area\r
+ * for display isn't always possible.\r
+ */\r
+\r
+static inline u16 *screen_buffer(u16 *buf)\r
+{\r
+ return buf + screen_y * g_screen_ppitch + screen_x -\r
+ (out_y * g_screen_ppitch + out_x);\r
+}\r
+\r
+void screen_blit(u16 *pd, int pp, u8* ps, int ss, u16 *pal)\r
+{\r
+ typedef void (*upscale_t)\r
+ (u16 *di,int ds, u8 *si,int ss, int w,int h, u16 *pal);\r
+ static const upscale_t upscale_256_224_hv[] = {\r
+ upscale_rgb_nn_x_4_5_y_16_17, upscale_rgb_snn_x_4_5_y_16_17,\r
+ upscale_rgb_bl2_x_4_5_y_16_17, upscale_rgb_bl4_x_4_5_y_16_17,\r
+ };\r
+ static const upscale_t upscale_256_____h[] = {\r
+ upscale_rgb_nn_x_4_5, upscale_rgb_snn_x_4_5,\r
+ upscale_rgb_bl2_x_4_5, upscale_rgb_bl4_x_4_5,\r
+ };\r
+ static const upscale_t upscale_____224_v[] = {\r
+ upscale_rgb_nn_y_16_17, upscale_rgb_snn_y_16_17,\r
+ upscale_rgb_bl2_y_16_17, upscale_rgb_bl4_y_16_17,\r
+ };\r
+ static const upscale_t upscale_160_144_hv[] = {\r
+ upscale_rgb_nn_x_1_2_y_3_5, upscale_rgb_nn_x_1_2_y_3_5,\r
+ upscale_rgb_bl2_x_1_2_y_3_5, upscale_rgb_bl4_x_1_2_y_3_5,\r
+ };\r
+ static const upscale_t upscale_160_____h[] = {\r
+ upscale_rgb_nn_x_1_2, upscale_rgb_nn_x_1_2,\r
+ upscale_rgb_bl2_x_1_2, upscale_rgb_bl2_x_1_2,\r
+ };\r
+ static const upscale_t upscale_____144_v[] = {\r
+ upscale_rgb_nn_y_3_5, upscale_rgb_nn_y_3_5,\r
+ upscale_rgb_bl2_y_3_5, upscale_rgb_bl4_y_3_5,\r
+ };\r
+ const upscale_t *upscale;\r
+ int y;\r
+\r
+ // handle software upscaling\r
+ upscale = NULL;\r
+ if (currentConfig.scaling == EOPT_SCALE_SW && out_w <= 256) {\r
+ if (currentConfig.vscaling == EOPT_SCALE_SW && out_h <= 224)\r
+ // h+v scaling\r
+ upscale = out_w >= 240 ? upscale_256_224_hv: upscale_160_144_hv;\r
+ else\r
+ // h scaling\r
+ upscale = out_w >= 240 ? upscale_256_____h : upscale_160_____h;\r
+ } else if (currentConfig.vscaling == EOPT_SCALE_SW && out_h <= 224)\r
+ // v scaling\r
+ upscale = out_w >= 240 ? upscale_____224_v : upscale_____144_v;\r
+ if (!upscale) {\r
+ // no scaling\r
+ for (y = 0; y < out_h; y++)\r
+ h_copy(pd, pp, ps, 328, out_w, f_pal);\r
+ return;\r