diff options
author | Ryan Holtz <rholtz@batcountryentertainment.com> | 2011-05-30 21:10:23 +0000 |
---|---|---|
committer | Ryan Holtz <rholtz@batcountryentertainment.com> | 2011-05-30 21:10:23 +0000 |
commit | 796e691522ba5c47fc0610da4f557514563f85b9 (patch) | |
tree | 961683497fd1e4d7369da812c579572f880b188a /src/osd/windows/drawd3d.c | |
parent | e532e74a8a869af6da71222657f39684210b624e (diff) |
HLSL Updates: [Ryan Holtz, Bat Country Entertainment, austere, SoltanGris42]
- Added the ability to render screenshots at arbitrary resolutions.
- Added the ability to record AVI videos (albeit with no audio) at arbitrary resolutions.
- Added a 43-tap-wide FIR-based NTSC filter with tunable Y, I and Q frequency response.
- Updated scanlines to have a user-tunable pixel-height ratio in addition to the current screen-height ratio.
- Fixed a VRAM leak that was causing many dynamic-resolution drivers to run out of memory mid-run.
Diffstat (limited to 'src/osd/windows/drawd3d.c')
-rw-r--r-- | src/osd/windows/drawd3d.c | 1335 |
1 files changed, 1164 insertions, 171 deletions
diff --git a/src/osd/windows/drawd3d.c b/src/osd/windows/drawd3d.c index 47af7112138..d2bf7ed4a64 100644 --- a/src/osd/windows/drawd3d.c +++ b/src/osd/windows/drawd3d.c @@ -54,6 +54,7 @@ #include <mmsystem.h> #include <d3d9.h> #include <d3dx9.h> +#include <math.h> #undef interface // MAME headers @@ -63,6 +64,8 @@ #include "rendutil.h" #include "options.h" #include "emuopts.h" +#include "aviio.h" +#include "png.h" // MAMEOS headers #include "d3dintf.h" @@ -116,6 +119,7 @@ typedef struct _texture_info texture_info; struct _texture_info { texture_info * next; // next texture in the list + texture_info * prev; // prev texture in the list UINT32 hash; // hash value for the texture UINT32 flags; // rendering flags render_texinfo texinfo; // copy of the texture info @@ -130,19 +134,8 @@ struct _texture_info int cur_frame; // what is our current frame? d3d_texture * d3dtex; // Direct3D texture pointer d3d_surface * d3dsurface; // Direct3D offscreen plain surface pointer - d3d_surface * d3dtarget0; // Direct3D render target surface pointer (pass 0, if necessary) - d3d_surface * d3dtarget1; // Direct3D render target surface pointer (pass 1, if necessary) - d3d_surface * d3dtarget2; // Direct3D render target surface pointer (pass 2, if necessary) - d3d_surface * d3dtarget3; // Direct3D render target surface pointer (pass 3, if necessary) - d3d_surface * d3dtarget4; // Direct3D render target surface pointer (pass 4, if necessary) - d3d_surface * d3dsmalltarget0; // Direct3D render target surface pointer (small pass 0, if necessary) - d3d_texture * d3dtexture0; // Direct3D render target texture pointer (pass 0, if necessary) - d3d_texture * d3dtexture1; // Direct3D render target texture pointer (pass 1, if necessary) - d3d_texture * d3dtexture2; // Direct3D render target texture pointer (pass 2, if necessary) - d3d_texture * d3dtexture3; // Direct3D render target texture pointer (pass 3, if necessary) - d3d_texture * d3dtexture4; // Direct3D render target texture pointer (pass 4, if necessary) - d3d_texture * d3dsmalltexture0; // Direct3D render target texture pointer (small pass 0, if necessary) d3d_texture * d3dfinaltex; // Direct3D final (post-scaled) texture + int target_index; // Direct3D target index }; @@ -169,7 +162,6 @@ struct _d3d_vertex float u0, v0; // texture stage 0 coordinates }; - /* d3d_options is the information about runtime-mutable Direct3D options */ typedef struct _d3d_options d3d_options; struct _d3d_options @@ -183,6 +175,7 @@ struct _d3d_options float screen_pincushion; float screen_scanline_alpha; float screen_scanline_scale; + float screen_scanline_height; float screen_scanline_bright_scale; float screen_scanline_bright_offset; float screen_scanline_offset; @@ -227,6 +220,88 @@ struct _d3d_options float screen_saturation; }; +static d3d_options g_d3d_hlsl_presets[6] = +{ + { 0.00f, 1, 1, 0.1875f, 0.1875f, + 0.03f, 0.03f, + 0.25f, 1.0f, 1.0f, 0.6f, 0.0f, + 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, + 1.1f, 1.1f, 1.1f, + 0.9f, 0.9f, 0.9f, + 0.05f, 0.05f, 0.05f, + 0.45f, 0.45f, 0.45f, + 1.4f }, + { 0.15f, 512, 384, 0.1875f, 0.1875f, + 0.03f, 0.03f, + 0.25f, 1.0f, 1.0f, 0.6f, 0.0f, + 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, + 1.1f, 1.1f, 1.1f, + 0.9f, 0.9f, 0.9f, + 0.05f, 0.05f, 0.05f, + 0.45f, 0.45f, 0.45f, + 1.4f }, + { 0.15f, 512, 384, 0.1875f, 0.1875f, + 0.03f, 0.03f, + 0.25f, 1.0f, 1.0f, 0.6f, 0.0f, + 0.0f, 0.0f, + 0.4f, 0.1f, 0.0, 0.0f,-0.25f,-0.3f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, + 1.1f, 1.1f, 1.1f, + 0.9f, 0.9f, 0.9f, + 0.05f, 0.05f, 0.05f, + 0.45f, 0.45f, 0.45f, + 1.4f }, + { 0.15f, 512, 384, 0.1875f, 0.1875f, + 0.03f, 0.03f, + 0.25f, 1.0f, 1.0f, 0.6f, 0.0f, + 0.0f, 0.0f, + 0.4f, 0.1f, 0.0, 0.0f,-0.25f,-0.3f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 0.05f, 0.05f, 0.05f, + 0.45f, 0.45f, 0.45f, + 1.0f }, + { 0.15f, 512, 384, 0.1875f, 0.1875f, + 0.03f, 0.03f, + 0.25f, 1.0f, 1.0f, 0.6f, 0.0f, + 0.0f, 0.0f, + 0.4f, 0.1f, 0.0, 0.0f,-0.25f,-0.3f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 0.05f, 0.05f, 0.05f, + 0.45f, 0.45f, 0.45f, + 0.8f }, + { 0.15f, 512, 384, 0.1875f, 0.1875f, + 0.03f, 0.03f, + 0.25f, 1.0f, 1.0f, 0.6f, 0.0f, + 0.0f, 0.0f, + 0.4f, 0.1f, 0.0, 0.0f,-0.25f,-0.3f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.7f, 0.3f, 0.0f, 0.0f, 0.7f, 0.3f, 0.3f, 0.0f, 0.7f, + 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 0.05f, 0.05f, 0.05f, + 0.45f, 0.45f, 0.45f, + 0.8f } +}; + /* d3d_info is the information about Direct3D for the current screen */ typedef struct _d3d_info d3d_info; struct _d3d_info @@ -249,6 +324,7 @@ struct _d3d_info int numverts; // number of accumulated vertices d3d_effect * effect; // pointer to the current effect object + d3d_effect * prescale_effect; // pointer to the current prescale-effect object d3d_effect * post_effect; // pointer to the current post-effect object d3d_effect * pincushion_effect; // pointer to the current pincushion-effect object d3d_effect * focus_effect; // pointer to the current focus-effect object @@ -291,16 +367,54 @@ struct _d3d_info bitmap_t * default_bitmap; // experimental: default bitmap texture_info * default_texture; // experimental: default texture - bool hlsl_enable; // experimental: HLSL enable flag - bool yiq_enable; // experimental: HLSL YIQ-convolution flag - d3d_surface * last_d3dtarget[9]; // Direct3D render target surface pointer for each screen's previous frame - d3d_texture * last_d3dtexture[9]; // Direct3D render target texture pointer for each screen's previous frame - float oversample_x; // experimental: render target oversampling factor (width) for shader prettification - float oversample_y; // experimental: render target oversampling factor (height) for shader prettification - bitmap_t * shadow_bitmap; // experimental: shadow mask bitmap for post-processing shader - texture_info * shadow_texture; // experimental: shadow mask texture for post-processing shader + bool hlsl_enable; // HLSL enable flag + bool yiq_enable; // HLSL YIQ-convolution flag + bool hlsl_prescale; // HLSL prescale enable flag + int hlsl_prescale_size; // HLSL prescale size + int hlsl_preset; // HLSL preset, if relevant + float oversample_x; // render target oversampling factor (width) for shader prettification + float oversample_y; // render target oversampling factor (height) for shader prettification + bitmap_t * shadow_bitmap; // shadow mask bitmap for post-processing shader + texture_info * shadow_texture; // shadow mask texture for post-processing shader int registered_targets; // Number of registered HLSL targets (i.e., screens) d3d_options * hlsl_options; // HLSL uniforms + avi_file * hlsl_avi_file; // HLSL AVI file + bitmap_t * hlsl_avi_snap; // HLSL AVI snapshot + int hlsl_avi_frame; // HLSL AVI frame + attotime hlsl_avi_frame_period; // HLSL AVI frame period + attotime hlsl_avi_next_frame_time; // HLSL AVI next frame time + d3d_surface * hlsl_avi_copy_surface; // HLSL AVI destination surface in system memory + d3d_texture * hlsl_avi_copy_texture; // HLSL AVI destination texture in system memory + d3d_surface * hlsl_avi_final_target; // HLSL AVI upscaled surface + d3d_texture * hlsl_avi_final_texture; // HLSL AVI upscaled texture + bool hlsl_render_snap; // whether or not to take HLSL post-render snapshot + bool hlsl_snap_rendered; // whether we just rendered our HLSL post-render shot or not + d3d_surface * hlsl_snap_copy_target; // HLSL snapshot destination surface in system memory + d3d_texture * hlsl_snap_copy_texture; // HLSL snapshot destination surface in system memory + d3d_surface * hlsl_snap_target; // HLSL snapshot upscaled surface + d3d_texture * hlsl_snap_texture; // HLSL snapshot upscaled texture + int hlsl_snap_width; // HLSL snapshot width + int hlsl_snap_height; // HLSL snapshot height + + // HLSL render targets + int target_use_count[9]; // Whether or not a target has been used yet + texture_info * target_in_use[9]; // Target texture that is currently in use + d3d_surface * last_hlsltarget[9]; // HLSL render target surface pointer for each screen's previous frame + d3d_texture * last_hlsltexture[9]; // HLSL render target texture pointer for each screen's previous frame + d3d_surface * hlslprescaletarget0[9]; // Direct3D render target surface pointer (prescale, if necessary) + d3d_surface * hlsltarget0[9]; // HLSL render target surface pointer (pass 0, if necessary) + d3d_surface * hlsltarget1[9]; // HLSL render target surface pointer (pass 1, if necessary) + d3d_surface * hlsltarget2[9]; // HLSL render target surface pointer (pass 2, if necessary) + d3d_surface * hlsltarget3[9]; // HLSL render target surface pointer (pass 3, if necessary) + d3d_surface * hlsltarget4[9]; // HLSL render target surface pointer (pass 4, if necessary) + d3d_surface * hlslsmalltarget0[9]; // HLSL render target surface pointer (small pass 0, if necessary) + d3d_texture * hlslprescaletexture0[9]; // HLSL render target surface pointer (prescale, if necessary) + d3d_texture * hlsltexture0[9]; // HLSL render target texture pointer (pass 0, if necessary) + d3d_texture * hlsltexture1[9]; // HLSL render target texture pointer (pass 1, if necessary) + d3d_texture * hlsltexture2[9]; // HLSL render target texture pointer (pass 2, if necessary) + d3d_texture * hlsltexture3[9]; // HLSL render target texture pointer (pass 3, if necessary) + d3d_texture * hlsltexture4[9]; // HLSL render target texture pointer (pass 4, if necessary) + d3d_texture * hlslsmalltexture0[9]; // HLSL render target texture pointer (small pass 0, if necessary) }; @@ -422,6 +536,11 @@ static INT32 slider_scanline_scale(running_machine &machine, void *arg, astring return slider_set(&(((d3d_info*)arg)->hlsl_options->screen_scanline_scale), 0.05f, "%2.2f", string, newval); } +static INT32 slider_scanline_height(running_machine &machine, void *arg, astring *string, INT32 newval) +{ + return slider_set(&(((d3d_info*)arg)->hlsl_options->screen_scanline_height), 0.05f, "%2.2f", string, newval); +} + static INT32 slider_scanline_bright_scale(running_machine &machine, void *arg, astring *string, INT32 newval) { return slider_set(&(((d3d_info*)arg)->hlsl_options->screen_scanline_bright_scale), 0.05f, "%2.2f", string, newval); @@ -656,7 +775,8 @@ static slider_state *init_slider_list(d3d_info *d3d) *tailptr = slider_alloc(d3d->window->machine(), "Screen Curvature", 0, 0, 100, 1, slider_curvature, (void*)d3d); tailptr = &(*tailptr)->next; *tailptr = slider_alloc(d3d->window->machine(), "Image Pincushion", 0, 0, 100, 1, slider_pincushion, (void*)d3d); tailptr = &(*tailptr)->next; *tailptr = slider_alloc(d3d->window->machine(), "Scanline Darkness", 0, 0, 100, 1, slider_scanline_alpha, (void*)d3d); tailptr = &(*tailptr)->next; - *tailptr = slider_alloc(d3d->window->machine(), "Scanline Size", 1, 20, 80, 1, slider_scanline_scale, (void*)d3d); tailptr = &(*tailptr)->next; + *tailptr = slider_alloc(d3d->window->machine(), "Scanline Screen Height", 1, 20, 80, 1, slider_scanline_scale, (void*)d3d); tailptr = &(*tailptr)->next; + *tailptr = slider_alloc(d3d->window->machine(), "Scanline Indiv. Height", 1, 10, 80, 1, slider_scanline_height, (void*)d3d); tailptr = &(*tailptr)->next; *tailptr = slider_alloc(d3d->window->machine(), "Scanline Brightness", 0, 20, 40, 1, slider_scanline_bright_scale, (void*)d3d); tailptr = &(*tailptr)->next; *tailptr = slider_alloc(d3d->window->machine(), "Scanline Brightness Overdrive", 0, 12, 20, 1, slider_scanline_bright_offset, (void*)d3d); tailptr = &(*tailptr)->next; *tailptr = slider_alloc(d3d->window->machine(), "Scanline Jitter", 0, 0, 40, 1, slider_scanline_offset, (void*)d3d); tailptr = &(*tailptr)->next; @@ -939,6 +1059,8 @@ static void drawd3d_exit(void); static int drawd3d_window_init(win_window_info *window); static void drawd3d_window_destroy(win_window_info *window); static render_primitive_list *drawd3d_window_get_primitives(win_window_info *window); +static void drawd3d_window_save(win_window_info *window); +static void drawd3d_window_record(win_window_info *window); static int drawd3d_window_draw(win_window_info *window, HDC dc, int update); // devices @@ -972,6 +1094,12 @@ static void texture_prescale(d3d_info *d3d, texture_info *texture); static texture_info *texture_find(d3d_info *d3d, const render_primitive *prim); static void texture_update(d3d_info *d3d, const render_primitive *prim); +// logging +static void end_hlsl_avi_recording(d3d_info *d3d); +static void hlsl_render_snapshot(d3d_info *d3d, d3d_surface *surface); +static void begin_hlsl_avi_recording(d3d_info *d3d, const char *name); +static void hlsl_record_texture(d3d_info *d3d, d3d_surface *surface); +static file_error open_next(d3d_info *d3d, emu_file &file, const char *extension, int idx); //============================================================ @@ -1005,6 +1133,8 @@ int drawd3d_init(running_machine &machine, win_draw_callbacks *callbacks) callbacks->window_init = drawd3d_window_init; callbacks->window_get_primitives = drawd3d_window_get_primitives; callbacks->window_draw = drawd3d_window_draw; + callbacks->window_save = drawd3d_window_save; + callbacks->window_record = drawd3d_window_record; callbacks->window_destroy = drawd3d_window_destroy; return 0; } @@ -1035,6 +1165,7 @@ static int drawd3d_window_init(win_window_info *window) d3d = global_alloc_clear(d3d_info); window->drawdata = d3d; d3d->window = window; + d3d->hlsl_options = NULL; // experimental: load a PNG to use for vector rendering; it is treated // as a brightness map @@ -1070,6 +1201,61 @@ error: //============================================================ +// drawd3d_window_save +//============================================================ + +static void drawd3d_window_save(win_window_info *window) +{ + d3d_info *d3d = (d3d_info *)window->drawdata; + + if (!d3d->hlsl_enable || !d3dintf->post_fx_available) + return; + + HRESULT result = (*d3dintf->device.create_texture)(d3d->device, d3d->hlsl_snap_width, d3d->hlsl_snap_height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &d3d->hlsl_snap_copy_texture); + if (result != D3D_OK) + { + mame_printf_verbose("Direct3D: Unable to init system-memory target for HLSL snapshot (%08x), bailing\n", (UINT32)result); + return; + } + (*d3dintf->texture.get_surface_level)(d3d->hlsl_snap_copy_texture, 0, &d3d->hlsl_snap_copy_target); + + result = (*d3dintf->device.create_texture)(d3d->device, d3d->hlsl_snap_width, d3d->hlsl_snap_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsl_snap_texture); + if (result != D3D_OK) + { + mame_printf_verbose("Direct3D: Unable to init video-memory target for HLSL snapshot (%08x), bailing\n", (UINT32)result); + return; + } + (*d3dintf->texture.get_surface_level)(d3d->hlsl_snap_texture, 0, &d3d->hlsl_snap_target); + + d3d->hlsl_render_snap = true; + d3d->hlsl_snap_rendered = false; +} + +static void drawd3d_window_record(win_window_info *window) +{ + d3d_info *d3d = (d3d_info *)window->drawdata; + + if (!d3d->hlsl_enable || !d3dintf->post_fx_available) + return; + + windows_options &options = downcast<windows_options &>(window->machine().options()); + const char *filename = options.d3d_hlsl_write(); + + if(d3d->hlsl_avi_file != NULL) + { + end_hlsl_avi_recording(d3d); + } + else + { + if (filename[0] != 0) + { + begin_hlsl_avi_recording(d3d, filename); + } + } +} + + +//============================================================ // drawd3d_window_destroy //============================================================ @@ -1077,6 +1263,8 @@ static void drawd3d_window_destroy(win_window_info *window) { d3d_info *d3d = (d3d_info *)window->drawdata; + end_hlsl_avi_recording(d3d); + // skip if nothing if (d3d == NULL) return; @@ -1164,6 +1352,8 @@ mtlog_add("drawd3d_window_draw: begin"); result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); + hlsl_record_texture(d3d, d3d->hlsl_avi_final_target); + // first update any textures window->primlist->acquire_lock(); for (prim = window->primlist->first(); prim != NULL; prim = prim->next()) @@ -1218,6 +1408,11 @@ mtlog_add("drawd3d_window_draw: present begin"); mtlog_add("drawd3d_window_draw: present end"); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device present call\n", (int)result); + if(d3d->hlsl_render_snap && d3d->hlsl_snap_rendered) + { + hlsl_render_snapshot(d3d, d3d->hlsl_snap_target); + } + return 0; } @@ -1326,6 +1521,11 @@ try_again: d3d->create_error_count = 0; mame_printf_verbose("Direct3D: Device created at %dx%d\n", d3d->width, d3d->height); + d3d->oversample_x = downcast<windows_options &>(d3d->window->machine().options()).screen_oversample_x(); + d3d->oversample_y = downcast<windows_options &>(d3d->window->machine().options()).screen_oversample_y(); + d3d->hlsl_snap_width = downcast<windows_options &>(d3d->window->machine().options()).d3d_snap_width(); + d3d->hlsl_snap_height = downcast<windows_options &>(d3d->window->machine().options()).d3d_snap_height(); + // set the max texture size window->target->set_max_texture_size(d3d->texture_max_width, d3d->texture_max_height); mame_printf_verbose("Direct3D: Max texture size = %dx%d\n", (int)d3d->texture_max_width, (int)d3d->texture_max_height); @@ -1362,6 +1562,7 @@ try_again: const char *fx_dir = downcast<windows_options &>(window->machine().options()).screen_post_fx_dir(); char primary_name_cstr[1024]; char post_name_cstr[1024]; + char prescale_name_cstr[1024]; char pincushion_name_cstr[1024]; char phosphor_name_cstr[1024]; char focus_name_cstr[1024]; @@ -1376,6 +1577,9 @@ try_again: sprintf(post_name_cstr, "%s\\post.fx", fx_dir); TCHAR *post_name = tstring_from_utf8(post_name_cstr); + sprintf(prescale_name_cstr, "%s\\prescale.fx", fx_dir); + TCHAR *prescale_name = tstring_from_utf8(prescale_name_cstr); + sprintf(pincushion_name_cstr, "%s\\pincushion.fx", fx_dir); TCHAR *pincushion_name = tstring_from_utf8(pincushion_name_cstr); @@ -1401,7 +1605,7 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, primary_name, &d3d->effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load primary.fx\n"); + printf("Direct3D: Unable to load primary.fx\n"); return 1; } @@ -1409,7 +1613,15 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, post_name, &d3d->post_effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load post.fx\n"); + printf("Direct3D: Unable to load post.fx\n"); + return 1; + } + + // create the prescaling shader + result = (*d3dintf->device.create_effect)(d3d->device, prescale_name, &d3d->prescale_effect); + if(result != D3D_OK) + { + printf("Direct3D: Unable to load prescale.fx\n"); return 1; } @@ -1417,7 +1629,7 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, pincushion_name, &d3d->pincushion_effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load pincushion.fx\n"); + printf("Direct3D: Unable to load pincushion.fx\n"); return 1; } @@ -1425,7 +1637,7 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, phosphor_name, &d3d->phosphor_effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load phosphor.fx\n"); + printf("Direct3D: Unable to load phosphor.fx\n"); return 1; } @@ -1433,7 +1645,7 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, focus_name, &d3d->focus_effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load focus.fx\n"); + printf("Direct3D: Unable to load focus.fx\n"); return 1; } @@ -1441,7 +1653,7 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, deconverge_name, &d3d->deconverge_effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load deconverge.fx\n"); + printf("Direct3D: Unable to load deconverge.fx\n"); return 1; } @@ -1449,7 +1661,7 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, color_name, &d3d->color_effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load color.fx\n"); + printf("Direct3D: Unable to load color.fx\n"); return 1; } @@ -1457,7 +1669,7 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, yiq_encode_name, &d3d->yiq_encode_effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load yiq_encode.fx\n"); + printf("Direct3D: Unable to load yiq_encode.fx\n"); return 1; } @@ -1465,7 +1677,7 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, yiq_decode_name, &d3d->yiq_decode_effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load yiq_decode.fx\n"); + printf("Direct3D: Unable to load yiq_decode.fx\n"); return 1; } @@ -1473,6 +1685,8 @@ try_again: osd_free(primary_name); if (post_name) osd_free(post_name); + if (prescale_name) + osd_free(prescale_name); if (pincushion_name) osd_free(pincushion_name); if (phosphor_name) @@ -1590,6 +1804,22 @@ static int device_create_resources(d3d_info *d3d) // experimental: initialize some more things if we're using HLSL if(d3d->hlsl_enable && d3dintf->post_fx_available) { + result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &d3d->hlsl_avi_copy_texture); + if (result != D3D_OK) + { + mame_printf_verbose("Direct3D: Unable to init system-memory target for HLSL AVI dumping (%08x)\n", (UINT32)result); + return 1; + } + (*d3dintf->texture.get_surface_level)(d3d->hlsl_avi_copy_texture, 0, &d3d->hlsl_avi_copy_surface); + + result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsl_avi_final_texture); + if (result != D3D_OK) + { + mame_printf_verbose("Direct3D: Unable to init video-memory target for HLSL AVI dumping (%08x)\n", (UINT32)result); + return 1; + } + (*d3dintf->texture.get_surface_level)(d3d->hlsl_avi_final_texture, 0, &d3d->hlsl_avi_final_target); + windows_options &options = downcast<windows_options &>(d3d->window->machine().options()); // experimental: load a PNG to use for vector rendering; it is treated @@ -1615,57 +1845,66 @@ static int device_create_resources(d3d_info *d3d) } d3d->hlsl_options = (d3d_options*)global_alloc_clear(d3d_options); - d3d->hlsl_options->screen_shadow_mask_alpha = options.screen_shadow_mask_alpha(); - d3d->hlsl_options->screen_shadow_mask_count_x = options.screen_shadow_mask_count_x(); - d3d->hlsl_options->screen_shadow_mask_count_y = options.screen_shadow_mask_count_y(); - d3d->hlsl_options->screen_shadow_mask_u_size = options.screen_shadow_mask_u_size(); - d3d->hlsl_options->screen_shadow_mask_v_size = options.screen_shadow_mask_v_size(); - d3d->hlsl_options->screen_curvature = options.screen_curvature(); - d3d->hlsl_options->screen_pincushion = options.screen_pincushion(); - d3d->hlsl_options->screen_scanline_alpha = options.screen_scanline_amount(); - d3d->hlsl_options->screen_scanline_scale = options.screen_scanline_scale(); - d3d->hlsl_options->screen_scanline_bright_scale = options.screen_scanline_bright_scale(); - d3d->hlsl_options->screen_scanline_bright_offset = options.screen_scanline_bright_offset(); - d3d->hlsl_options->screen_scanline_offset = options.screen_scanline_offset(); - d3d->hlsl_options->screen_defocus_x = options.screen_defocus_x(); - d3d->hlsl_options->screen_defocus_y = options.screen_defocus_y(); - d3d->hlsl_options->screen_red_converge_x = options.screen_red_converge_x(); - d3d->hlsl_options->screen_red_converge_y = options.screen_red_converge_y(); - d3d->hlsl_options->screen_green_converge_x = options.screen_green_converge_x(); - d3d->hlsl_options->screen_green_converge_y = options.screen_green_converge_y(); - d3d->hlsl_options->screen_blue_converge_x = options.screen_blue_converge_x(); - d3d->hlsl_options->screen_blue_converge_y = options.screen_blue_converge_y(); - d3d->hlsl_options->screen_red_radial_converge_x = options.screen_red_radial_converge_x(); - d3d->hlsl_options->screen_red_radial_converge_y = options.screen_red_radial_converge_y(); - d3d->hlsl_options->screen_green_radial_converge_x = options.screen_green_radial_converge_x(); - d3d->hlsl_options->screen_green_radial_converge_y = options.screen_green_radial_converge_y(); - d3d->hlsl_options->screen_blue_radial_converge_x = options.screen_blue_radial_converge_x(); - d3d->hlsl_options->screen_blue_radial_converge_y = options.screen_blue_radial_converge_y(); - d3d->hlsl_options->screen_red_from_red = options.screen_red_from_red(); - d3d->hlsl_options->screen_red_from_green = options.screen_red_from_green(); - d3d->hlsl_options->screen_red_from_blue = options.screen_red_from_blue(); - d3d->hlsl_options->screen_green_from_red = options.screen_green_from_red(); - d3d->hlsl_options->screen_green_from_green = options.screen_green_from_green(); - d3d->hlsl_options->screen_green_from_blue = options.screen_green_from_blue(); - d3d->hlsl_options->screen_blue_from_red = options.screen_blue_from_red(); - d3d->hlsl_options->screen_blue_from_green = options.screen_blue_from_green(); - d3d->hlsl_options->screen_blue_from_blue = options.screen_blue_from_blue(); - d3d->hlsl_options->screen_red_offset = options.screen_red_offset(); - d3d->hlsl_options->screen_green_offset = options.screen_green_offset(); - d3d->hlsl_options->screen_blue_offset = options.screen_blue_offset(); - d3d->hlsl_options->screen_red_scale = options.screen_red_scale(); - d3d->hlsl_options->screen_green_scale = options.screen_green_scale(); - d3d->hlsl_options->screen_blue_scale = options.screen_blue_scale(); - d3d->hlsl_options->screen_red_power = options.screen_red_power(); - d3d->hlsl_options->screen_green_power = options.screen_green_power(); - d3d->hlsl_options->screen_blue_power = options.screen_blue_power(); - d3d->hlsl_options->screen_red_floor = options.screen_red_floor(); - d3d->hlsl_options->screen_green_floor = options.screen_green_floor(); - d3d->hlsl_options->screen_blue_floor = options.screen_blue_floor(); - d3d->hlsl_options->screen_red_phosphor_life = options.screen_red_phosphor(); - d3d->hlsl_options->screen_green_phosphor_life = options.screen_green_phosphor(); - d3d->hlsl_options->screen_blue_phosphor_life = options.screen_blue_phosphor(); - d3d->hlsl_options->screen_saturation = options.screen_saturation(); + + if(d3d->hlsl_preset == -1) + { + d3d->hlsl_options->screen_shadow_mask_alpha = options.screen_shadow_mask_alpha(); + d3d->hlsl_options->screen_shadow_mask_count_x = options.screen_shadow_mask_count_x(); + d3d->hlsl_options->screen_shadow_mask_count_y = options.screen_shadow_mask_count_y(); + d3d->hlsl_options->screen_shadow_mask_u_size = options.screen_shadow_mask_u_size(); + d3d->hlsl_options->screen_shadow_mask_v_size = options.screen_shadow_mask_v_size(); + d3d->hlsl_options->screen_curvature = options.screen_curvature(); + d3d->hlsl_options->screen_pincushion = options.screen_pincushion(); + d3d->hlsl_options->screen_scanline_alpha = options.screen_scanline_amount(); + d3d->hlsl_options->screen_scanline_scale = options.screen_scanline_scale(); + d3d->hlsl_options->screen_scanline_height = options.screen_scanline_height(); + d3d->hlsl_options->screen_scanline_bright_scale = options.screen_scanline_bright_scale(); + d3d->hlsl_options->screen_scanline_bright_offset = options.screen_scanline_bright_offset(); + d3d->hlsl_options->screen_scanline_offset = options.screen_scanline_offset(); + d3d->hlsl_options->screen_defocus_x = options.screen_defocus_x(); + d3d->hlsl_options->screen_defocus_y = options.screen_defocus_y(); + d3d->hlsl_options->screen_red_converge_x = options.screen_red_converge_x(); + d3d->hlsl_options->screen_red_converge_y = options.screen_red_converge_y(); + d3d->hlsl_options->screen_green_converge_x = options.screen_green_converge_x(); + d3d->hlsl_options->screen_green_converge_y = options.screen_green_converge_y(); + d3d->hlsl_options->screen_blue_converge_x = options.screen_blue_converge_x(); + d3d->hlsl_options->screen_blue_converge_y = options.screen_blue_converge_y(); + d3d->hlsl_options->screen_red_radial_converge_x = options.screen_red_radial_converge_x(); + d3d->hlsl_options->screen_red_radial_converge_y = options.screen_red_radial_converge_y(); + d3d->hlsl_options->screen_green_radial_converge_x = options.screen_green_radial_converge_x(); + d3d->hlsl_options->screen_green_radial_converge_y = options.screen_green_radial_converge_y(); + d3d->hlsl_options->screen_blue_radial_converge_x = options.screen_blue_radial_converge_x(); + d3d->hlsl_options->screen_blue_radial_converge_y = options.screen_blue_radial_converge_y(); + d3d->hlsl_options->screen_red_from_red = options.screen_red_from_red(); + d3d->hlsl_options->screen_red_from_green = options.screen_red_from_green(); + d3d->hlsl_options->screen_red_from_blue = options.screen_red_from_blue(); + d3d->hlsl_options->screen_green_from_red = options.screen_green_from_red(); + d3d->hlsl_options->screen_green_from_green = options.screen_green_from_green(); + d3d->hlsl_options->screen_green_from_blue = options.screen_green_from_blue(); + d3d->hlsl_options->screen_blue_from_red = options.screen_blue_from_red(); + d3d->hlsl_options->screen_blue_from_green = options.screen_blue_from_green(); + d3d->hlsl_options->screen_blue_from_blue = options.screen_blue_from_blue(); + d3d->hlsl_options->screen_red_offset = options.screen_red_offset(); + d3d->hlsl_options->screen_green_offset = options.screen_green_offset(); + d3d->hlsl_options->screen_blue_offset = options.screen_blue_offset(); + d3d->hlsl_options->screen_red_scale = options.screen_red_scale(); + d3d->hlsl_options->screen_green_scale = options.screen_green_scale(); + d3d->hlsl_options->screen_blue_scale = options.screen_blue_scale(); + d3d->hlsl_options->screen_red_power = options.screen_red_power(); + d3d->hlsl_options->screen_green_power = options.screen_green_power(); + d3d->hlsl_options->screen_blue_power = options.screen_blue_power(); + d3d->hlsl_options->screen_red_floor = options.screen_red_floor(); + d3d->hlsl_options->screen_green_floor = options.screen_green_floor(); + d3d->hlsl_options->screen_blue_floor = options.screen_blue_floor(); + d3d->hlsl_options->screen_red_phosphor_life = options.screen_red_phosphor(); + d3d->hlsl_options->screen_green_phosphor_life = options.screen_green_phosphor(); + d3d->hlsl_options->screen_blue_phosphor_life = options.screen_blue_phosphor(); + d3d->hlsl_options->screen_saturation = options.screen_saturation(); + } + else + { + d3d->hlsl_options = &g_d3d_hlsl_presets[d3d->hlsl_preset]; + } slider_list = init_slider_list(d3d); } @@ -1713,30 +1952,6 @@ static void device_delete_resources(d3d_info *d3d) (*d3dintf->texture.release)(tex->d3dtex); if (tex->d3dsurface != NULL) (*d3dintf->surface.release)(tex->d3dsurface); - if (tex->d3dtexture0 != NULL) - (*d3dintf->texture.release)(tex->d3dtexture0); - if (tex->d3dtexture1 != NULL) - (*d3dintf->texture.release)(tex->d3dtexture1); - if (tex->d3dtexture2 != NULL) - (*d3dintf->texture.release)(tex->d3dtexture2); - if (tex->d3dtexture3 != NULL) - (*d3dintf->texture.release)(tex->d3dtexture3); - if (tex->d3dtexture4 != NULL) - (*d3dintf->texture.release)(tex->d3dtexture4); - if (tex->d3dsmalltexture0 != NULL) - (*d3dintf->texture.release)(tex->d3dsmalltexture0); - if (tex->d3dtarget0 != NULL) - (*d3dintf->surface.release)(tex->d3dtarget0); - if (tex->d3dtarget1 != NULL) - (*d3dintf->surface.release)(tex->d3dtarget1); - if (tex->d3dtarget2 != NULL) - (*d3dintf->surface.release)(tex->d3dtarget2); - if (tex->d3dtarget3 != NULL) - (*d3dintf->surface.release)(tex->d3dtarget3); - if (tex->d3dtarget4 != NULL) - (*d3dintf->surface.release)(tex->d3dtarget4); - if (tex->d3dsmalltarget0 != NULL) - (*d3dintf->surface.release)(tex->d3dsmalltarget0); global_free(tex); } @@ -1758,6 +1973,11 @@ static void device_delete_resources(d3d_info *d3d) (*d3dintf->effect.release)(d3d->post_effect); d3d->post_effect = NULL; } + if(d3d->prescale_effect != NULL) + { + (*d3dintf->effect.release)(d3d->prescale_effect); + d3d->prescale_effect = NULL; + } if(d3d->pincushion_effect != NULL) { (*d3dintf->effect.release)(d3d->pincushion_effect); @@ -1796,16 +2016,110 @@ static void device_delete_resources(d3d_info *d3d) for(int index = 0; index < 9; index++) { - if(d3d->last_d3dtexture[index] != NULL) + if (d3d->hlslprescaletexture0[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlslprescaletexture0[index]); + d3d->hlslprescaletexture0[index] = NULL; + } + if (d3d->hlsltexture0[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture0[index]); + d3d->hlsltexture0[index] = NULL; + } + if (d3d->hlsltexture1[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture1[index]); + d3d->hlsltexture1[index] = NULL; + } + if (d3d->hlsltexture2[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture2[index]); + d3d->hlsltexture2[index] = NULL; + } + if (d3d->hlsltexture3[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture3[index]); + d3d->hlsltexture3[index] = NULL; + } + if (d3d->hlsltexture4[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture4[index]); + d3d->hlsltexture4[index] = NULL; + } + if (d3d->hlslsmalltexture0[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlslsmalltexture0[index]); + d3d->hlslsmalltexture0[index] = NULL; + } + if (d3d->hlslprescaletarget0[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlslprescaletarget0[index]); + d3d->hlslprescaletarget0[index] = NULL; + } + if (d3d->hlsltarget0[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget0[index]); + d3d->hlsltarget0[index] = NULL; + } + if (d3d->hlsltarget1[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget1[index]); + d3d->hlsltarget1[index] = NULL; + } + if (d3d->hlsltarget2[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget2[index]); + d3d->hlsltarget2[index] = NULL; + } + if (d3d->hlsltarget3[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget3[index]); + d3d->hlsltarget3[index] = NULL; + } + if (d3d->hlsltarget4[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget4[index]); + d3d->hlsltarget4[index] = NULL; + } + if (d3d->hlslsmalltarget0[index] != NULL) { - (*d3dintf->texture.release)(d3d->last_d3dtexture[index]); - d3d->last_d3dtexture[index] = NULL; + (*d3dintf->surface.release)(d3d->hlslsmalltarget0[index]); + d3d->hlslsmalltarget0[index] = NULL; } - if(d3d->last_d3dtarget[index] != NULL) + if(d3d->last_hlsltexture[index] != NULL) { - (*d3dintf->surface.release)(d3d->last_d3dtarget[index]); - d3d->last_d3dtarget[index] = NULL; + (*d3dintf->texture.release)(d3d->last_hlsltexture[index]); + d3d->last_hlsltexture[index] = NULL; } + if(d3d->last_hlsltarget[index] != NULL) + { + (*d3dintf->surface.release)(d3d->last_hlsltarget[index]); + d3d->last_hlsltarget[index] = NULL; + } + } + + if(d3d->hlsl_avi_copy_texture != NULL) + { + (*d3dintf->texture.release)(d3d->hlsl_avi_copy_texture); + d3d->hlsl_avi_copy_texture = NULL; + } + + if(d3d->hlsl_avi_copy_surface != NULL) + { + (*d3dintf->surface.release)(d3d->hlsl_avi_copy_surface); + d3d->hlsl_avi_copy_surface = NULL; + } + + if(d3d->hlsl_avi_final_texture != NULL) + { + (*d3dintf->texture.release)(d3d->hlsl_avi_final_texture); + d3d->hlsl_avi_final_texture = NULL; + } + + if(d3d->hlsl_avi_final_target != NULL) + { + (*d3dintf->surface.release)(d3d->hlsl_avi_final_target); + d3d->hlsl_avi_final_target = NULL; } if(d3d->hlsl_options != NULL) @@ -1846,6 +2160,10 @@ static int device_verify_caps(d3d_info *d3d, win_window_info *window) d3d->hlsl_enable = downcast<windows_options &>(window->machine().options()).d3d_hlsl_enable() && d3dintf->post_fx_available; d3d->yiq_enable = downcast<windows_options &>(window->machine().options()).screen_yiq_enable(); + d3d->hlsl_prescale = downcast<windows_options &>(window->machine().options()).d3d_hlsl_prescale(); + d3d->hlsl_prescale_size = downcast<windows_options &>(window->machine().options()).d3d_hlsl_prescale_size(); + d3d->hlsl_preset = downcast<windows_options &>(window->machine().options()).d3d_hlsl_preset(); + result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->adapter, D3DDEVTYPE_HAL, CAPS_MAX_PS30_INSN_SLOTS, &tempcaps); if (result != D3D_OK) mame_printf_verbose("Direct3D Error %08X during get_caps_dword call\n", (int)result); if(tempcaps < 512 && d3d->hlsl_enable) @@ -2610,9 +2928,10 @@ static void primitive_flush_pending(d3d_info *d3d) vertnum = 0; } + bool screen_encountered[9] = { false }; + d3d_options *options = d3d->hlsl_options; - int cur_render_screen = 0; // now do the polys for (polynum = 0; polynum < d3d->numpolys; polynum++) { @@ -2625,6 +2944,9 @@ static void primitive_flush_pending(d3d_info *d3d) // set filtering if different if (poly->texture != NULL) { + screen_encountered[poly->texture->target_index] = true; + d3d->target_in_use[poly->texture->target_index] = poly->texture; + newfilter = FALSE; if (PRIMFLAG_GET_SCREENTEX(poly->flags)) newfilter = video_config.filter; @@ -2664,6 +2986,7 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.set_float)(curr_effect, "ShadowHeight", d3d->shadow_texture == NULL ? 1.0f : (float)d3d->shadow_texture->rawheight); (*d3dintf->effect.set_float)(curr_effect, "ScanlineAmount", options->screen_scanline_alpha); (*d3dintf->effect.set_float)(curr_effect, "ScanlineScale", options->screen_scanline_scale); + (*d3dintf->effect.set_float)(curr_effect, "ScanlineHeight", options->screen_scanline_height); (*d3dintf->effect.set_float)(curr_effect, "ScanlineBrightScale", options->screen_scanline_bright_scale); (*d3dintf->effect.set_float)(curr_effect, "ScanlineBrightOffset", options->screen_scanline_bright_offset); (*d3dintf->effect.set_float)(curr_effect, "ScanlineOffset", (poly->texture->cur_frame == 0) ? 0.0f : options->screen_scanline_offset); @@ -2688,6 +3011,8 @@ static void primitive_flush_pending(d3d_info *d3d) if(PRIMFLAG_GET_SCREENTEX(d3d->last_texture_flags) && poly->texture != NULL) { + d3d->target_use_count[poly->texture->target_index] = 60; + if(d3d->yiq_enable) { /* Convert our signal into YIQ */ @@ -2699,13 +3024,16 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.set_float)(curr_effect, "HeightRatio", 1.0f / (poly->texture->vstop - poly->texture->vstart)); (*d3dintf->effect.set_float)(curr_effect, "TargetWidth", (float)d3d->width); (*d3dintf->effect.set_float)(curr_effect, "TargetHeight", (float)d3d->height); - (*d3dintf->effect.set_float)(curr_effect, "WValue", winoptions.screen_yiq_w()); + (*d3dintf->effect.set_float)(curr_effect, "CCValue", winoptions.screen_yiq_cc()); (*d3dintf->effect.set_float)(curr_effect, "AValue", winoptions.screen_yiq_a()); - (*d3dintf->effect.set_float)(curr_effect, "BValue", (float)poly->texture->cur_frame * winoptions.screen_yiq_b()); - (*d3dintf->effect.set_float)(curr_effect, "FscScale", winoptions.screen_yiq_fsc_scale()); - (*d3dintf->effect.set_float)(curr_effect, "FscValue", winoptions.screen_yiq_fsc()); + (*d3dintf->effect.set_float)(curr_effect, "BValue", (poly->texture->cur_frame == 2) ? 0.0f : ((float)poly->texture->cur_frame * winoptions.screen_yiq_b())); + (*d3dintf->effect.set_float)(curr_effect, "PValue", winoptions.screen_yiq_p()); + (*d3dintf->effect.set_float)(curr_effect, "YFreqResponse", winoptions.screen_yiq_y()); + (*d3dintf->effect.set_float)(curr_effect, "IFreqResponse", winoptions.screen_yiq_i()); + (*d3dintf->effect.set_float)(curr_effect, "QFreqResponse", winoptions.screen_yiq_q()); + (*d3dintf->effect.set_float)(curr_effect, "ScanTime", winoptions.screen_yiq_scan_time()); - result = (*d3dintf->device.set_render_target)(d3d->device, 0, poly->texture->d3dtarget4); + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlsltarget4[poly->texture->target_index]); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); @@ -2727,7 +3055,7 @@ static void primitive_flush_pending(d3d_info *d3d) /* Convert our signal from YIQ */ curr_effect = d3d->yiq_decode_effect; - (*d3dintf->effect.set_texture)(curr_effect, "Composite", poly->texture->d3dtexture4); + (*d3dintf->effect.set_texture)(curr_effect, "Composite", d3d->hlsltexture4[poly->texture->target_index]); (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", poly->texture->d3dfinaltex); (*d3dintf->effect.set_float)(curr_effect, "RawWidth", (float)poly->texture->rawwidth); (*d3dintf->effect.set_float)(curr_effect, "RawHeight", (float)poly->texture->rawheight); @@ -2735,12 +3063,17 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.set_float)(curr_effect, "HeightRatio", 1.0f / (poly->texture->vstop - poly->texture->vstart)); (*d3dintf->effect.set_float)(curr_effect, "TargetWidth", (float)d3d->width); (*d3dintf->effect.set_float)(curr_effect, "TargetHeight", (float)d3d->height); - (*d3dintf->effect.set_float)(curr_effect, "WValue", winoptions.screen_yiq_w()); + (*d3dintf->effect.set_float)(curr_effect, "CCValue", winoptions.screen_yiq_cc()); (*d3dintf->effect.set_float)(curr_effect, "AValue", winoptions.screen_yiq_a()); - (*d3dintf->effect.set_float)(curr_effect, "BValue", (float)poly->texture->cur_frame * winoptions.screen_yiq_b()); - (*d3dintf->effect.set_float)(curr_effect, "FscValue", winoptions.screen_yiq_fsc()); + (*d3dintf->effect.set_float)(curr_effect, "BValue", (poly->texture->cur_frame == 2) ? 0.0f : ((float)poly->texture->cur_frame * winoptions.screen_yiq_b())); + (*d3dintf->effect.set_float)(curr_effect, "OValue", winoptions.screen_yiq_o()); + (*d3dintf->effect.set_float)(curr_effect, "PValue", winoptions.screen_yiq_p()); + (*d3dintf->effect.set_float)(curr_effect, "YFreqResponse", winoptions.screen_yiq_y()); + (*d3dintf->effect.set_float)(curr_effect, "IFreqResponse", winoptions.screen_yiq_i()); + (*d3dintf->effect.set_float)(curr_effect, "QFreqResponse", winoptions.screen_yiq_q()); + (*d3dintf->effect.set_float)(curr_effect, "ScanTime", winoptions.screen_yiq_scan_time()); - result = (*d3dintf->device.set_render_target)(d3d->device, 0, poly->texture->d3dtarget3); + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlsltarget3[poly->texture->target_index]); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); @@ -2761,7 +3094,7 @@ static void primitive_flush_pending(d3d_info *d3d) curr_effect = d3d->color_effect; - (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", poly->texture->d3dtexture3); + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlsltexture3[poly->texture->target_index]); } curr_effect = d3d->color_effect; @@ -2797,7 +3130,7 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.set_float)(curr_effect, "BluFloor", options->screen_blue_floor); (*d3dintf->effect.set_float)(curr_effect, "Saturation", options->screen_saturation); - result = (*d3dintf->device.set_render_target)(d3d->device, 0, poly->texture->d3dsmalltarget0); + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlslsmalltarget0[poly->texture->target_index]); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); @@ -2816,9 +3149,48 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.end)(curr_effect); + /* Pre-scaling pass (if enabled) */ + if(d3d->hlsl_prescale) + { + curr_effect = d3d->prescale_effect; + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlslsmalltexture0[poly->texture->target_index]); + + (*d3dintf->effect.set_float)(curr_effect, "TargetWidth", (float)d3d->width); + (*d3dintf->effect.set_float)(curr_effect, "TargetHeight", (float)d3d->height); + (*d3dintf->effect.set_float)(curr_effect, "RawWidth", (float)poly->texture->rawwidth); + (*d3dintf->effect.set_float)(curr_effect, "RawHeight", (float)poly->texture->rawheight); + (*d3dintf->effect.set_float)(curr_effect, "WidthRatio", 1.0f / (poly->texture->ustop - poly->texture->ustart)); + (*d3dintf->effect.set_float)(curr_effect, "HeightRatio", 1.0f / (poly->texture->vstop - poly->texture->vstart)); + + (*d3dintf->effect.begin)(curr_effect, &num_passes, 0); + + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlslprescaletarget0[poly->texture->target_index]); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); + result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); + + for (UINT pass = 0; pass < num_passes; pass++) + { + (*d3dintf->effect.begin_pass)(curr_effect, pass); + // add the primitives + result = (*d3dintf->device.draw_primitive)(d3d->device, poly->type, 0, poly->count); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result); + (*d3dintf->effect.end_pass)(curr_effect); + } + + (*d3dintf->effect.end)(curr_effect); + + curr_effect = d3d->deconverge_effect; + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlslprescaletexture0[poly->texture->target_index]); + } + else + { + curr_effect = d3d->deconverge_effect; + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlslsmalltexture0[poly->texture->target_index]); + } + /* Deconverge pass */ curr_effect = d3d->deconverge_effect; - (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", poly->texture->d3dsmalltexture0); (*d3dintf->effect.set_float)(curr_effect, "TargetWidth", (float)d3d->width); (*d3dintf->effect.set_float)(curr_effect, "TargetHeight", (float)d3d->height); @@ -2841,7 +3213,7 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.begin)(curr_effect, &num_passes, 0); - result = (*d3dintf->device.set_render_target)(d3d->device, 0, poly->texture->d3dtarget2); + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlsltarget2[poly->texture->target_index]); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call 6\n", (int)result); result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); @@ -2865,7 +3237,7 @@ static void primitive_flush_pending(d3d_info *d3d) /* Defocus pass 1 */ curr_effect = d3d->focus_effect; - (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", poly->texture->d3dtexture2); + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlsltexture2[poly->texture->target_index]); (*d3dintf->effect.set_float)(curr_effect, "TargetWidth", (float)d3d->width); (*d3dintf->effect.set_float)(curr_effect, "TargetHeight", (float)d3d->height); @@ -2879,7 +3251,7 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.begin)(curr_effect, &num_passes, 0); - result = (*d3dintf->device.set_render_target)(d3d->device, 0, poly->texture->d3dtarget0); + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlsltarget0[poly->texture->target_index]); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call 6\n", (int)result); result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); @@ -2897,7 +3269,7 @@ static void primitive_flush_pending(d3d_info *d3d) /* Defocus pass 2 */ - (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", poly->texture->d3dtexture0); + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlsltexture0[poly->texture->target_index]); (*d3dintf->effect.set_float)(curr_effect, "TargetWidth", (float)d3d->width); (*d3dintf->effect.set_float)(curr_effect, "TargetHeight", (float)d3d->height); @@ -2911,7 +3283,7 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.begin)(curr_effect, &num_passes, 0); - result = (*d3dintf->device.set_render_target)(d3d->device, 0, poly->texture->d3dtarget1); + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlsltarget1[poly->texture->target_index]); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call 7\n", (int)result); for (UINT pass = 0; pass < num_passes; pass++) @@ -2939,10 +3311,10 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.set_float)(curr_effect, "GreenPhosphor", options->screen_green_phosphor_life); (*d3dintf->effect.set_float)(curr_effect, "BluePhosphor", options->screen_blue_phosphor_life); - (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", focus_enable ? poly->texture->d3dtexture1 : poly->texture->d3dtexture2); - (*d3dintf->effect.set_texture)(curr_effect, "LastPass", d3d->last_d3dtexture[cur_render_screen]); + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", focus_enable ? d3d->hlsltexture1[poly->texture->target_index] : d3d->hlsltexture2[poly->texture->target_index]); + (*d3dintf->effect.set_texture)(curr_effect, "LastPass", d3d->last_hlsltexture[poly->texture->target_index]); - result = (*d3dintf->device.set_render_target)(d3d->device, 0, poly->texture->d3dtarget0); + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlsltarget0[poly->texture->target_index]); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call 4\n", (int)result); result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); @@ -2965,10 +3337,10 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.set_float)(curr_effect, "FixedAlpha", 1.0f); - (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", focus_enable ? poly->texture->d3dtexture1 : poly->texture->d3dtexture2); - (*d3dintf->effect.set_texture)(curr_effect, "LastPass", focus_enable ? poly->texture->d3dtexture1 : poly->texture->d3dtexture2); + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", focus_enable ? d3d->hlsltexture1[poly->texture->target_index] : d3d->hlsltexture2[poly->texture->target_index]); + (*d3dintf->effect.set_texture)(curr_effect, "LastPass", focus_enable ? d3d->hlsltexture1[poly->texture->target_index] : d3d->hlsltexture2[poly->texture->target_index]); - result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->last_d3dtarget[cur_render_screen++]); + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->last_hlsltarget[poly->texture->target_index]); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call 5\n", (int)result); result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); @@ -2986,13 +3358,62 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.end)(curr_effect); + /* Scanlines and shadow mask, at high res for AVI logging*/ + if(d3d->hlsl_avi_file != NULL) + { + curr_effect = d3d->post_effect; + + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlsltexture0[poly->texture->target_index]); + + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlsl_avi_final_target); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); + + (*d3dintf->effect.begin)(curr_effect, &num_passes, 0); + + for (UINT pass = 0; pass < num_passes; pass++) + { + (*d3dintf->effect.begin_pass)(curr_effect, pass); + // add the primitives + result = (*d3dintf->device.draw_primitive)(d3d->device, poly->type, vertnum, poly->count); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result); + (*d3dintf->effect.end_pass)(curr_effect); + } + + (*d3dintf->effect.end)(curr_effect); + } + + if(d3d->hlsl_render_snap) + { + curr_effect = d3d->post_effect; + + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlsltexture0[poly->texture->target_index]); + + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlsl_snap_target); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); + + (*d3dintf->effect.begin)(curr_effect, &num_passes, 0); + + for (UINT pass = 0; pass < num_passes; pass++) + { + (*d3dintf->effect.begin_pass)(curr_effect, pass); + // add the primitives + result = (*d3dintf->device.draw_primitive)(d3d->device, poly->type, vertnum, poly->count); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result); + (*d3dintf->effect.end_pass)(curr_effect); + } + + (*d3dintf->effect.end)(curr_effect); + + d3d->hlsl_snap_rendered = true; + } + /* Scanlines and shadow mask */ curr_effect = d3d->post_effect; - (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", poly->texture->d3dtexture0); + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlsltexture0[poly->texture->target_index]); result = (*d3dintf->device.set_render_target)(d3d->device, 0, backbuffer); - if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call 5\n", (int)result); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); (*d3dintf->effect.begin)(curr_effect, &num_passes, 0); @@ -3053,12 +3474,428 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->surface.release)(backbuffer); } + // Unregister any registered targets we didn't traverse in the past frame. A resolution change must + // have occurred. + for(int index = 0; index < 9 && d3d->hlsl_enable && d3dintf->post_fx_available; index++) + { + if(!screen_encountered[index] && d3d->hlslsmalltarget0[index] != NULL) + { + if(d3d->target_use_count[index] > 0) + { + d3d->target_use_count[index]--; + } + else + { + // free all textures + if(d3d->target_in_use[index] != NULL) + { + texture_info *tex = d3d->target_in_use[index]; + if(d3d->texlist == tex) + { + d3d->texlist = tex->next; + if(d3d->texlist != NULL) + { + d3d->texlist->prev = NULL; + } + } + else + { + if(tex->next != NULL) + { + tex->next->prev = tex->prev; + } + if(tex->prev != NULL) + { + tex->prev->next = tex->next; + } + } + + if (tex->d3dfinaltex != NULL) + (*d3dintf->texture.release)(tex->d3dfinaltex); + if (tex->d3dtex != NULL && tex->d3dtex != tex->d3dfinaltex) + (*d3dintf->texture.release)(tex->d3dtex); + if (tex->d3dsurface != NULL) + (*d3dintf->surface.release)(tex->d3dsurface); + global_free(tex); + } + + if (d3d->hlslprescaletexture0[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlslprescaletexture0[index]); + d3d->hlslprescaletexture0[index] = NULL; + } + if (d3d->hlsltexture0[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture0[index]); + d3d->hlsltexture0[index] = NULL; + } + if (d3d->hlsltexture1[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture1[index]); + d3d->hlsltexture1[index] = NULL; + } + if (d3d->hlsltexture2[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture2[index]); + d3d->hlsltexture2[index] = NULL; + } + if (d3d->hlsltexture3[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture3[index]); + d3d->hlsltexture3[index] = NULL; + } + if (d3d->hlsltexture4[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture4[index]); + d3d->hlsltexture4[index] = NULL; + } + if (d3d->hlslsmalltexture0[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlslsmalltexture0[index]); + d3d->hlslsmalltexture0[index] = NULL; + } + if (d3d->hlslprescaletarget0[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlslprescaletarget0[index]); + d3d->hlslprescaletarget0[index] = NULL; + } + if (d3d->hlsltarget0[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget0[index]); + d3d->hlsltarget0[index] = NULL; + } + if (d3d->hlsltarget1[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget1[index]); + d3d->hlsltarget1[index] = NULL; + } + if (d3d->hlsltarget2[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget2[index]); + d3d->hlsltarget2[index] = NULL; + } + if (d3d->hlsltarget3[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget3[index]); + d3d->hlsltarget3[index] = NULL; + } + if (d3d->hlsltarget4[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget4[index]); + d3d->hlsltarget4[index] = NULL; + } + if (d3d->hlslsmalltarget0[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlslsmalltarget0[index]); + d3d->hlslsmalltarget0[index] = NULL; + } + if(d3d->last_hlsltexture[index] != NULL) + { + (*d3dintf->texture.release)(d3d->last_hlsltexture[index]); + d3d->last_hlsltexture[index] = NULL; + } + if(d3d->last_hlsltarget[index] != NULL) + { + (*d3dintf->surface.release)(d3d->last_hlsltarget[index]); + d3d->last_hlsltarget[index] = NULL; + } + d3d->target_use_count[index] = 0; + } + } + } + // reset the vertex count d3d->numverts = 0; d3d->numpolys = 0; } +//============================================================ +// hlsl_avi_update_snap +//============================================================ + +static void hlsl_avi_update_snap(d3d_info *d3d, d3d_surface *surface) +{ + D3DLOCKED_RECT rect; + + // if we don't have a bitmap, or if it's not the right size, allocate a new one + if (d3d->hlsl_avi_snap == NULL || (int)((float)d3d->width * d3d->oversample_x) != d3d->hlsl_avi_snap->width || (int)((float)d3d->height * d3d->oversample_y) != d3d->hlsl_avi_snap->height) + { + if (d3d->hlsl_avi_snap != NULL) + { + auto_free(d3d->window->machine(), d3d->hlsl_avi_snap); + } + d3d->hlsl_avi_snap = auto_alloc(d3d->window->machine(), bitmap_t((int)((float)d3d->width * d3d->oversample_x), (int)((float)d3d->height * d3d->oversample_y), BITMAP_FORMAT_RGB32)); + } + + // copy the texture + HRESULT result = (*d3dintf->device.get_render_target_data)(d3d->device, surface, d3d->hlsl_avi_copy_surface); + if (result != D3D_OK) + { + printf("Couldn't copy (%08x)\n", (UINT32)result); + return; + } + + // lock the texture + result = (*d3dintf->surface.lock_rect)(d3d->hlsl_avi_copy_surface, &rect, NULL, D3DLOCK_DISCARD); + if (result != D3D_OK) + { + printf("Couldn't lock (%08x)\n", (UINT32)result); + return; + } + + // loop over Y + for (int srcy = 0; srcy < (int)((float)d3d->height * d3d->oversample_y); srcy++) + { + BYTE *src = (BYTE *)rect.pBits + srcy * rect.Pitch; + BYTE *dst = (BYTE *)d3d->hlsl_avi_snap->base + srcy * d3d->hlsl_avi_snap->rowpixels * 4; + + for(int x = 0; x < (int)((float)d3d->width * d3d->oversample_x); x++) + { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + } + } + + // unlock + result = (*d3dintf->surface.unlock_rect)(d3d->hlsl_avi_copy_surface); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result); +} + + + +//============================================================ +// hlsl_render_snapshot +//============================================================ + +static void hlsl_render_snapshot(d3d_info *d3d, d3d_surface *surface) +{ + D3DLOCKED_RECT rect; + + d3d->hlsl_render_snap = false; + + // if we don't have a bitmap, or if it's not the right size, allocate a new one + if (d3d->hlsl_avi_snap == NULL || d3d->hlsl_snap_width != (d3d->hlsl_avi_snap->width / 2) || d3d->hlsl_snap_height != (d3d->hlsl_avi_snap->height / 2)) + { + if (d3d->hlsl_avi_snap != NULL) + { + auto_free(d3d->window->machine(), d3d->hlsl_avi_snap); + } + d3d->hlsl_avi_snap = auto_alloc(d3d->window->machine(), bitmap_t(d3d->hlsl_snap_width / 2, d3d->hlsl_snap_height / 2, BITMAP_FORMAT_RGB32)); + } + + // copy the texture + HRESULT result = (*d3dintf->device.get_render_target_data)(d3d->device, surface, d3d->hlsl_snap_copy_target); + if (result != D3D_OK) + { + printf("Couldn't copy (%08x)\n", (UINT32)result); + return; + } + + // lock the texture + result = (*d3dintf->surface.lock_rect)(d3d->hlsl_snap_copy_target, &rect, NULL, D3DLOCK_DISCARD); + if (result != D3D_OK) + { + printf("Couldn't lock (%08x)\n", (UINT32)result); + return; + } + + for(int cy = 0; cy < 2; cy++) + { + for(int cx = 0; cx < 2; cx++) + { + // loop over Y + for (int srcy = 0; srcy < d3d->hlsl_snap_height / 2; srcy++) + { + int toty = (srcy + cy * (d3d->hlsl_snap_height / 2)); + int totx = cx * (d3d->hlsl_snap_width / 2); + BYTE *src = (BYTE *)rect.pBits + toty * rect.Pitch + totx * 4; + BYTE *dst = (BYTE *)d3d->hlsl_avi_snap->base + srcy * d3d->hlsl_avi_snap->rowpixels * 4; + + for(int x = 0; x < d3d->hlsl_snap_width / 2; x++) + { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + } + } + + int idx = cy * 2 + cx; + + emu_file file(d3d->window->machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + file_error filerr = open_next(d3d, file, "png", idx); + if (filerr != FILERR_NONE) + return; + + // add two text entries describing the image + astring text1(APPNAME, " ", build_version); + astring text2(d3d->window->machine().system().manufacturer, " ", d3d->window->machine().system().description); + png_info pnginfo = { 0 }; + png_add_text(&pnginfo, "Software", text1); + png_add_text(&pnginfo, "System", text2); + + // now do the actual work + png_error error = png_write_bitmap(file, &pnginfo, d3d->hlsl_avi_snap, 1 << 24, NULL); + if (error != PNGERR_NONE) + mame_printf_error("Error generating PNG for HLSL snapshot: png_error = %d\n", error); + + // free any data allocated + png_free(&pnginfo); + } + } + + // unlock + result = (*d3dintf->surface.unlock_rect)(d3d->hlsl_snap_copy_target); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result); + + if(d3d->hlsl_snap_texture != NULL) + { + (*d3dintf->texture.release)(d3d->hlsl_snap_texture); + d3d->hlsl_snap_texture = NULL; + } + + if(d3d->hlsl_snap_target != NULL) + { + (*d3dintf->surface.release)(d3d->hlsl_snap_target); + d3d->hlsl_snap_target = NULL; + } + + if(d3d->hlsl_snap_copy_texture != NULL) + { + (*d3dintf->texture.release)(d3d->hlsl_snap_copy_texture); + d3d->hlsl_snap_copy_texture = NULL; + } + + if(d3d->hlsl_snap_copy_target != NULL) + { + (*d3dintf->surface.release)(d3d->hlsl_snap_copy_target); + d3d->hlsl_snap_copy_target = NULL; + } +} + + +//============================================================ +// hlsl_record_texture +//============================================================ + +static void hlsl_record_texture(d3d_info *d3d, d3d_surface *surface) +{ + // ignore if nothing to do + if (d3d->hlsl_avi_file == NULL || surface == NULL) + { + return; + } + + // get the current time + attotime curtime = d3d->window->machine().time(); + + hlsl_avi_update_snap(d3d, surface); + + // loop until we hit the right time + while (d3d->hlsl_avi_next_frame_time <= curtime) + { + // handle an AVI recording + // write the next frame + avi_error avierr = avi_append_video_frame_rgb32(d3d->hlsl_avi_file, d3d->hlsl_avi_snap); + if (avierr != AVIERR_NONE) + { + end_hlsl_avi_recording(d3d); + return; + } + + // advance time + d3d->hlsl_avi_next_frame_time += d3d->hlsl_avi_frame_period; + d3d->hlsl_avi_frame++; + } +} + + +//============================================================ +// end_hlsl_avi_recording +//============================================================ + +static void end_hlsl_avi_recording(d3d_info *d3d) +{ + if(d3d->hlsl_avi_file != NULL) + { + avi_close(d3d->hlsl_avi_file); + } + d3d->hlsl_avi_file = NULL; + d3d->hlsl_avi_frame = 0; +} + + +//============================================================ +// begin_hlsl_avi_recording +//============================================================ + +static void begin_hlsl_avi_recording(d3d_info *d3d, const char *name) +{ + // stop any existing recording + end_hlsl_avi_recording(d3d); + + // reset the state + d3d->hlsl_avi_frame = 0; + d3d->hlsl_avi_next_frame_time = d3d->window->machine().time(); + + // build up information about this new movie + avi_movie_info info; + info.video_format = 0; + info.video_timescale = 1000 * ((d3d->window->machine().primary_screen != NULL) ? ATTOSECONDS_TO_HZ(d3d->window->machine().primary_screen->frame_period().attoseconds) : screen_device::DEFAULT_FRAME_RATE); + info.video_sampletime = 1000; + info.video_numsamples = 0; + info.video_width = d3d->width * d3d->oversample_x; + info.video_height = d3d->height * d3d->oversample_y; + info.video_depth = 24; + + info.audio_format = 0; + info.audio_timescale = d3d->window->machine().sample_rate(); + info.audio_sampletime = 1; + info.audio_numsamples = 0; + info.audio_channels = 2; + info.audio_samplebits = 16; + info.audio_samplerate = d3d->window->machine().sample_rate(); + + // create a new temporary movie file + file_error filerr; + astring fullpath; + { + emu_file tempfile(d3d->window->machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + if (name != NULL) + { + filerr = tempfile.open(name); + } + else + { + filerr = open_next(d3d, tempfile, "avi", 0); + } + + // compute the frame time + { + d3d->hlsl_avi_frame_period = attotime::from_seconds(1000) / info.video_timescale; + } + + // if we succeeded, make a copy of the name and create the real file over top + if (filerr == FILERR_NONE) + { + fullpath = tempfile.fullpath(); + } + } + + if (filerr == FILERR_NONE) + { + // create the file and free the string + avi_error avierr = avi_create(fullpath, &info, &d3d->hlsl_avi_file); + if (avierr != AVIERR_NONE) + { + mame_printf_error("Error creating AVI: %s\n", avi_error_string(avierr)); + } + } +} + //============================================================ // texture_create @@ -3082,9 +3919,6 @@ static texture_info *texture_create(d3d_info *d3d, const render_texinfo *texsour // compute the size texture_compute_size(d3d, texsource->width, texsource->height, texture); - d3d->oversample_x = downcast<windows_options &>(d3d->window->machine().options()).screen_oversample_x(); - d3d->oversample_y = downcast<windows_options &>(d3d->window->machine().options()).screen_oversample_y(); - // non-screen textures are easy if (!PRIMFLAG_GET_SCREENTEX(flags)) { @@ -3143,42 +3977,56 @@ static texture_info *texture_create(d3d_info *d3d, const render_texinfo *texsour if(d3d->hlsl_enable && d3dintf->post_fx_available) { - result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture0); + int idx = d3d->registered_targets; + + result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture0[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture0, 0, &texture->d3dtarget0); + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture0[idx], 0, &d3d->hlsltarget0[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->last_d3dtexture[d3d->registered_targets]); + result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->last_hlsltexture[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(d3d->last_d3dtexture[d3d->registered_targets], 0, &d3d->last_d3dtarget[d3d->registered_targets]); + (*d3dintf->texture.get_surface_level)(d3d->last_hlsltexture[idx], 0, &d3d->last_hlsltarget[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture1); + result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture1[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture1, 0, &texture->d3dtarget1); + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture1[idx], 0, &d3d->hlsltarget1[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture2); + result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture2[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture2, 0, &texture->d3dtarget2); + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture2[idx], 0, &d3d->hlsltarget2[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, texture->rawwidth, texture->rawheight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture3); + result = (*d3dintf->device.create_texture)(d3d->device, texture->rawwidth, texture->rawheight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture3[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture3, 0, &texture->d3dtarget3); + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture3[idx], 0, &d3d->hlsltarget3[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, texture->rawwidth, texture->rawheight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture4); + result = (*d3dintf->device.create_texture)(d3d->device, texture->rawwidth, texture->rawheight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture4[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture4, 0, &texture->d3dtarget4); + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture4[idx], 0, &d3d->hlsltarget4[idx]); + + int scale = 1; + if(d3d->hlsl_prescale) scale = d3d->hlsl_prescale_size; - result = (*d3dintf->device.create_texture)(d3d->device, texture->rawwidth, texture->rawheight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dsmalltexture0); + result = (*d3dintf->device.create_texture)(d3d->device, texture->rawwidth * scale, texture->rawheight * scale, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlslsmalltexture0[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dsmalltexture0, 0, &texture->d3dsmalltarget0); + (*d3dintf->texture.get_surface_level)(d3d->hlslsmalltexture0[idx], 0, &d3d->hlslsmalltarget0[idx]); + result = (*d3dintf->device.create_texture)(d3d->device, texture->rawwidth * scale, texture->rawheight * scale, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlslprescaletexture0[idx]); + if (result != D3D_OK) + goto error; + (*d3dintf->texture.get_surface_level)(d3d->hlslprescaletexture0[idx], 0, &d3d->hlslprescaletarget0[idx]); + + texture->target_index = d3d->registered_targets; + d3d->target_use_count[texture->target_index] = 60; + d3d->target_in_use[texture->target_index] = texture; d3d->registered_targets++; + d3d->registered_targets %= 9; } break; @@ -3221,41 +4069,56 @@ static texture_info *texture_create(d3d_info *d3d, const render_texinfo *texsour { if(d3d->hlsl_enable && d3dintf->post_fx_available) { - result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture0); + int idx = d3d->registered_targets; + + result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture0[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture0, 0, &texture->d3dtarget0); + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture0[idx], 0, &d3d->hlsltarget0[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->last_d3dtexture[d3d->registered_targets]); + result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->last_hlsltexture[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(d3d->last_d3dtexture[d3d->registered_targets], 0, &d3d->last_d3dtarget[d3d->registered_targets]); - d3d->registered_targets++; + (*d3dintf->texture.get_surface_level)(d3d->last_hlsltexture[idx], 0, &d3d->last_hlsltarget[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture1); + result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture1[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture1, 0, &texture->d3dtarget1); + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture1[idx], 0, &d3d->hlsltarget1[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture2); + result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture2[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture2, 0, &texture->d3dtarget2); + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture2[idx], 0, &d3d->hlsltarget2[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture3); + result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture3[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture3, 0, &texture->d3dtarget3); + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture3[idx], 0, &d3d->hlsltarget3[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture4); + result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture4[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture4, 0, &texture->d3dtarget4); + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture4[idx], 0, &d3d->hlsltarget4[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, scwidth, scheight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dsmalltexture0); + int scale = 1; + if(d3d->hlsl_prescale) scale = d3d->hlsl_prescale_size; + + result = (*d3dintf->device.create_texture)(d3d->device, scwidth * scale, scheight * scale, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlslsmalltexture0[idx]); + if (result != D3D_OK) + goto error; + (*d3dintf->texture.get_surface_level)(d3d->hlslsmalltexture0[idx], 0, &d3d->hlslsmalltarget0[idx]); + + result = (*d3dintf->device.create_texture)(d3d->device, scwidth * scale, scheight * scale, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlslprescaletexture0[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dsmalltexture0, 0, &texture->d3dsmalltarget0); + (*d3dintf->texture.get_surface_level)(d3d->hlslprescaletexture0[idx], 0, &d3d->hlslprescaletarget0[idx]); + + texture->target_index = d3d->registered_targets; + d3d->target_use_count[texture->target_index] = 60; + d3d->target_in_use[texture->target_index] = texture; + d3d->registered_targets++; + d3d->registered_targets %= 9; } break; } @@ -3269,6 +4132,9 @@ static texture_info *texture_create(d3d_info *d3d, const render_texinfo *texsour texture_set_data(d3d, texture, texsource, flags); // add us to the texture list + if(d3d->texlist != NULL) + d3d->texlist->prev = texture; + texture->prev = NULL; texture->next = d3d->texlist; d3d->texlist = texture; return texture; @@ -4022,3 +4888,130 @@ static void texture_update(d3d_info *d3d, const render_primitive *prim) texture->texinfo.seqid = prim->texture.seqid; } } + + +// NOTE: The function below is taken directly from src/emu/video.c and should likely be moved into a global helper function. +//------------------------------------------------- +// open_next - open the next non-existing file of +// type filetype according to our numbering +// scheme +//------------------------------------------------- + +static file_error open_next(d3d_info *d3d, emu_file &file, const char *extension, int idx) +{ + UINT32 origflags = file.openflags(); + + // handle defaults + const char *snapname = d3d->window->machine().options().snap_name(); + + if (snapname == NULL || snapname[0] == 0) + snapname = "%g/%i"; + astring snapstr(snapname); + + // strip any extension in the provided name + int index = snapstr.rchr(0, '.'); + if (index != -1) + snapstr.substr(0, index); + + // handle %d in the template (for image devices) + astring snapdev("%d_"); + int pos = snapstr.find(0, snapdev); + + if (pos != -1) + { + // if more %d are found, revert to default and ignore them all + if (snapstr.find(pos + 3, snapdev) != -1) + snapstr.cpy("%g/%i"); + // else if there is a single %d, try to create the correct snapname + else + { + int name_found = 0; + + // find length of the device name + int end1 = snapstr.find(pos + 3, "/"); + int end2 = snapstr.find(pos + 3, "%"); + int end = -1; + + if ((end1 != -1) && (end2 != -1)) + end = MIN(end1, end2); + else if (end1 != -1) + end = end1; + else if (end2 != -1) + end = end2; + else + end = snapstr.len(); + + if (end - pos < 3) + fatalerror("Something very wrong is going on!!!"); + + // copy the device name to an astring + astring snapdevname; + snapdevname.cpysubstr(snapstr, pos + 3, end - pos - 3); + + // verify that there is such a device for this system + device_image_interface *image = NULL; + for (bool gotone = d3d->window->machine().devicelist().first(image); gotone; gotone = image->next(image)) + { + // get the device name + astring tempdevname(image->brief_instance_name()); + + if (snapdevname.cmp(tempdevname) == 0) + { + // verify that such a device has an image mounted + if (image->basename() != NULL) + { + astring filename(image->basename()); + + // strip extension + filename.substr(0, filename.rchr(0, '.')); + + // setup snapname and remove the %d_ + snapstr.replace(0, snapdevname, filename); + snapstr.del(pos, 3); + + name_found = 1; + } + } + } + + // or fallback to default + if (name_found == 0) + snapstr.cpy("%g/%i"); + } + } + + // add our own index + // add our own extension + snapstr.cat(".").cat(extension); + + // substitute path and gamename up front + snapstr.replace(0, "/", PATH_SEPARATOR); + snapstr.replace(0, "%g", d3d->window->machine().basename()); + + // determine if the template has an index; if not, we always use the same name + astring fname; + if (snapstr.find(0, "%i") == -1) + fname.cpy(snapstr); + + // otherwise, we scan for the next available filename + else + { + // try until we succeed + astring seqtext; + file.set_openflags(OPEN_FLAG_READ); + for (int seq = 0; ; seq++) + { + // build up the filename + fname.cpy(snapstr).replace(0, "%i", seqtext.format("%04d_%d", seq, idx).cstr()); + + // try to open the file; stop when we fail + file_error filerr = file.open(fname); + if (filerr != FILERR_NONE) + break; + } + } + + // create the final file + file.set_openflags(origflags); + return file.open(fname); +} |