mirror of
https://github.com/holub/mame
synced 2025-05-11 16:48:52 +03:00
1142 lines
30 KiB
C
1142 lines
30 KiB
C
//============================================================
|
|
//
|
|
// drawsdl.c - SDL software and OpenGL implementation
|
|
//
|
|
// Copyright (c) 1996-2010, Nicola Salmoria and the MAME Team.
|
|
// Visit http://mamedev.org for licensing and usage restrictions.
|
|
//
|
|
// SDLMAME by Olivier Galibert and R. Belmont
|
|
//
|
|
//============================================================
|
|
|
|
// standard C headers
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
|
|
// MAME headers
|
|
#include "emu.h"
|
|
#include "ui.h"
|
|
|
|
// standard SDL headers
|
|
#include <SDL/SDL.h>
|
|
|
|
// OSD headers
|
|
#include "osdsdl.h"
|
|
#include "window.h"
|
|
|
|
//============================================================
|
|
// DEBUGGING
|
|
//============================================================
|
|
|
|
//============================================================
|
|
// CONSTANTS
|
|
//============================================================
|
|
|
|
//============================================================
|
|
// TYPES
|
|
//============================================================
|
|
|
|
typedef struct _sdl_scale_mode sdl_scale_mode;
|
|
|
|
/* sdl_info is the information about SDL for the current screen */
|
|
typedef struct _sdl_info sdl_info;
|
|
struct _sdl_info
|
|
{
|
|
INT32 blittimer;
|
|
UINT32 extra_flags;
|
|
|
|
#if (SDL_VERSION_ATLEAST(1,3,0))
|
|
SDL_TextureID texture_id;
|
|
#else
|
|
// SDL surface
|
|
SDL_Surface *sdlsurf;
|
|
SDL_Overlay *yuvsurf;
|
|
#endif
|
|
|
|
// YUV overlay
|
|
UINT32 *yuv_lookup;
|
|
UINT16 *yuv_bitmap;
|
|
|
|
// if we leave scaling to SDL and the underlying driver, this
|
|
// is the render_target_width/height to use
|
|
|
|
int hw_scale_width;
|
|
int hw_scale_height;
|
|
int last_hofs;
|
|
int last_vofs;
|
|
int old_blitwidth;
|
|
int old_blitheight;
|
|
|
|
// shortcut to scale mode info
|
|
|
|
const sdl_scale_mode *scale_mode;
|
|
};
|
|
|
|
struct _sdl_scale_mode
|
|
{
|
|
const char *name;
|
|
int is_scale; /* Scale mode? */
|
|
int is_yuv; /* Yuv mode? */
|
|
int mult_w; /* Width multiplier */
|
|
int mult_h; /* Height multiplier */
|
|
#if (!SDL_VERSION_ATLEAST(1,3,0))
|
|
int extra_flags; /* Texture/surface flags */
|
|
#else
|
|
int sdl_scale_mode; /* sdl 1.3 scale mode */
|
|
#endif
|
|
int pixel_format; /* Pixel/Overlay format */
|
|
void (*yuv_blit)(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch);
|
|
};
|
|
|
|
//============================================================
|
|
// INLINES
|
|
//============================================================
|
|
|
|
//============================================================
|
|
// PROTOTYPES
|
|
//============================================================
|
|
|
|
// core functions
|
|
static void drawsdl_exit(void);
|
|
static void drawsdl_attach(sdl_draw_info *info, sdl_window_info *window);
|
|
static int drawsdl_window_create(sdl_window_info *window, int width, int height);
|
|
static void drawsdl_window_resize(sdl_window_info *window, int width, int height);
|
|
static void drawsdl_window_destroy(sdl_window_info *window);
|
|
static render_primitive_list &drawsdl_window_get_primitives(sdl_window_info *window);
|
|
static int drawsdl_window_draw(sdl_window_info *window, UINT32 dc, int update);
|
|
static void drawsdl_destroy_all_textures(sdl_window_info *window);
|
|
static void drawsdl_window_clear(sdl_window_info *window);
|
|
static int drawsdl_xy_to_render_target(sdl_window_info *window, int x, int y, int *xt, int *yt);
|
|
|
|
#if (SDL_VERSION_ATLEAST(1,3,0))
|
|
static void setup_texture(sdl_window_info *window, int tempwidth, int tempheight);
|
|
#endif
|
|
|
|
// soft rendering
|
|
static void drawsdl_rgb888_draw_primitives(const render_primitive_list &primlist, void *dstdata, UINT32 width, UINT32 height, UINT32 pitch);
|
|
static void drawsdl_bgr888_draw_primitives(const render_primitive_list &primlist, void *dstdata, UINT32 width, UINT32 height, UINT32 pitch);
|
|
static void drawsdl_bgra888_draw_primitives(const render_primitive_list &primlist, void *dstdata, UINT32 width, UINT32 height, UINT32 pitch);
|
|
static void drawsdl_rgb565_draw_primitives(const render_primitive_list &primlist, void *dstdata, UINT32 width, UINT32 height, UINT32 pitch);
|
|
static void drawsdl_rgb555_draw_primitives(const render_primitive_list &primlist, void *dstdata, UINT32 width, UINT32 height, UINT32 pitch);
|
|
|
|
// YUV overlays
|
|
|
|
static void drawsdl_yuv_init(sdl_info *sdl);
|
|
static void yuv_RGB_to_YV12(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch);
|
|
static void yuv_RGB_to_YV12X2(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch);
|
|
static void yuv_RGB_to_YUY2(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch);
|
|
static void yuv_RGB_to_YUY2X2(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch);
|
|
|
|
// Static declarations
|
|
|
|
#if (!SDL_VERSION_ATLEAST(1,3,0))
|
|
static int shown_video_info = 0;
|
|
|
|
static const sdl_scale_mode scale_modes[] =
|
|
{
|
|
{ "none", 0, 0, 0, 0, SDL_DOUBLEBUF, 0, 0 },
|
|
{ "async", 0, 0, 0, 0, SDL_DOUBLEBUF | SDL_ASYNCBLIT, 0, 0 },
|
|
{ "yv12", 1, 1, 1, 1, 0, SDL_YV12_OVERLAY, yuv_RGB_to_YV12 },
|
|
{ "yv12x2", 1, 1, 2, 2, 0, SDL_YV12_OVERLAY, yuv_RGB_to_YV12X2 },
|
|
{ "yuy2", 1, 1, 1, 1, 0, SDL_YUY2_OVERLAY, yuv_RGB_to_YUY2 },
|
|
{ "yuy2x2", 1, 1, 2, 1, 0, SDL_YUY2_OVERLAY, yuv_RGB_to_YUY2X2 },
|
|
{ NULL }
|
|
};
|
|
#else
|
|
static const sdl_scale_mode scale_modes[] =
|
|
{
|
|
{ "none", 0, 0, 0, 0, SDL_TEXTURESCALEMODE_NONE, 0, 0 },
|
|
{ "hwblit", 1, 0, 1, 1, SDL_TEXTURESCALEMODE_FAST, 0, 0 },
|
|
{ "hwbest", 1, 0, 1, 1, SDL_TEXTURESCALEMODE_BEST, 0, 0 },
|
|
{ "yv12", 1, 1, 1, 1, SDL_TEXTURESCALEMODE_NONE, SDL_PIXELFORMAT_YV12, yuv_RGB_to_YV12 },
|
|
{ "yv12x2", 1, 1, 2, 2, SDL_TEXTURESCALEMODE_NONE, SDL_PIXELFORMAT_YV12, yuv_RGB_to_YV12X2 },
|
|
{ "yuy2", 1, 1, 1, 1, SDL_TEXTURESCALEMODE_NONE, SDL_PIXELFORMAT_YUY2, yuv_RGB_to_YUY2 },
|
|
{ "yuy2x2", 1, 1, 2, 1, SDL_TEXTURESCALEMODE_NONE, SDL_PIXELFORMAT_YUY2, yuv_RGB_to_YUY2X2 },
|
|
{ NULL }
|
|
};
|
|
#endif
|
|
|
|
//============================================================
|
|
// drawsdl_scale_mode
|
|
//============================================================
|
|
|
|
const char *drawsdl_scale_mode_str(int index)
|
|
{
|
|
const sdl_scale_mode *sm = scale_modes;
|
|
|
|
while (index>0)
|
|
{
|
|
if (sm->name == NULL)
|
|
return NULL;
|
|
index--;
|
|
sm++;
|
|
}
|
|
return sm->name;
|
|
};
|
|
|
|
int drawsdl_scale_mode(const char *s)
|
|
{
|
|
const sdl_scale_mode *sm = scale_modes;
|
|
int index;
|
|
|
|
index = 0;
|
|
while (sm->name != NULL)
|
|
{
|
|
if (strcmp(sm->name, s) == 0)
|
|
return index;
|
|
index++;
|
|
sm++;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//============================================================
|
|
// drawsdl_init
|
|
//============================================================
|
|
|
|
int drawsdl_init(sdl_draw_info *callbacks)
|
|
{
|
|
// fill in the callbacks
|
|
callbacks->exit = drawsdl_exit;
|
|
callbacks->attach = drawsdl_attach;
|
|
|
|
if (SDL_VERSION_ATLEAST(1,3,0))
|
|
mame_printf_verbose("Using SDL multi-window soft driver (SDL 1.3+)\n");
|
|
else
|
|
mame_printf_verbose("Using SDL single-window soft driver (SDL 1.2)\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
//============================================================
|
|
// drawsdl_exit
|
|
//============================================================
|
|
|
|
static void drawsdl_exit(void)
|
|
{
|
|
}
|
|
|
|
//============================================================
|
|
// drawsdl_attach
|
|
//============================================================
|
|
|
|
static void drawsdl_attach(sdl_draw_info *info, sdl_window_info *window)
|
|
{
|
|
// fill in the callbacks
|
|
window->create = drawsdl_window_create;
|
|
window->resize = drawsdl_window_resize;
|
|
window->get_primitives = drawsdl_window_get_primitives;
|
|
window->draw = drawsdl_window_draw;
|
|
window->destroy = drawsdl_window_destroy;
|
|
window->destroy_all_textures = drawsdl_destroy_all_textures;
|
|
window->clear = drawsdl_window_clear;
|
|
window->xy_to_render_target = drawsdl_xy_to_render_target;
|
|
}
|
|
|
|
//============================================================
|
|
// drawsdl_destroy_all_textures
|
|
//============================================================
|
|
|
|
static void drawsdl_destroy_all_textures(sdl_window_info *window)
|
|
{
|
|
/* nothing to be done in soft mode */
|
|
}
|
|
|
|
//============================================================
|
|
// setup_texture for window
|
|
//============================================================
|
|
|
|
#if (SDL_VERSION_ATLEAST(1,3,0))
|
|
static void setup_texture(sdl_window_info *window, int tempwidth, int tempheight)
|
|
{
|
|
sdl_info *sdl = (sdl_info *) window->dxdata;
|
|
const sdl_scale_mode *sdl_sm = sdl->scale_mode;
|
|
SDL_DisplayMode mode;
|
|
UINT32 fmt;
|
|
|
|
// Determine preferred pixelformat and set up yuv if necessary
|
|
SDL_GetCurrentDisplayMode(&mode);
|
|
|
|
if (sdl->yuv_bitmap)
|
|
{
|
|
global_free(sdl->yuv_bitmap);
|
|
sdl->yuv_bitmap = NULL;
|
|
}
|
|
|
|
if (sdl_sm->is_scale)
|
|
{
|
|
window->target->compute_minimum_size(sdl->hw_scale_width, sdl->hw_scale_height);
|
|
if (video_config.prescale)
|
|
{
|
|
sdl->hw_scale_width *= video_config.prescale;
|
|
sdl->hw_scale_height *= video_config.prescale;
|
|
}
|
|
}
|
|
|
|
if (sdl_sm->is_yuv)
|
|
sdl->yuv_bitmap = global_alloc_array(UINT16, sdl->hw_scale_width * sdl->hw_scale_height);
|
|
|
|
fmt = (sdl_sm->pixel_format ? sdl_sm->pixel_format : mode.format);
|
|
|
|
if (sdl_sm->is_scale)
|
|
{
|
|
int w = sdl->hw_scale_width * sdl_sm->mult_w;
|
|
int h = sdl->hw_scale_height * sdl_sm->mult_h;
|
|
|
|
sdl->texture_id = SDL_CreateTexture(fmt, SDL_TEXTUREACCESS_STREAMING, w, h);
|
|
|
|
}
|
|
else
|
|
{
|
|
sdl->texture_id = SDL_CreateTexture(fmt, SDL_TEXTUREACCESS_STREAMING,
|
|
tempwidth, tempheight);
|
|
}
|
|
|
|
SDL_SetTextureScaleMode(sdl->texture_id, sdl_sm->sdl_scale_mode);
|
|
|
|
}
|
|
#endif
|
|
|
|
//============================================================
|
|
// yuv_overlay_init
|
|
//============================================================
|
|
|
|
#if (!SDL_VERSION_ATLEAST(1,3,0))
|
|
static void yuv_overlay_init(sdl_window_info *window)
|
|
{
|
|
sdl_info *sdl = (sdl_info *) window->dxdata;
|
|
const sdl_scale_mode *sdl_sm = sdl->scale_mode;
|
|
int minimum_width, minimum_height;
|
|
|
|
window->target->compute_minimum_size(minimum_width, minimum_height);
|
|
|
|
if (video_config.prescale)
|
|
{
|
|
minimum_width *= video_config.prescale;
|
|
minimum_height *= video_config.prescale;
|
|
}
|
|
|
|
if (sdl->yuvsurf != NULL)
|
|
{
|
|
SDL_FreeYUVOverlay(sdl->yuvsurf);
|
|
sdl->yuvsurf = NULL;
|
|
}
|
|
|
|
if (sdl->yuv_bitmap != NULL)
|
|
{
|
|
global_free(sdl->yuv_bitmap);
|
|
}
|
|
|
|
mame_printf_verbose("SDL: Creating %d x %d YUV-Overlay ...\n", minimum_width, minimum_height);
|
|
|
|
sdl->yuv_bitmap = global_alloc_array(UINT16, minimum_width*minimum_height);
|
|
|
|
sdl->yuvsurf = SDL_CreateYUVOverlay(minimum_width * sdl_sm->mult_w, minimum_height * sdl_sm->mult_h,
|
|
sdl_sm->pixel_format, sdl->sdlsurf);
|
|
|
|
if ( sdl->yuvsurf == NULL ) {
|
|
mame_printf_error("SDL: Couldn't create SDL_yuv_overlay: %s\n", SDL_GetError());
|
|
//return 1;
|
|
}
|
|
|
|
sdl->hw_scale_width = minimum_width;
|
|
sdl->hw_scale_height = minimum_height;
|
|
|
|
if (!shown_video_info)
|
|
{
|
|
mame_printf_verbose("YUV Mode : %s\n", sdl_sm->name);
|
|
mame_printf_verbose("YUV Overlay Size : %d x %d\n", minimum_width, minimum_height);
|
|
mame_printf_verbose("YUV Acceleration : %s\n", sdl->yuvsurf->hw_overlay ? "Hardware" : "Software");
|
|
shown_video_info = 1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//============================================================
|
|
// drawsdl_show_info
|
|
//============================================================
|
|
|
|
#if (SDL_VERSION_ATLEAST(1,3,0))
|
|
static void drawsdl_show_info(sdl_window_info *window, struct SDL_RendererInfo *render_info)
|
|
{
|
|
#define RF_ENTRY(x) {x, #x }
|
|
static struct {
|
|
int flag;
|
|
const char *name;
|
|
} rflist[] =
|
|
{
|
|
RF_ENTRY(SDL_RENDERER_SINGLEBUFFER),
|
|
RF_ENTRY(SDL_RENDERER_PRESENTCOPY),
|
|
RF_ENTRY(SDL_RENDERER_PRESENTFLIP2),
|
|
RF_ENTRY(SDL_RENDERER_PRESENTFLIP3),
|
|
RF_ENTRY(SDL_RENDERER_PRESENTDISCARD),
|
|
RF_ENTRY(SDL_RENDERER_PRESENTVSYNC),
|
|
RF_ENTRY(SDL_RENDERER_ACCELERATED),
|
|
{-1, NULL}
|
|
};
|
|
int i;
|
|
|
|
mame_printf_verbose("window: using renderer %s\n", render_info->name ? render_info->name : "<unknown>");
|
|
for (i = 0; rflist[i].name != NULL; i++)
|
|
if (render_info->flags & rflist[i].flag)
|
|
mame_printf_verbose("renderer: flag %s\n", rflist[i].name);
|
|
}
|
|
#endif
|
|
|
|
//============================================================
|
|
// drawsdl_window_create
|
|
//============================================================
|
|
|
|
static int drawsdl_window_create(sdl_window_info *window, int width, int height)
|
|
{
|
|
sdl_info *sdl;
|
|
|
|
// allocate memory for our structures
|
|
sdl = (sdl_info *) osd_malloc(sizeof(sdl_info));
|
|
memset(sdl, 0, sizeof(sdl_info));
|
|
|
|
window->dxdata = sdl;
|
|
|
|
sdl->scale_mode = &scale_modes[window->scale_mode];
|
|
|
|
#if (SDL_VERSION_ATLEAST(1,3,0))
|
|
sdl->extra_flags = (window->fullscreen ?
|
|
SDL_WINDOW_BORDERLESS | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS
|
|
| SDL_WINDOW_INPUT_GRABBED : SDL_WINDOW_RESIZABLE);
|
|
|
|
SDL_SelectVideoDisplay(window->monitor->handle);
|
|
|
|
if (window->fullscreen && video_config.switchres)
|
|
{
|
|
SDL_DisplayMode mode;
|
|
SDL_GetCurrentDisplayMode(&mode);
|
|
mode.w = width;
|
|
mode.h = height;
|
|
if (window->refresh)
|
|
mode.refresh_rate = window->refresh;
|
|
SDL_SetWindowDisplayMode(window->sdl_window, &mode); // Try to set mode
|
|
}
|
|
else
|
|
SDL_SetWindowDisplayMode(window->sdl_window, NULL); // Use desktop
|
|
|
|
window->sdl_window = SDL_CreateWindow(window->title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
|
width, height, sdl->extra_flags);
|
|
SDL_ShowWindow(window->sdl_window);
|
|
|
|
SDL_SetWindowFullscreen(window->sdl_window, window->fullscreen);
|
|
SDL_GetWindowSize(window->sdl_window, &window->width, &window->height);
|
|
SDL_RaiseWindow(window->sdl_window);
|
|
|
|
/* FIXME: Bug in SDL 1.3 */
|
|
if (window->fullscreen)
|
|
SDL_SetWindowGrab(window->sdl_window, 1);
|
|
|
|
// create a texture
|
|
|
|
if (video_config.waitvsync)
|
|
SDL_CreateRenderer(window->sdl_window, -1, SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_PRESENTVSYNC);
|
|
else
|
|
SDL_CreateRenderer(window->sdl_window, -1, SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTDISCARD);
|
|
|
|
SDL_SelectRenderer(window->sdl_window);
|
|
|
|
{
|
|
struct SDL_RendererInfo render_info;
|
|
SDL_GetRendererInfo(&render_info);
|
|
|
|
drawsdl_show_info(window, &render_info);
|
|
|
|
// Check scale mode
|
|
|
|
if (sdl->scale_mode->pixel_format)
|
|
{
|
|
int i;
|
|
int found = 0;
|
|
|
|
for (i=0; i < render_info.num_texture_formats; i++)
|
|
if (sdl->scale_mode->pixel_format == render_info.texture_formats[i])
|
|
found = 1;
|
|
|
|
if (!found)
|
|
{
|
|
mame_printf_verbose("window: Scale mode %s not supported! Using default.\n", sdl->scale_mode->name);
|
|
ui_popup_time(3, "Scale mode %s not supported! Using default.", sdl->scale_mode->name);
|
|
sdl->scale_mode = &scale_modes[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
setup_texture(window, width, height);
|
|
#else
|
|
sdl->extra_flags = (window->fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE);
|
|
|
|
sdl->extra_flags |= sdl->scale_mode->extra_flags;
|
|
|
|
sdl->sdlsurf = SDL_SetVideoMode(width, height,
|
|
0, SDL_SWSURFACE | SDL_ANYFORMAT | sdl->extra_flags);
|
|
|
|
if (!sdl->sdlsurf)
|
|
return 1;
|
|
|
|
window->width = sdl->sdlsurf->w;
|
|
window->height = sdl->sdlsurf->h;
|
|
|
|
if (sdl->scale_mode->is_yuv)
|
|
yuv_overlay_init(window);
|
|
|
|
// set the window title
|
|
SDL_WM_SetCaption(window->title, "SDLMAME");
|
|
#endif
|
|
sdl->yuv_lookup = NULL;
|
|
sdl->blittimer = 0;
|
|
|
|
drawsdl_yuv_init(sdl);
|
|
return 0;
|
|
}
|
|
|
|
//============================================================
|
|
// drawsdl_window_resize
|
|
//============================================================
|
|
|
|
static void drawsdl_window_resize(sdl_window_info *window, int width, int height)
|
|
{
|
|
|
|
#if (SDL_VERSION_ATLEAST(1,3,0))
|
|
SDL_SetWindowSize(window->sdl_window, width, height);
|
|
SDL_GetWindowSize(window->sdl_window, &window->width, &window->height);
|
|
|
|
#else
|
|
sdl_info *sdl = (sdl_info *) window->dxdata;
|
|
|
|
if (sdl->yuvsurf != NULL)
|
|
{
|
|
SDL_FreeYUVOverlay(sdl->yuvsurf);
|
|
sdl->yuvsurf = NULL;
|
|
}
|
|
SDL_FreeSurface(sdl->sdlsurf);
|
|
//printf("SetVideoMode %d %d\n", wp->resize_new_width, wp->resize_new_height);
|
|
|
|
sdl->sdlsurf = SDL_SetVideoMode(width, height, 0,
|
|
SDL_SWSURFACE | SDL_ANYFORMAT | sdl->extra_flags);
|
|
window->width = sdl->sdlsurf->w;
|
|
window->height = sdl->sdlsurf->h;
|
|
|
|
if (sdl->scale_mode->is_yuv)
|
|
{
|
|
yuv_overlay_init(window);
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// drawsdl_window_destroy
|
|
//============================================================
|
|
|
|
static void drawsdl_window_destroy(sdl_window_info *window)
|
|
{
|
|
sdl_info *sdl = (sdl_info *) window->dxdata;
|
|
|
|
// skip if nothing
|
|
if (sdl == NULL)
|
|
return;
|
|
|
|
#if (SDL_VERSION_ATLEAST(1,3,0))
|
|
SDL_SelectRenderer(window->sdl_window);
|
|
SDL_DestroyTexture(sdl->texture_id);
|
|
//SDL_DestroyRenderer(window->sdl_window);
|
|
SDL_DestroyWindow(window->sdl_window);
|
|
#else
|
|
if (sdl->yuvsurf != NULL)
|
|
{
|
|
SDL_FreeYUVOverlay(sdl->yuvsurf);
|
|
sdl->yuvsurf = NULL;
|
|
}
|
|
|
|
if (sdl->sdlsurf)
|
|
{
|
|
SDL_FreeSurface(sdl->sdlsurf);
|
|
sdl->sdlsurf = NULL;
|
|
}
|
|
#endif
|
|
// free the memory in the window
|
|
|
|
if (sdl->yuv_lookup != NULL)
|
|
{
|
|
global_free(sdl->yuv_lookup);
|
|
sdl->yuv_lookup = NULL;
|
|
}
|
|
if (sdl->yuv_bitmap != NULL)
|
|
{
|
|
global_free(sdl->yuv_bitmap);
|
|
sdl->yuv_bitmap = NULL;
|
|
}
|
|
osd_free(sdl);
|
|
window->dxdata = NULL;
|
|
}
|
|
|
|
//============================================================
|
|
// drawsdl_window_clear
|
|
//============================================================
|
|
|
|
static void drawsdl_window_clear(sdl_window_info *window)
|
|
{
|
|
sdl_info *sdl = (sdl_info *) window->dxdata;
|
|
|
|
sdl->blittimer = 3;
|
|
}
|
|
|
|
//============================================================
|
|
// drawsdl_xy_to_render_target
|
|
//============================================================
|
|
|
|
static int drawsdl_xy_to_render_target(sdl_window_info *window, int x, int y, int *xt, int *yt)
|
|
{
|
|
sdl_info *sdl = (sdl_info *) window->dxdata;
|
|
|
|
*xt = x - sdl->last_hofs;
|
|
*yt = y - sdl->last_vofs;
|
|
if (*xt<0 || *xt >= window->blitwidth)
|
|
return 0;
|
|
if (*yt<0 || *xt >= window->blitheight)
|
|
return 0;
|
|
if (!sdl->scale_mode->is_scale)
|
|
{
|
|
return 1;
|
|
}
|
|
/* Rescale */
|
|
*xt = (*xt * sdl->hw_scale_width) / window->blitwidth;
|
|
*yt = (*yt * sdl->hw_scale_height) / window->blitheight;
|
|
return 1;
|
|
}
|
|
|
|
//============================================================
|
|
// drawsdl_window_get_primitives
|
|
//============================================================
|
|
|
|
static render_primitive_list &drawsdl_window_get_primitives(sdl_window_info *window)
|
|
{
|
|
sdl_info *sdl = (sdl_info *) window->dxdata;
|
|
|
|
if ((!window->fullscreen) || (video_config.switchres))
|
|
{
|
|
sdlwindow_blit_surface_size(window, window->width, window->height);
|
|
}
|
|
else
|
|
{
|
|
sdlwindow_blit_surface_size(window, window->monitor->center_width, window->monitor->center_height);
|
|
}
|
|
if (!sdl->scale_mode->is_scale)
|
|
window->target->set_bounds(window->blitwidth, window->blitheight, sdlvideo_monitor_get_aspect(window->monitor));
|
|
else
|
|
window->target->set_bounds(sdl->hw_scale_width, sdl->hw_scale_height);
|
|
return window->target->get_primitives();
|
|
}
|
|
|
|
//============================================================
|
|
// drawsdl_window_draw
|
|
//============================================================
|
|
|
|
static int drawsdl_window_draw(sdl_window_info *window, UINT32 dc, int update)
|
|
{
|
|
sdl_info *sdl = (sdl_info *) window->dxdata;
|
|
UINT8 *surfptr;
|
|
INT32 pitch;
|
|
int bpp;
|
|
Uint32 rmask, gmask, bmask, amask;
|
|
INT32 vofs, hofs, blitwidth, blitheight, ch, cw;
|
|
|
|
if (video_config.novideo)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// if we haven't been created, just punt
|
|
if (sdl == NULL)
|
|
return 1;
|
|
|
|
// lock it if we need it
|
|
#if (!SDL_VERSION_ATLEAST(1,3,0))
|
|
|
|
pitch = sdl->sdlsurf->pitch;
|
|
bpp = sdl->sdlsurf->format->BytesPerPixel;
|
|
rmask = sdl->sdlsurf->format->Rmask;
|
|
gmask = sdl->sdlsurf->format->Gmask;
|
|
bmask = sdl->sdlsurf->format->Bmask;
|
|
amask = sdl->sdlsurf->format->Amask;
|
|
|
|
if (window->blitwidth != sdl->old_blitwidth || window->blitheight != sdl->old_blitheight)
|
|
{
|
|
if (sdl->scale_mode->is_yuv)
|
|
yuv_overlay_init(window);
|
|
sdl->old_blitwidth = window->blitwidth;
|
|
sdl->old_blitheight = window->blitheight;
|
|
sdl->blittimer = 3;
|
|
}
|
|
|
|
if (SDL_MUSTLOCK(sdl->sdlsurf)) SDL_LockSurface(sdl->sdlsurf);
|
|
// Clear if necessary
|
|
|
|
if (sdl->blittimer > 0)
|
|
{
|
|
memset(sdl->sdlsurf->pixels, 0, window->height * sdl->sdlsurf->pitch);
|
|
sdl->blittimer--;
|
|
}
|
|
|
|
|
|
if (sdl->scale_mode->is_yuv)
|
|
{
|
|
SDL_LockYUVOverlay(sdl->yuvsurf);
|
|
surfptr = sdl->yuvsurf->pixels[0]; // (UINT8 *) sdl->yuv_bitmap;
|
|
pitch = sdl->yuvsurf->pitches[0]; // (UINT8 *) sdl->yuv_bitmap;
|
|
}
|
|
else
|
|
surfptr = (UINT8 *)sdl->sdlsurf->pixels;
|
|
#else
|
|
SDL_SelectRenderer(window->sdl_window);
|
|
|
|
if (window->blitwidth != sdl->old_blitwidth || window->blitheight != sdl->old_blitheight)
|
|
{
|
|
SDL_DestroyTexture(sdl->texture_id);
|
|
setup_texture(window, window->blitwidth, window->blitheight);
|
|
sdl->old_blitwidth = window->blitwidth;
|
|
sdl->old_blitheight = window->blitheight;
|
|
sdl->blittimer = 3;
|
|
}
|
|
|
|
{
|
|
Uint32 format;
|
|
int access, w, h;
|
|
|
|
SDL_QueryTexture(sdl->texture_id, &format, &access, &w, &h);
|
|
SDL_PixelFormatEnumToMasks(format, &bpp, &rmask, &gmask, &bmask, &amask);
|
|
bpp = bpp / 8; /* convert to bytes per pixels */
|
|
}
|
|
|
|
// Clear if necessary
|
|
if (sdl->blittimer > 0)
|
|
{
|
|
/* SDL Underlays need alpha = 0 ! */
|
|
SDL_SetRenderDrawColor(0,0,0,0);
|
|
SDL_RenderFillRect(NULL);
|
|
//SDL_RenderFill(0,0,0,0 /*255*/,NULL);
|
|
sdl->blittimer--;
|
|
}
|
|
|
|
SDL_LockTexture(sdl->texture_id, NULL, 1, (void **) &surfptr, &pitch);
|
|
|
|
#endif
|
|
// get ready to center the image
|
|
vofs = hofs = 0;
|
|
blitwidth = window->blitwidth;
|
|
blitheight = window->blitheight;
|
|
|
|
// figure out what coordinate system to use for centering - in window mode it's always the
|
|
// SDL surface size. in fullscreen the surface covers all monitors, so center according to
|
|
// the first one only
|
|
if ((window->fullscreen) && (!video_config.switchres))
|
|
{
|
|
ch = window->monitor->center_height;
|
|
cw = window->monitor->center_width;
|
|
}
|
|
else
|
|
{
|
|
ch = window->height;
|
|
cw = window->width;
|
|
}
|
|
|
|
// do not crash if the window's smaller than the blit area
|
|
if (blitheight > ch)
|
|
{
|
|
blitheight = ch;
|
|
}
|
|
else if (video_config.centerv)
|
|
{
|
|
vofs = (ch - window->blitheight) / 2;
|
|
}
|
|
|
|
if (blitwidth > cw)
|
|
{
|
|
blitwidth = cw;
|
|
}
|
|
else if (video_config.centerh)
|
|
{
|
|
hofs = (cw - window->blitwidth) / 2;
|
|
}
|
|
|
|
sdl->last_hofs = hofs;
|
|
sdl->last_vofs = vofs;
|
|
|
|
window->primlist->acquire_lock();
|
|
|
|
// render to it
|
|
if (!sdl->scale_mode->is_yuv)
|
|
{
|
|
int mamewidth, mameheight;
|
|
|
|
if (!sdl->scale_mode->is_scale)
|
|
{
|
|
mamewidth = blitwidth;
|
|
mameheight = blitheight;
|
|
#if !SDL_VERSION_ATLEAST(1,3,0)
|
|
surfptr += ((vofs * pitch) + (hofs * bpp));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
mamewidth = sdl->hw_scale_width;
|
|
mameheight = sdl->hw_scale_height;
|
|
}
|
|
switch (rmask)
|
|
{
|
|
case 0x0000ff00:
|
|
drawsdl_bgra888_draw_primitives(*window->primlist, surfptr, mamewidth, mameheight, pitch / 4);
|
|
break;
|
|
|
|
case 0x00ff0000:
|
|
drawsdl_rgb888_draw_primitives(*window->primlist, surfptr, mamewidth, mameheight, pitch / 4);
|
|
break;
|
|
|
|
case 0x000000ff:
|
|
drawsdl_bgr888_draw_primitives(*window->primlist, surfptr, mamewidth, mameheight, pitch / 4);
|
|
break;
|
|
|
|
case 0xf800:
|
|
drawsdl_rgb565_draw_primitives(*window->primlist, surfptr, mamewidth, mameheight, pitch / 2);
|
|
break;
|
|
|
|
case 0x7c00:
|
|
drawsdl_rgb555_draw_primitives(*window->primlist, surfptr, mamewidth, mameheight, pitch / 2);
|
|
break;
|
|
|
|
default:
|
|
mame_printf_error("SDL: ERROR! Unknown video mode: R=%08X G=%08X B=%08X\n", rmask, gmask, bmask);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
assert (sdl->yuv_bitmap != NULL);
|
|
assert (surfptr != NULL);
|
|
drawsdl_rgb555_draw_primitives(*window->primlist, sdl->yuv_bitmap, sdl->hw_scale_width, sdl->hw_scale_height, sdl->hw_scale_width);
|
|
sdl->scale_mode->yuv_blit((UINT16 *)sdl->yuv_bitmap, sdl, surfptr, pitch);
|
|
}
|
|
|
|
window->primlist->release_lock();
|
|
|
|
// unlock and flip
|
|
#if (!SDL_VERSION_ATLEAST(1,3,0))
|
|
if (SDL_MUSTLOCK(sdl->sdlsurf)) SDL_UnlockSurface(sdl->sdlsurf);
|
|
if (!sdl->scale_mode->is_yuv)
|
|
{
|
|
SDL_Flip(sdl->sdlsurf);
|
|
}
|
|
else
|
|
{
|
|
SDL_Rect r;
|
|
|
|
SDL_UnlockYUVOverlay(sdl->yuvsurf);
|
|
r.x=hofs;
|
|
r.y=vofs;
|
|
r.w=blitwidth;
|
|
r.h=blitheight;
|
|
SDL_DisplayYUVOverlay(sdl->yuvsurf, &r);
|
|
}
|
|
#else
|
|
SDL_UnlockTexture(sdl->texture_id);
|
|
{
|
|
SDL_Rect r;
|
|
|
|
r.x=hofs;
|
|
r.y=vofs;
|
|
r.w=blitwidth;
|
|
r.h=blitheight;
|
|
//printf("blitwidth %d %d - %d %d\n", blitwidth, blitheight, window->width, window->height);
|
|
//SDL_UpdateTexture(sdl->sdltex, NULL, sdl->sdlsurf->pixels, pitch);
|
|
SDL_RenderCopy(sdl->texture_id, NULL, &r);
|
|
SDL_RenderPresent();
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
//============================================================
|
|
// SOFTWARE RENDERING
|
|
//============================================================
|
|
|
|
#define FUNC_PREFIX(x) drawsdl_rgb888_##x
|
|
#define PIXEL_TYPE UINT32
|
|
#define SRCSHIFT_R 0
|
|
#define SRCSHIFT_G 0
|
|
#define SRCSHIFT_B 0
|
|
#define DSTSHIFT_R 16
|
|
#define DSTSHIFT_G 8
|
|
#define DSTSHIFT_B 0
|
|
|
|
#include "rendersw.c"
|
|
|
|
#define FUNC_PREFIX(x) drawsdl_bgr888_##x
|
|
#define PIXEL_TYPE UINT32
|
|
#define SRCSHIFT_R 0
|
|
#define SRCSHIFT_G 0
|
|
#define SRCSHIFT_B 0
|
|
#define DSTSHIFT_R 0
|
|
#define DSTSHIFT_G 8
|
|
#define DSTSHIFT_B 16
|
|
|
|
#include "rendersw.c"
|
|
|
|
#define FUNC_PREFIX(x) drawsdl_bgra888_##x
|
|
#define PIXEL_TYPE UINT32
|
|
#define SRCSHIFT_R 0
|
|
#define SRCSHIFT_G 0
|
|
#define SRCSHIFT_B 0
|
|
#define DSTSHIFT_R 8
|
|
#define DSTSHIFT_G 16
|
|
#define DSTSHIFT_B 24
|
|
|
|
#include "rendersw.c"
|
|
|
|
#define FUNC_PREFIX(x) drawsdl_rgb565_##x
|
|
#define PIXEL_TYPE UINT16
|
|
#define SRCSHIFT_R 3
|
|
#define SRCSHIFT_G 2
|
|
#define SRCSHIFT_B 3
|
|
#define DSTSHIFT_R 11
|
|
#define DSTSHIFT_G 5
|
|
#define DSTSHIFT_B 0
|
|
|
|
#include "rendersw.c"
|
|
|
|
#define FUNC_PREFIX(x) drawsdl_rgb555_##x
|
|
#define PIXEL_TYPE UINT16
|
|
#define SRCSHIFT_R 3
|
|
#define SRCSHIFT_G 3
|
|
#define SRCSHIFT_B 3
|
|
#define DSTSHIFT_R 10
|
|
#define DSTSHIFT_G 5
|
|
#define DSTSHIFT_B 0
|
|
|
|
#include "rendersw.c"
|
|
|
|
//============================================================
|
|
// YUV Blitting
|
|
//============================================================
|
|
|
|
#define CU_CLAMP(v, a, b) ((v < a)? a: ((v > b)? b: v))
|
|
#define RGB2YUV_F(r,g,b,y,u,v) \
|
|
(y) = (0.299*(r) + 0.587*(g) + 0.114*(b) ); \
|
|
(u) = (-0.169*(r) - 0.331*(g) + 0.5*(b) + 128); \
|
|
(v) = (0.5*(r) - 0.419*(g) - 0.081*(b) + 128); \
|
|
(y) = CU_CLAMP(y,0,255); \
|
|
(u) = CU_CLAMP(u,0,255); \
|
|
(v) = CU_CLAMP(v,0,255)
|
|
|
|
#define RGB2YUV(r,g,b,y,u,v) \
|
|
(y) = (( 8453*(r) + 16594*(g) + 3223*(b) + 524288) >> 15); \
|
|
(u) = (( -4878*(r) - 9578*(g) + 14456*(b) + 4210688) >> 15); \
|
|
(v) = (( 14456*(r) - 12105*(g) - 2351*(b) + 4210688) >> 15)
|
|
|
|
#ifdef LSB_FIRST
|
|
#define Y1MASK 0x000000FF
|
|
#define UMASK 0x0000FF00
|
|
#define Y2MASK 0x00FF0000
|
|
#define VMASK 0xFF000000
|
|
#define Y1SHIFT 0
|
|
#define USHIFT 8
|
|
#define Y2SHIFT 16
|
|
#define VSHIFT 24
|
|
#else
|
|
#define Y1MASK 0xFF000000
|
|
#define UMASK 0x00FF0000
|
|
#define Y2MASK 0x0000FF00
|
|
#define VMASK 0x000000FF
|
|
#define Y1SHIFT 24
|
|
#define USHIFT 16
|
|
#define Y2SHIFT 8
|
|
#define VSHIFT 0
|
|
#endif
|
|
|
|
#define YMASK (Y1MASK|Y2MASK)
|
|
#define UVMASK (UMASK|VMASK)
|
|
|
|
static void yuv_lookup_set(sdl_info *sdl, unsigned int pen, unsigned char red,
|
|
unsigned char green, unsigned char blue)
|
|
{
|
|
UINT32 y,u,v;
|
|
|
|
RGB2YUV(red,green,blue,y,u,v);
|
|
|
|
/* Storing this data in YUYV order simplifies using the data for
|
|
YUY2, both with and without smoothing... */
|
|
sdl->yuv_lookup[pen]=(y<<Y1SHIFT)|(u<<USHIFT)|(y<<Y2SHIFT)|(v<<VSHIFT);
|
|
}
|
|
|
|
static void drawsdl_yuv_init(sdl_info *sdl)
|
|
{
|
|
unsigned char r,g,b;
|
|
if (sdl->yuv_lookup == NULL)
|
|
sdl->yuv_lookup = global_alloc_array(UINT32, 65536);
|
|
for (r = 0; r < 32; r++)
|
|
for (g = 0; g < 32; g++)
|
|
for (b = 0; b < 32; b++)
|
|
{
|
|
int idx = (r << 10) | (g << 5) | b;
|
|
yuv_lookup_set(sdl, idx,
|
|
(r << 3) | (r >> 2),
|
|
(g << 3) | (g >> 2),
|
|
(b << 3) | (b >> 2));
|
|
}
|
|
}
|
|
|
|
static void yuv_RGB_to_YV12(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch)
|
|
{
|
|
int x, y;
|
|
UINT8 *dest_y;
|
|
UINT8 *dest_u;
|
|
UINT8 *dest_v;
|
|
UINT16 *src;
|
|
UINT16 *src2;
|
|
UINT32 *lookup = sdl->yuv_lookup;
|
|
UINT8 *pixels[3];
|
|
int u1,v1,y1,u2,v2,y2,u3,v3,y3,u4,v4,y4; /* 12 */
|
|
|
|
pixels[0] = ptr;
|
|
pixels[1] = ptr + pitch * sdl->hw_scale_height;
|
|
pixels[2] = pixels[1] + pitch * sdl->hw_scale_height / 4;
|
|
|
|
for(y=0;y<sdl->hw_scale_height;y+=2)
|
|
{
|
|
src=bitmap + (y * sdl->hw_scale_width) ;
|
|
src2=src + sdl->hw_scale_width;
|
|
|
|
dest_y = pixels[0] + y * pitch;
|
|
dest_v = pixels[1] + (y>>1) * pitch / 2;
|
|
dest_u = pixels[2] + (y>>1) * pitch / 2;
|
|
|
|
for(x=0;x<sdl->hw_scale_width;x+=2)
|
|
{
|
|
v1 = lookup[src[x]];
|
|
y1 = (v1>>Y1SHIFT) & 0xff;
|
|
u1 = (v1>>USHIFT) & 0xff;
|
|
v1 = (v1>>VSHIFT) & 0xff;
|
|
|
|
v2 = lookup[src[x+1]];
|
|
y2 = (v2>>Y1SHIFT) & 0xff;
|
|
u2 = (v2>>USHIFT) & 0xff;
|
|
v2 = (v2>>VSHIFT) & 0xff;
|
|
|
|
v3 = lookup[src2[x]];
|
|
y3 = (v3>>Y1SHIFT) & 0xff;
|
|
u3 = (v3>>USHIFT) & 0xff;
|
|
v3 = (v3>>VSHIFT) & 0xff;
|
|
|
|
v4 = lookup[src2[x+1]];
|
|
y4 = (v4>>Y1SHIFT) & 0xff;
|
|
u4 = (v4>>USHIFT) & 0xff;
|
|
v4 = (v4>>VSHIFT) & 0xff;
|
|
|
|
dest_y[x] = y1;
|
|
dest_y[x+pitch] = y3;
|
|
dest_y[x+1] = y2;
|
|
dest_y[x+pitch+1] = y4;
|
|
|
|
dest_u[x>>1] = (u1+u2+u3+u4)/4;
|
|
dest_v[x>>1] = (v1+v2+v3+v4)/4;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
static void yuv_RGB_to_YV12X2(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch)
|
|
{
|
|
/* this one is used when scale==2 */
|
|
unsigned int x,y;
|
|
UINT16 *dest_y;
|
|
UINT8 *dest_u;
|
|
UINT8 *dest_v;
|
|
UINT16 *src;
|
|
int u1,v1,y1;
|
|
UINT8 *pixels[3];
|
|
|
|
pixels[0] = ptr;
|
|
pixels[1] = ptr + pitch * sdl->hw_scale_height * 2;
|
|
pixels[2] = pixels[1] + pitch * sdl->hw_scale_height / 2;
|
|
|
|
for(y=0;y<sdl->hw_scale_height;y++)
|
|
{
|
|
src = bitmap + (y * sdl->hw_scale_width) ;
|
|
|
|
dest_y = (UINT16 *)(pixels[0] + 2 * y * pitch);
|
|
dest_v = pixels[1] + y * pitch / 2;
|
|
dest_u = pixels[2] + y * pitch / 2;
|
|
for(x=0;x<sdl->hw_scale_width;x++)
|
|
{
|
|
v1 = sdl->yuv_lookup[src[x]];
|
|
y1 = (v1 >> Y1SHIFT) & 0xff;
|
|
u1 = (v1 >> USHIFT) & 0xff;
|
|
v1 = (v1 >> VSHIFT) & 0xff;
|
|
|
|
dest_y[x + pitch/2] = y1 << 8 | y1;
|
|
dest_y[x] = y1 << 8 | y1;
|
|
dest_u[x] = u1;
|
|
dest_v[x] = v1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void yuv_RGB_to_YUY2(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch)
|
|
{
|
|
/* this one is used when scale==2 */
|
|
unsigned int y;
|
|
UINT32 *dest;
|
|
UINT16 *src;
|
|
UINT16 *end;
|
|
UINT32 p1,p2,uv;
|
|
UINT32 *lookup = sdl->yuv_lookup;
|
|
int yuv_pitch = pitch/4;
|
|
|
|
for(y=0;y<sdl->hw_scale_height;y++)
|
|
{
|
|
src=bitmap + (y * sdl->hw_scale_width) ;
|
|
end=src+sdl->hw_scale_width;
|
|
|
|
dest = (UINT32 *) ptr;
|
|
dest += y * yuv_pitch;
|
|
for(; src<end; src+=2)
|
|
{
|
|
p1 = lookup[src[0]];
|
|
p2 = lookup[src[1]];
|
|
uv = (p1&UVMASK)>>1;
|
|
uv += (p2&UVMASK)>>1;
|
|
*dest++ = (p1&Y1MASK)|(p2&Y2MASK)|(uv&UVMASK);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void yuv_RGB_to_YUY2X2(UINT16 *bitmap, sdl_info *sdl, UINT8 *ptr, int pitch)
|
|
{
|
|
/* this one is used when scale==2 */
|
|
unsigned int y;
|
|
UINT32 *dest;
|
|
UINT16 *src;
|
|
UINT16 *end;
|
|
UINT32 *lookup = sdl->yuv_lookup;
|
|
int yuv_pitch = pitch / 4;
|
|
|
|
for(y=0;y<sdl->hw_scale_height;y++)
|
|
{
|
|
src=bitmap + (y * sdl->hw_scale_width) ;
|
|
end=src+sdl->hw_scale_width;
|
|
|
|
dest = (UINT32 *) ptr;
|
|
dest += (y * yuv_pitch);
|
|
for(; src<end; src++)
|
|
{
|
|
dest[0] = lookup[src[0]];
|
|
dest++;
|
|
}
|
|
}
|
|
}
|