Previous 199869 Revisions Next

r41776 Monday 9th November, 2015 at 08:08:10 UTC by Jezze
Renamed *.c to *.cpp (nw)

- renamed *.c to *.cpp of changed files to be able to merge with base
master
[src/osd/modules/render]drawd3d.c drawd3d.cpp*
[src/osd/modules/render/d3d]d3dhlsl.c d3dhlsl.cpp*
[src/osd/windows]winmain.c winmain.cpp*

trunk/src/osd/modules/render/d3d/d3dhlsl.c
r250287r250288
1// license:BSD-3-Clause
2// copyright-holders:Aaron Giles
3//============================================================
4//
5//  d3dhlsl.c - Win32 Direct3D HLSL implementation
6//
7//============================================================
8
9// Useful info:
10//  Windows XP/2003 shipped with DirectX 8.1
11//  Windows 2000 shipped with DirectX 7a
12//  Windows 98SE shipped with DirectX 6.1a
13//  Windows 98 shipped with DirectX 5
14//  Windows NT shipped with DirectX 3.0a
15//  Windows 95 shipped with DirectX 2
16
17// standard windows headers
18#define WIN32_LEAN_AND_MEAN
19#include <windows.h>
20#include <tchar.h>
21#include <mmsystem.h>
22#include <d3d9.h>
23#include <d3dx9.h>
24#include <math.h>
25#undef interface
26
27// MAME headers
28#include "emu.h"
29#include "render.h"
30#include "ui/ui.h"
31#include "rendutil.h"
32#include "options.h"
33#include "emuopts.h"
34#include "aviio.h"
35#include "png.h"
36#include "screen.h"
37
38// MAMEOS headers
39#include "d3dintf.h"
40#include "winmain.h"
41#include "window.h"
42#include "config.h"
43#include "d3dcomm.h"
44#include "modules/render/drawd3d.h"
45#include "strconv.h"
46
47
48//============================================================
49//  GLOBALS
50//============================================================
51
52static slider_state *g_slider_list;
53static file_error open_next(d3d::renderer *d3d, emu_file &file, const char *templ, const char *extension, int idx);
54
55namespace d3d
56{
57
58//============================================================
59//  PROTOTYPES
60//============================================================
61
62static void get_vector(const char *data, int count, float *out, bool report_error);
63
64
65//============================================================
66//  TYPE DEFINITIONS
67//============================================================
68
69typedef HRESULT (WINAPI *direct3dx9_loadeffect_ptr)(LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, const D3DXMACRO *pDefines, LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXEFFECTPOOL pPool, LPD3DXEFFECT *ppEffect, LPD3DXBUFFER *ppCompilationErrors);
70static direct3dx9_loadeffect_ptr g_load_effect = NULL;
71
72
73//============================================================
74//  shader manager constructor
75//============================================================
76
77shaders::shaders()
78{
79   master_enable = false;
80   vector_enable = true;
81   hlsl_prescale_x = 1;
82   hlsl_prescale_x = 1;
83   preset = -1;
84   shadow_texture = NULL;
85   options = NULL;
86   paused = true;
87   lastidx = -1;
88   targethead = NULL;
89   cachehead = NULL;
90   initialized = false;
91}
92
93
94//============================================================
95//  shaders destructor
96//============================================================
97
98shaders::~shaders()
99{
100   cache_target *currcache = cachehead;
101   while(cachehead != NULL)
102   {
103      cachehead = currcache->next;
104      global_free(currcache);
105      currcache = cachehead;
106   }
107
108   render_target *currtarget = targethead;
109   while(targethead != NULL)
110   {
111      targethead = currtarget->next;
112      global_free(currtarget);
113      currtarget = targethead;
114   }
115}
116
117
118//============================================================
119//  shaders::window_save
120//============================================================
121
122void shaders::window_save()
123{
124   if (!master_enable || !d3dintf->post_fx_available)
125   {
126      return;
127   }
128
129   HRESULT result = (*d3dintf->device.create_texture)(d3d->get_device(), snap_width, snap_height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &snap_copy_texture);
130   if (result != D3D_OK)
131   {
132      osd_printf_verbose("Direct3D: Unable to init system-memory target for HLSL snapshot (%08x), bailing\n", (UINT32)result);
133      return;
134   }
135   (*d3dintf->texture.get_surface_level)(snap_copy_texture, 0, &snap_copy_target);
136
137   result = (*d3dintf->device.create_texture)(d3d->get_device(), snap_width, snap_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &snap_texture);
138   if (result != D3D_OK)
139   {
140      osd_printf_verbose("Direct3D: Unable to init video-memory target for HLSL snapshot (%08x), bailing\n", (UINT32)result);
141      return;
142   }
143   (*d3dintf->texture.get_surface_level)(snap_texture, 0, &snap_target);
144
145   render_snap = true;
146   snap_rendered = false;
147}
148
149
150//============================================================
151//  shaders::window_record
152//============================================================
153
154void shaders::window_record()
155{
156   if (!master_enable || !d3dintf->post_fx_available)
157   {
158      return;
159   }
160
161   windows_options &options = downcast<windows_options &>(machine->options());
162   const char *filename = options.d3d_hlsl_write();
163
164   if (avi_output_file != NULL)
165   {
166      end_avi_recording();
167   }
168   else if (filename[0] != 0)
169   {
170      begin_avi_recording(filename);
171   }
172}
173
174
175//============================================================
176//  shaders::avi_update_snap
177//============================================================
178
179void shaders::avi_update_snap(surface *surface)
180{
181   if (!master_enable || !d3dintf->post_fx_available)
182   {
183      return;
184   }
185
186   D3DLOCKED_RECT rect;
187
188   // if we don't have a bitmap, or if it's not the right size, allocate a new one
189   if (!avi_snap.valid() || (int)snap_width != avi_snap.width() || (int)snap_height != avi_snap.height())
190   {
191      avi_snap.allocate((int)snap_width, (int)snap_height);
192   }
193
194   // copy the texture
195   HRESULT result = (*d3dintf->device.get_render_target_data)(d3d->get_device(), surface, avi_copy_surface);
196   if (result != D3D_OK)
197   {
198      return;
199   }
200
201   // lock the texture
202   result = (*d3dintf->surface.lock_rect)(avi_copy_surface, &rect, NULL, D3DLOCK_DISCARD);
203   if (result != D3D_OK)
204   {
205      return;
206   }
207
208   // loop over Y
209   for (int srcy = 0; srcy < (int)snap_height; srcy++)
210   {
211      DWORD *src = (DWORD *)((BYTE *)rect.pBits + srcy * rect.Pitch);
212      UINT32 *dst = &avi_snap.pix32(srcy);
213
214      for (int x = 0; x < snap_width; x++)
215      {
216         *dst++ = *src++;
217      }
218   }
219
220   // unlock
221   result = (*d3dintf->surface.unlock_rect)(avi_copy_surface);
222   if (result != D3D_OK)
223   {
224      osd_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result);
225   }
226}
227
228
229
230//============================================================
231//  hlsl_render_snapshot
232//============================================================
233
234void shaders::render_snapshot(surface *surface)
235{
236   if (!master_enable || !d3dintf->post_fx_available)
237   {
238      return;
239   }
240
241   D3DLOCKED_RECT rect;
242
243   render_snap = false;
244
245   // if we don't have a bitmap, or if it's not the right size, allocate a new one
246   if (!avi_snap.valid() || snap_width != (avi_snap.width() / 2) || snap_height != (avi_snap.height() / 2))
247   {
248      avi_snap.allocate(snap_width / 2, snap_height / 2);
249   }
250
251   // copy the texture
252   HRESULT result = (*d3dintf->device.get_render_target_data)(d3d->get_device(), surface, snap_copy_target);
253   if (result != D3D_OK)
254   {
255      return;
256   }
257
258   // lock the texture
259   result = (*d3dintf->surface.lock_rect)(snap_copy_target, &rect, NULL, D3DLOCK_DISCARD);
260   if (result != D3D_OK)
261   {
262      return;
263   }
264
265   for (int cy = 0; cy < 2; cy++)
266   {
267      for (int cx = 0; cx < 2; cx++)
268      {
269         // loop over Y
270         for (int srcy = 0; srcy < snap_height / 2; srcy++)
271         {
272            int toty = (srcy + cy * (snap_height / 2));
273            int totx = cx * (snap_width / 2);
274            DWORD *src = (DWORD *)((BYTE *)rect.pBits + toty * rect.Pitch + totx * 4);
275            UINT32 *dst = &avi_snap.pix32(srcy);
276
277            for (int x = 0; x < snap_width / 2; x++)
278            {
279               *dst++ = *src++;
280            }
281         }
282
283         int idx = cy * 2 + cx;
284
285         emu_file file(machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
286         file_error filerr = open_next(d3d, file, NULL, "png", idx);
287         if (filerr != FILERR_NONE)
288         {
289            return;
290         }
291
292         // add two text entries describing the image
293         std::string text1 = std::string(emulator_info::get_appname()).append(" ").append(build_version);
294         std::string text2 = std::string(machine->system().manufacturer).append(" ").append(machine->system().description);
295         png_info pnginfo = { 0 };
296         png_add_text(&pnginfo, "Software", text1.c_str());
297         png_add_text(&pnginfo, "System", text2.c_str());
298
299         // now do the actual work
300         png_error error = png_write_bitmap(file, &pnginfo, avi_snap, 1 << 24, NULL);
301         if (error != PNGERR_NONE)
302         {
303            osd_printf_error("Error generating PNG for HLSL snapshot: png_error = %d\n", error);
304         }
305
306         // free any data allocated
307         png_free(&pnginfo);
308      }
309   }
310
311   // unlock
312   result = (*d3dintf->surface.unlock_rect)(snap_copy_target);
313   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result);
314
315   if (snap_texture != NULL)
316   {
317      (*d3dintf->texture.release)(snap_texture);
318      snap_texture = NULL;
319   }
320
321   if (snap_target != NULL)
322   {
323      (*d3dintf->surface.release)(snap_target);
324      snap_target = NULL;
325   }
326
327   if (snap_copy_texture != NULL)
328   {
329      (*d3dintf->texture.release)(snap_copy_texture);
330      snap_copy_texture = NULL;
331   }
332
333   if (snap_copy_target != NULL)
334   {
335      (*d3dintf->surface.release)(snap_copy_target);
336      snap_copy_target = NULL;
337   }
338}
339
340
341//============================================================
342//  shaders::record_texture
343//============================================================
344
345void shaders::record_texture()
346{
347   if (!master_enable || !d3dintf->post_fx_available)
348   {
349      return;
350   }
351
352   surface *surface = avi_final_target;
353
354   // ignore if nothing to do
355   if (avi_output_file == NULL || surface == NULL)
356   {
357      return;
358   }
359
360   // get the current time
361   attotime curtime = machine->time();
362
363   avi_update_snap(surface);
364
365   // loop until we hit the right time
366   while (avi_next_frame_time <= curtime)
367   {
368      // handle an AVI recording
369      // write the next frame
370      avi_error avierr = avi_append_video_frame(avi_output_file, avi_snap);
371      if (avierr != AVIERR_NONE)
372      {
373         end_avi_recording();
374         return;
375      }
376
377      // advance time
378      avi_next_frame_time += avi_frame_period;
379      avi_frame++;
380   }
381}
382
383
384//============================================================
385//  shaders::end_hlsl_avi_recording
386//============================================================
387
388void shaders::end_avi_recording()
389{
390   if (!master_enable || !d3dintf->post_fx_available)
391   {
392      return;
393   }
394
395   if (avi_output_file != NULL)
396   {
397      avi_close(avi_output_file);
398   }
399
400   avi_output_file = NULL;
401   avi_frame = 0;
402}
403
404
405//============================================================
406//  shaders::toggle
407//============================================================
408
409void shaders::toggle()
410{
411   if (master_enable)
412   {
413      if (initialized)
414      {
415         delete_resources(false);
416      }
417      master_enable = !master_enable;
418   }
419   else
420   {
421      if (!initialized)
422      {
423         master_enable = !master_enable;
424         bool failed = create_resources(false);
425         if (failed)
426         {
427            master_enable = false;
428         }
429      }
430      else
431      {
432         master_enable = !master_enable;
433      }
434   }
435}
436
437//============================================================
438//  shaders::begin_avi_recording
439//============================================================
440
441void shaders::begin_avi_recording(const char *name)
442{
443   if (!master_enable || !d3dintf->post_fx_available)
444   {
445      return;
446   }
447
448   // stop any existing recording
449   end_avi_recording();
450
451   // reset the state
452   avi_frame = 0;
453   avi_next_frame_time = machine->time();
454
455   // build up information about this new movie
456   avi_movie_info info;
457   info.video_format = 0;
458   info.video_timescale = 1000 * ((machine->first_screen() != NULL) ? ATTOSECONDS_TO_HZ(machine->first_screen()->frame_period().m_attoseconds) : screen_device::DEFAULT_FRAME_RATE);
459   info.video_sampletime = 1000;
460   info.video_numsamples = 0;
461   info.video_width = snap_width;
462   info.video_height = snap_height;
463   info.video_depth = 24;
464
465   info.audio_format = 0;
466   info.audio_timescale = machine->sample_rate();
467   info.audio_sampletime = 1;
468   info.audio_numsamples = 0;
469   info.audio_channels = 2;
470   info.audio_samplebits = 16;
471   info.audio_samplerate = machine->sample_rate();
472
473   // create a new temporary movie file
474   file_error filerr;
475   std::string fullpath;
476   {
477      emu_file tempfile(machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
478      if (name != NULL)
479      {
480         filerr = tempfile.open(name);
481      }
482      else
483      {
484         filerr = open_next(d3d, tempfile, NULL, "avi", 0);
485      }
486
487      // compute the frame time
488      {
489         avi_frame_period = attotime::from_seconds(1000) / info.video_timescale;
490      }
491
492      // if we succeeded, make a copy of the name and create the real file over top
493      if (filerr == FILERR_NONE)
494      {
495         fullpath = tempfile.fullpath();
496      }
497   }
498
499   if (filerr == FILERR_NONE)
500   {
501      // create the file and free the string
502      avi_error avierr = avi_create(fullpath.c_str(), &info, &avi_output_file);
503      if (avierr != AVIERR_NONE)
504      {
505         osd_printf_error("Error creating AVI: %s\n", avi_error_string(avierr));
506      }
507   }
508}
509
510
511//============================================================
512//  remove_cache_target - remove an active cache target when
513//  refcount hits zero
514//============================================================
515
516void shaders::remove_cache_target(cache_target *cache)
517{
518   if (cache != NULL)
519   {
520      if (cache == cachehead)
521      {
522         cachehead = cachehead->next;
523      }
524
525      if (cache->prev != NULL)
526      {
527         cache->prev->next = cache->next;
528      }
529
530      if (cache->next != NULL)
531      {
532         cache->next->prev = cache->prev;
533      }
534
535      global_free(cache);
536   }
537}
538
539
540//============================================================
541//  remove_render_target - remove an active target
542//============================================================
543
544void shaders::remove_render_target(texture_info *texture)
545{
546   remove_render_target(find_render_target(texture));
547}
548
549void shaders::remove_render_target(int width, int height, UINT32 screen_index, UINT32 page_index)
550{
551   render_target *target = find_render_target(width, height, screen_index, page_index);
552   if (target != NULL)
553   {
554      remove_render_target(target);
555   }
556}
557
558void shaders::remove_render_target(render_target *rt)
559{
560   if (rt != NULL)
561   {
562      if (rt == targethead)
563      {
564         targethead = targethead->next;
565      }
566
567      if (rt->prev != NULL)
568      {
569         rt->prev->next = rt->next;
570      }
571
572      if (rt->next != NULL)
573      {
574         rt->next->prev = rt->prev;
575      }
576
577      cache_target *cache = find_cache_target(rt->screen_index, rt->width, rt->height);
578      if (cache != NULL)
579      {
580         remove_cache_target(cache);
581      }
582
583      int screen_index = rt->screen_index;
584      int other_page = 1 - rt->page_index;
585      int width = rt->width;
586      int height = rt->height;
587
588      global_free(rt);
589
590      // Remove other double-buffered page (if it exists)
591      remove_render_target(width, height, screen_index, other_page);
592   }
593}
594
595
596//============================================================
597//  shaders::set_texture
598//============================================================
599
600void shaders::set_texture(texture_info *texture)
601{
602   if (!master_enable || !d3dintf->post_fx_available)
603   {
604      return;
605   }
606
607   if (texture != NULL)
608   {
609      paused = texture->paused();
610      texture->advance_frame();
611   }
612
613   // set initial texture to use
614   texture_info *default_texture = d3d->get_default_texture();
615   default_effect->set_texture("Diffuse", (texture == NULL) ? default_texture->get_finaltex() : texture->get_finaltex());
616   if (options->yiq_enable)
617   {
618      yiq_encode_effect->set_texture("Diffuse", (texture == NULL) ? default_texture->get_finaltex() : texture->get_finaltex());
619   }
620   else
621   {
622      color_effect->set_texture("Diffuse", (texture == NULL) ? default_texture->get_finaltex() : texture->get_finaltex());
623   }
624}
625
626
627//============================================================
628//  shaders::init
629//============================================================
630
631void shaders::init(base *d3dintf, running_machine *machine, d3d::renderer *renderer)
632{
633   if (!d3dintf->post_fx_available)
634   {
635      return;
636   }
637
638   g_load_effect = (direct3dx9_loadeffect_ptr)GetProcAddress(d3dintf->libhandle, "D3DXCreateEffectFromFileW");
639   if (g_load_effect == NULL)
640   {
641      printf("Direct3D: Unable to find D3DXCreateEffectFromFileW\n");
642      d3dintf->post_fx_available = false;
643      return;
644   }
645
646   this->d3dintf = d3dintf;
647   this->machine = machine;
648   this->d3d = renderer;
649   this->options = renderer->get_shaders_options();
650
651   windows_options &winoptions = downcast<windows_options &>(machine->options());
652
653   master_enable = winoptions.d3d_hlsl_enable();
654   hlsl_prescale_x = winoptions.d3d_hlsl_prescale_x();
655   hlsl_prescale_y = winoptions.d3d_hlsl_prescale_y();
656   snap_width = winoptions.d3d_snap_width();
657   snap_height = winoptions.d3d_snap_height();
658
659   if (!options->params_init)
660   {
661      strncpy(options->shadow_mask_texture, winoptions.screen_shadow_mask_texture(), sizeof(options->shadow_mask_texture));
662      options->shadow_mask_alpha = winoptions.screen_shadow_mask_alpha();
663      options->shadow_mask_count_x = winoptions.screen_shadow_mask_count_x();
664      options->shadow_mask_count_y = winoptions.screen_shadow_mask_count_y();
665      options->shadow_mask_u_size = winoptions.screen_shadow_mask_u_size();
666      options->shadow_mask_v_size = winoptions.screen_shadow_mask_v_size();
667      options->shadow_mask_u_offset = winoptions.screen_shadow_mask_u_offset();
668      options->shadow_mask_v_offset = winoptions.screen_shadow_mask_v_offset();
669      options->curvature = winoptions.screen_curvature();
670      options->round_corner = winoptions.screen_round_corner();
671      options->smooth_border = winoptions.screen_smooth_border();
672      options->reflection = winoptions.screen_reflection();
673      options->vignetting = winoptions.screen_vignetting();
674      options->scanline_alpha = winoptions.screen_scanline_amount();
675      options->scanline_scale = winoptions.screen_scanline_scale();
676      options->scanline_height = winoptions.screen_scanline_height();
677      options->scanline_bright_scale = winoptions.screen_scanline_bright_scale();
678      options->scanline_bright_offset = winoptions.screen_scanline_bright_offset();
679      options->scanline_offset = winoptions.screen_scanline_offset();
680      get_vector(winoptions.screen_defocus(), 2, options->defocus, TRUE);
681      get_vector(winoptions.screen_converge_x(), 3, options->converge_x, TRUE);
682      get_vector(winoptions.screen_converge_y(), 3, options->converge_y, TRUE);
683      get_vector(winoptions.screen_radial_converge_x(), 3, options->radial_converge_x, TRUE);
684      get_vector(winoptions.screen_radial_converge_y(), 3, options->radial_converge_y, TRUE);
685      get_vector(winoptions.screen_red_ratio(), 3, options->red_ratio, TRUE);
686      get_vector(winoptions.screen_grn_ratio(), 3, options->grn_ratio, TRUE);
687      get_vector(winoptions.screen_blu_ratio(), 3, options->blu_ratio, TRUE);
688      get_vector(winoptions.screen_offset(), 3, options->offset, TRUE);
689      get_vector(winoptions.screen_scale(), 3, options->scale, TRUE);
690      get_vector(winoptions.screen_power(), 3, options->power, TRUE);
691      get_vector(winoptions.screen_floor(), 3, options->floor, TRUE);
692      get_vector(winoptions.screen_phosphor(), 3, options->phosphor, TRUE);
693      options->saturation = winoptions.screen_saturation();
694      options->yiq_enable = winoptions.screen_yiq_enable();
695      options->yiq_cc = winoptions.screen_yiq_cc();
696      options->yiq_a = winoptions.screen_yiq_a();
697      options->yiq_b = winoptions.screen_yiq_b();
698      options->yiq_o = winoptions.screen_yiq_o();
699      options->yiq_p = winoptions.screen_yiq_p();
700      options->yiq_n = winoptions.screen_yiq_n();
701      options->yiq_y = winoptions.screen_yiq_y();
702      options->yiq_i = winoptions.screen_yiq_i();
703      options->yiq_q = winoptions.screen_yiq_q();
704      options->yiq_scan_time = winoptions.screen_yiq_scan_time();
705      options->yiq_phase_count = winoptions.screen_yiq_phase_count();
706      options->vector_length_scale = winoptions.screen_vector_length_scale();
707      options->vector_length_ratio = winoptions.screen_vector_length_ratio();
708      options->bloom_scale = winoptions.screen_bloom_scale();
709      get_vector(winoptions.screen_bloom_overdrive(), 3, options->bloom_overdrive, TRUE);
710      options->bloom_level0_weight = winoptions.screen_bloom_lvl0_weight();
711      options->bloom_level1_weight = winoptions.screen_bloom_lvl1_weight();
712      options->bloom_level2_weight = winoptions.screen_bloom_lvl2_weight();
713      options->bloom_level3_weight = winoptions.screen_bloom_lvl3_weight();
714      options->bloom_level4_weight = winoptions.screen_bloom_lvl4_weight();
715      options->bloom_level5_weight = winoptions.screen_bloom_lvl5_weight();
716      options->bloom_level6_weight = winoptions.screen_bloom_lvl6_weight();
717      options->bloom_level7_weight = winoptions.screen_bloom_lvl7_weight();
718      options->bloom_level8_weight = winoptions.screen_bloom_lvl8_weight();
719      options->bloom_level9_weight = winoptions.screen_bloom_lvl9_weight();
720      options->bloom_level10_weight = winoptions.screen_bloom_lvl10_weight();
721
722      options->params_init = true;
723   }
724
725   options->params_dirty = true;
726
727   g_slider_list = init_slider_list();
728}
729
730
731//============================================================
732//  shaders::init_fsfx_quad
733//============================================================
734
735void shaders::init_fsfx_quad(void *vertbuf)
736{
737   // Called at the start of each frame by the D3D code in order to reserve two triangles
738   // that are guaranteed to be at a fixed position so as to simply use D3DPT_TRIANGLELIST, 0, 2
739   // instead of having to do bookkeeping about a specific screen quad
740   if (!master_enable || !d3dintf->post_fx_available)
741   {
742      return;
743   }
744
745   // get a pointer to the vertex buffer
746   fsfx_vertices = (vertex *)vertbuf;
747   if (fsfx_vertices == NULL)
748   {
749      return;
750   }
751
752   // fill in the vertexes clockwise
753   fsfx_vertices[0].x = 0.0f;
754   fsfx_vertices[0].y = 0.0f;
755   fsfx_vertices[1].x = d3d->get_width();
756   fsfx_vertices[1].y = 0.0f;
757   fsfx_vertices[2].x = 0.0f;
758   fsfx_vertices[2].y = d3d->get_height();
759   fsfx_vertices[3].x = d3d->get_width();
760   fsfx_vertices[3].y = 0.0f;
761   fsfx_vertices[4].x = 0.0f;
762   fsfx_vertices[4].y = d3d->get_height();
763   fsfx_vertices[5].x = d3d->get_width();
764   fsfx_vertices[5].y = d3d->get_height();
765
766   fsfx_vertices[0].u0 = 0.0f;
767   fsfx_vertices[0].v0 = 0.0f;
768
769   fsfx_vertices[1].u0 = 1.0f;
770   fsfx_vertices[1].v0 = 0.0f;
771
772   fsfx_vertices[2].u0 = 0.0f;
773   fsfx_vertices[2].v0 = 1.0f;
774
775   fsfx_vertices[3].u0 = 1.0f;
776   fsfx_vertices[3].v0 = 0.0f;
777
778   fsfx_vertices[4].u0 = 0.0f;
779   fsfx_vertices[4].v0 = 1.0f;
780
781   fsfx_vertices[5].u0 = 1.0f;
782   fsfx_vertices[5].v0 = 1.0f;
783
784   fsfx_vertices[0].u1 = 0.0f;
785   fsfx_vertices[0].v1 = 0.0f;
786   fsfx_vertices[1].u1 = 0.0f;
787   fsfx_vertices[1].v1 = 0.0f;
788   fsfx_vertices[2].u1 = 0.0f;
789   fsfx_vertices[2].v1 = 0.0f;
790   fsfx_vertices[3].u1 = 0.0f;
791   fsfx_vertices[3].v1 = 0.0f;
792   fsfx_vertices[4].u1 = 0.0f;
793   fsfx_vertices[4].v1 = 0.0f;
794   fsfx_vertices[5].u1 = 0.0f;
795   fsfx_vertices[5].v1 = 0.0f;
796
797   // set the color, Z parameters to standard values
798   for (int i = 0; i < 6; i++)
799   {
800      fsfx_vertices[i].z = 0.0f;
801      fsfx_vertices[i].rhw = 1.0f;
802      fsfx_vertices[i].color = D3DCOLOR_ARGB(255, 255, 255, 255);
803   }
804}
805
806
807//============================================================
808//  shaders::create_resources
809//============================================================
810
811int shaders::create_resources(bool reset)
812{
813   if (!master_enable || !d3dintf->post_fx_available)
814   {
815      return 0;
816   }
817
818   HRESULT result = (*d3dintf->device.get_render_target)(d3d->get_device(), 0, &backbuffer);
819   if (result != D3D_OK)
820   {
821      osd_printf_verbose("Direct3D: Error %08X during device get_render_target call\n", (int)result);
822   }
823
824   result = (*d3dintf->device.create_texture)(d3d->get_device(), 4, 4, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &black_texture);
825   if (result != D3D_OK)
826   {
827      osd_printf_verbose("Direct3D: Unable to init video-memory target for black texture (%08x)\n", (UINT32)result);
828      return 1;
829   }
830   (*d3dintf->texture.get_surface_level)(black_texture, 0, &black_surface);
831   result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, black_surface);
832   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result);
833   result = (*d3dintf->device.clear)(d3d->get_device(), 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0);
834   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result);
835   result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, backbuffer);
836   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result);
837
838   result = (*d3dintf->device.create_texture)(d3d->get_device(), (int)snap_width, (int)snap_height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &avi_copy_texture);
839   if (result != D3D_OK)
840   {
841      osd_printf_verbose("Direct3D: Unable to init system-memory target for HLSL AVI dumping (%08x)\n", (UINT32)result);
842      return 1;
843   }
844   (*d3dintf->texture.get_surface_level)(avi_copy_texture, 0, &avi_copy_surface);
845
846   result = (*d3dintf->device.create_texture)(d3d->get_device(), (int)snap_width, (int)snap_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &avi_final_texture);
847   if (result != D3D_OK)
848   {
849      osd_printf_verbose("Direct3D: Unable to init video-memory target for HLSL AVI dumping (%08x)\n", (UINT32)result);
850      return 1;
851   }
852   (*d3dintf->texture.get_surface_level)(avi_final_texture, 0, &avi_final_target);
853
854   emu_file file(machine->options().art_path(), OPEN_FLAG_READ);
855   render_load_png(shadow_bitmap, file, NULL, options->shadow_mask_texture);
856
857   // experimental: if we have a shadow bitmap, create a texture for it
858   if (shadow_bitmap.valid())
859   {
860      render_texinfo texture;
861
862      // fake in the basic data so it looks like it came from render.c
863      texture.base = shadow_bitmap.raw_pixptr(0);
864      texture.rowpixels = shadow_bitmap.rowpixels();
865      texture.width = shadow_bitmap.width();
866      texture.height = shadow_bitmap.height();
867      texture.palette = NULL;
868      texture.seqid = 0;
869
870      // now create it (no prescale, but wrap)
871      shadow_texture = new texture_info(d3d->get_texture_manager(), &texture, 1, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32) | PRIMFLAG_TEXWRAP_MASK);
872   }
873
874   const char *fx_dir = downcast<windows_options &>(machine->options()).screen_post_fx_dir();
875
876   default_effect = new effect(this, d3d->get_device(), "primary.fx", fx_dir);
877   post_effect = new effect(this, d3d->get_device(), "post.fx", fx_dir);
878   distortion_effect = new effect(this, d3d->get_device(), "distortion.fx", fx_dir);
879   prescale_effect = new effect(this, d3d->get_device(), "prescale.fx", fx_dir);
880   phosphor_effect = new effect(this, d3d->get_device(), "phosphor.fx", fx_dir);
881   focus_effect = new effect(this, d3d->get_device(), "focus.fx", fx_dir);
882   deconverge_effect = new effect(this, d3d->get_device(), "deconverge.fx", fx_dir);
883   color_effect = new effect(this, d3d->get_device(), "color.fx", fx_dir);
884   yiq_encode_effect = new effect(this, d3d->get_device(), "yiq_encode.fx", fx_dir);
885   yiq_decode_effect = new effect(this, d3d->get_device(), "yiq_decode.fx", fx_dir);
886   bloom_effect = new effect(this, d3d->get_device(), "bloom.fx", fx_dir);
887   downsample_effect = new effect(this, d3d->get_device(), "downsample.fx", fx_dir);
888   vector_effect = new effect(this, d3d->get_device(), "vector.fx", fx_dir);
889
890   if (!default_effect->is_valid() ||
891      !post_effect->is_valid() ||
892      !distortion_effect->is_valid() ||
893      !prescale_effect->is_valid() ||
894      !phosphor_effect->is_valid() ||
895      !focus_effect->is_valid() ||
896      !deconverge_effect->is_valid() ||
897      !color_effect->is_valid() ||
898      !yiq_encode_effect->is_valid() ||
899      !yiq_decode_effect->is_valid() ||
900      !bloom_effect->is_valid() ||
901      !downsample_effect->is_valid() ||
902      !vector_effect->is_valid())
903   {
904      return 1;
905   }
906
907   yiq_encode_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
908   yiq_encode_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
909   yiq_encode_effect->add_uniform("SourceRect", uniform::UT_VEC2, uniform::CU_SOURCE_RECT);
910   yiq_encode_effect->add_uniform("CCValue", uniform::UT_FLOAT, uniform::CU_NTSC_CCFREQ);
911   yiq_encode_effect->add_uniform("AValue", uniform::UT_FLOAT, uniform::CU_NTSC_A);
912   yiq_encode_effect->add_uniform("BValue", uniform::UT_FLOAT, uniform::CU_NTSC_B);
913   yiq_encode_effect->add_uniform("PValue", uniform::UT_FLOAT, uniform::CU_NTSC_P);
914   yiq_encode_effect->add_uniform("NotchHalfWidth", uniform::UT_FLOAT, uniform::CU_NTSC_NOTCH);
915   yiq_encode_effect->add_uniform("YFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_YFREQ);
916   yiq_encode_effect->add_uniform("IFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_IFREQ);
917   yiq_encode_effect->add_uniform("QFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_QFREQ);
918   yiq_encode_effect->add_uniform("ScanTime", uniform::UT_FLOAT, uniform::CU_NTSC_HTIME);
919
920   yiq_decode_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
921   yiq_decode_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
922   yiq_decode_effect->add_uniform("SourceRect", uniform::UT_VEC2, uniform::CU_SOURCE_RECT);
923   yiq_decode_effect->add_uniform("CCValue", uniform::UT_FLOAT, uniform::CU_NTSC_CCFREQ);
924   yiq_decode_effect->add_uniform("AValue", uniform::UT_FLOAT, uniform::CU_NTSC_A);
925   yiq_decode_effect->add_uniform("BValue", uniform::UT_FLOAT, uniform::CU_NTSC_B);
926   yiq_decode_effect->add_uniform("OValue", uniform::UT_FLOAT, uniform::CU_NTSC_O);
927   yiq_decode_effect->add_uniform("PValue", uniform::UT_FLOAT, uniform::CU_NTSC_P);
928   yiq_decode_effect->add_uniform("NotchHalfWidth", uniform::UT_FLOAT, uniform::CU_NTSC_NOTCH);
929   yiq_decode_effect->add_uniform("YFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_YFREQ);
930   yiq_decode_effect->add_uniform("IFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_IFREQ);
931   yiq_decode_effect->add_uniform("QFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_QFREQ);
932   yiq_decode_effect->add_uniform("ScanTime", uniform::UT_FLOAT, uniform::CU_NTSC_HTIME);
933
934   color_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
935   color_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
936
937   color_effect->add_uniform("YIQEnable", uniform::UT_FLOAT, uniform::CU_NTSC_ENABLE);
938   color_effect->add_uniform("RedRatios", uniform::UT_VEC3, uniform::CU_COLOR_RED_RATIOS);
939   color_effect->add_uniform("GrnRatios", uniform::UT_VEC3, uniform::CU_COLOR_GRN_RATIOS);
940   color_effect->add_uniform("BluRatios", uniform::UT_VEC3, uniform::CU_COLOR_BLU_RATIOS);
941   color_effect->add_uniform("Offset", uniform::UT_VEC3, uniform::CU_COLOR_OFFSET);
942   color_effect->add_uniform("Scale", uniform::UT_VEC3, uniform::CU_COLOR_SCALE);
943   color_effect->add_uniform("Saturation", uniform::UT_FLOAT, uniform::CU_COLOR_SATURATION);
944
945   prescale_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
946   prescale_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
947
948   deconverge_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
949   deconverge_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
950   deconverge_effect->add_uniform("SourceRect", uniform::UT_VEC2, uniform::CU_SOURCE_RECT);
951   deconverge_effect->add_uniform("ConvergeX", uniform::UT_VEC3, uniform::CU_CONVERGE_LINEAR_X);
952   deconverge_effect->add_uniform("ConvergeY", uniform::UT_VEC3, uniform::CU_CONVERGE_LINEAR_Y);
953   deconverge_effect->add_uniform("RadialConvergeX", uniform::UT_VEC3, uniform::CU_CONVERGE_RADIAL_X);
954   deconverge_effect->add_uniform("RadialConvergeY", uniform::UT_VEC3, uniform::CU_CONVERGE_RADIAL_Y);
955
956   focus_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
957   focus_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS);
958   focus_effect->add_uniform("Defocus", uniform::UT_VEC2, uniform::CU_FOCUS_SIZE);
959
960   phosphor_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
961   phosphor_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS);
962   phosphor_effect->add_uniform("Phosphor", uniform::UT_VEC3, uniform::CU_PHOSPHOR_LIFE);
963
964   downsample_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
965
966   bloom_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
967   bloom_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS);
968
969   post_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
970   post_effect->add_uniform("SourceRect", uniform::UT_VEC2, uniform::CU_SOURCE_RECT); // backward compatibility
971   post_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
972   post_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS);
973   post_effect->add_uniform("QuadDims", uniform::UT_VEC2, uniform::CU_QUAD_DIMS); // backward compatibility
974
975   post_effect->add_uniform("VignettingAmount", uniform::UT_FLOAT, uniform::CU_POST_VIGNETTING); // backward compatibility
976   post_effect->add_uniform("CurvatureAmount", uniform::UT_FLOAT, uniform::CU_POST_CURVATURE); // backward compatibility
977   post_effect->add_uniform("RoundCornerAmount", uniform::UT_FLOAT, uniform::CU_POST_ROUND_CORNER); // backward compatibility
978   post_effect->add_uniform("SmoothBorderAmount", uniform::UT_FLOAT, uniform::CU_POST_SMOOTH_BORDER); // backward compatibility
979   post_effect->add_uniform("ReflectionAmount", uniform::UT_FLOAT, uniform::CU_POST_REFLECTION); // backward compatibility
980
981   post_effect->add_uniform("ShadowAlpha", uniform::UT_FLOAT, uniform::CU_POST_SHADOW_ALPHA);
982   post_effect->add_uniform("ShadowCount", uniform::UT_VEC2, uniform::CU_POST_SHADOW_COUNT);
983   post_effect->add_uniform("ShadowUV", uniform::UT_VEC2, uniform::CU_POST_SHADOW_UV);
984   post_effect->add_uniform("ShadowUVOffset", uniform::UT_VEC2, uniform::CU_POST_SHADOW_UV_OFFSET);
985   post_effect->add_uniform("ShadowDims", uniform::UT_VEC2, uniform::CU_POST_SHADOW_DIMS);
986
987   post_effect->add_uniform("ScanlineAlpha", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_ALPHA);
988   post_effect->add_uniform("ScanlineScale", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_SCALE);
989   post_effect->add_uniform("ScanlineHeight", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_HEIGHT);
990   post_effect->add_uniform("ScanlineBrightScale", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_BRIGHT_SCALE);
991   post_effect->add_uniform("ScanlineBrightOffset", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_BRIGHT_OFFSET);
992   post_effect->add_uniform("Power", uniform::UT_VEC3, uniform::CU_POST_POWER);
993   post_effect->add_uniform("Floor", uniform::UT_VEC3, uniform::CU_POST_FLOOR);
994
995   distortion_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
996   distortion_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS);
997   distortion_effect->add_uniform("QuadDims", uniform::UT_VEC2, uniform::CU_QUAD_DIMS);
998
999   distortion_effect->add_uniform("VignettingAmount", uniform::UT_FLOAT, uniform::CU_POST_VIGNETTING);
1000   distortion_effect->add_uniform("CurvatureAmount", uniform::UT_FLOAT, uniform::CU_POST_CURVATURE);
1001   distortion_effect->add_uniform("RoundCornerAmount", uniform::UT_FLOAT, uniform::CU_POST_ROUND_CORNER);
1002   distortion_effect->add_uniform("SmoothBorderAmount", uniform::UT_FLOAT, uniform::CU_POST_SMOOTH_BORDER);
1003   distortion_effect->add_uniform("ReflectionAmount", uniform::UT_FLOAT, uniform::CU_POST_REFLECTION);
1004
1005   vector_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
1006
1007   default_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
1008   default_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS);
1009
1010   initialized = true;
1011
1012   return 0;
1013}
1014
1015
1016//============================================================
1017//  shaders::begin_draw
1018//============================================================
1019
1020void shaders::begin_draw()
1021{
1022   if (!master_enable || !d3dintf->post_fx_available)
1023   {
1024      return;
1025   }
1026
1027   curr_effect = default_effect;
1028
1029   default_effect->set_technique("TestTechnique");
1030   post_effect->set_technique("ScanMaskTechnique");
1031   distortion_effect->set_technique("DistortionTechnique");
1032   phosphor_effect->set_technique("TestTechnique");
1033   focus_effect->set_technique("TestTechnique");
1034   deconverge_effect->set_technique("DeconvergeTechnique");
1035   color_effect->set_technique("ColorTechnique");
1036   yiq_encode_effect->set_technique("EncodeTechnique");
1037   yiq_decode_effect->set_technique("DecodeTechnique");
1038
1039   HRESULT result = (*d3dintf->device.get_render_target)(d3d->get_device(), 0, &backbuffer);
1040   if (result != D3D_OK)
1041   {
1042      osd_printf_verbose("Direct3D: Error %08X during device get_render_target call\n", (int)result);
1043   }
1044}
1045
1046
1047//============================================================
1048//  shaders::begin_frame
1049//============================================================
1050
1051void shaders::begin_frame()
1052{
1053   record_texture();
1054}
1055
1056
1057//============================================================
1058//  shaders::blit
1059//============================================================
1060
1061void shaders::blit(
1062   surface *dst,
1063   bool clear_dst,
1064   D3DPRIMITIVETYPE prim_type,
1065   UINT32 prim_index,
1066   UINT32 prim_count)
1067{
1068   HRESULT result;
1069
1070   if (dst != NULL)
1071   {
1072      result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, dst);
1073      if (result != D3D_OK)
1074      {
1075         osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result);
1076      }
1077
1078      if (clear_dst)
1079      {
1080         result = (*d3dintf->device.clear)(d3d->get_device(), 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(1,0,0,0), 0, 0);
1081         if (result != D3D_OK)
1082         {
1083            osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result);
1084         }
1085      }
1086   }
1087
1088   UINT num_passes = 0;
1089   curr_effect->begin(&num_passes, 0);
1090
1091   for (UINT pass = 0; pass < num_passes; pass++)
1092   {
1093      curr_effect->begin_pass(pass);
1094
1095      // add the primitives
1096      result = (*d3dintf->device.draw_primitive)(d3d->get_device(), prim_type, prim_index, prim_count);
1097      if (result != D3D_OK)
1098      {
1099         osd_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result);
1100      }
1101
1102      curr_effect->end_pass();
1103   }
1104
1105   curr_effect->end();
1106}
1107
1108
1109//============================================================
1110//  shaders::end_frame
1111//============================================================
1112
1113void shaders::end_frame()
1114{
1115   if (!master_enable || !d3dintf->post_fx_available)
1116   {
1117      return;
1118   }
1119
1120   if (render_snap && snap_rendered)
1121   {
1122      render_snapshot(snap_target);
1123   }
1124
1125   if (!lines_pending)
1126   {
1127      return;
1128   }
1129
1130   lines_pending = false;
1131}
1132
1133
1134//============================================================
1135//  shaders::init_effect_info
1136//============================================================
1137
1138void shaders::init_effect_info(poly_info *poly)
1139{
1140   // nothing to do
1141}
1142
1143
1144//============================================================
1145//  shaders::find_render_target
1146//============================================================
1147
1148render_target* shaders::find_render_target(texture_info *info)
1149{
1150   UINT32 screen_index_data = (UINT32)info->get_texinfo().osddata;
1151   UINT32 screen_index = screen_index_data >> 1;
1152   UINT32 page_index = screen_index_data & 1;
1153
1154   render_target *curr = targethead;
1155   while (curr != NULL && (
1156      curr->screen_index != screen_index ||
1157      curr->page_index != page_index ||
1158      curr->width != info->get_texinfo().width ||
1159      curr->height != info->get_texinfo().height))
1160   {
1161      curr = curr->next;
1162   }
1163
1164   return curr;
1165}
1166
1167
1168//============================================================
1169//  shaders::find_render_target
1170//============================================================
1171
1172render_target* shaders::find_render_target(int width, int height, UINT32 screen_index, UINT32 page_index)
1173{
1174   render_target *curr = targethead;
1175   while (curr != NULL && (
1176      curr->width != width ||
1177      curr->height != height ||
1178      curr->screen_index != screen_index ||
1179      curr->page_index != page_index))
1180   {
1181      curr = curr->next;
1182   }
1183
1184   return curr;
1185}
1186
1187
1188//============================================================
1189//  shaders::find_cache_target
1190//============================================================
1191
1192cache_target* shaders::find_cache_target(UINT32 screen_index, int width, int height)
1193{
1194   cache_target *curr = cachehead;
1195   while (curr != NULL && (
1196      curr->screen_index != screen_index ||
1197      curr->width != width ||
1198      curr->height != height))
1199   {
1200      curr = curr->next;
1201   }
1202
1203   return curr;
1204}
1205
1206int shaders::ntsc_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1207{
1208   int next_index = source_index;
1209
1210   if (!options->yiq_enable)
1211   {
1212      return next_index;
1213   }
1214
1215   // Convert our signal into YIQ
1216   curr_effect = yiq_encode_effect;
1217   curr_effect->update_uniforms();
1218
1219   // initial "Diffuse"  texture is set in shaders::set_texture()
1220
1221   next_index = rt->next_index(next_index);
1222   blit(rt->native_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2);
1223
1224   // Convert our signal from YIQ
1225   curr_effect = yiq_decode_effect;
1226   curr_effect->update_uniforms();
1227   curr_effect->set_texture("Composite", rt->native_texture[next_index]);
1228   curr_effect->set_texture("Diffuse", curr_texture->get_finaltex());
1229
1230   next_index = rt->next_index(next_index);
1231   blit(rt->native_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2);
1232
1233   color_effect->set_texture("Diffuse", rt->native_texture[next_index]);
1234
1235   return next_index;
1236}
1237
1238int shaders::color_convolution_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1239{
1240   int next_index = source_index;
1241
1242   curr_effect = color_effect;
1243   curr_effect->update_uniforms();
1244
1245   // initial "Diffuse" texture is set in shaders::set_texture() or the result of shaders::ntsc_pass()
1246
1247   next_index = rt->next_index(next_index);
1248   blit(rt->native_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2);
1249
1250   return next_index;
1251}
1252
1253int shaders::prescale_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1254{
1255   int next_index = source_index;
1256
1257   curr_effect = prescale_effect;
1258   curr_effect->update_uniforms();
1259   curr_effect->set_texture("Diffuse", rt->native_texture[next_index]);
1260
1261   next_index = rt->next_index(next_index);
1262   blit(rt->prescale_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2);
1263
1264   return next_index;
1265}
1266
1267int shaders::deconverge_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1268{
1269   int next_index = source_index;
1270
1271   curr_effect = deconverge_effect;
1272   curr_effect->update_uniforms();
1273   curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]);
1274
1275   next_index = rt->next_index(next_index);
1276   blit(rt->prescale_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2);
1277
1278   return next_index;
1279}
1280
1281int shaders::defocus_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1282{
1283   int next_index = source_index;
1284
1285   float defocus_x = options->defocus[0];
1286   float defocus_y = options->defocus[1];
1287
1288   // skip defocus if no influencing settings
1289   if (defocus_x == 0.0f && defocus_y == 0.0f)
1290   {
1291      return next_index;
1292   }
1293
1294   curr_effect = focus_effect;
1295   curr_effect->update_uniforms();
1296   curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]);
1297
1298   next_index = rt->next_index(next_index);
1299   blit(rt->prescale_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2);
1300
1301   return next_index;
1302}
1303
1304int shaders::phosphor_pass(render_target *rt, cache_target *ct, int source_index, poly_info *poly, int vertnum)
1305{
1306   int next_index = source_index;
1307
1308   curr_effect = phosphor_effect;
1309   curr_effect->update_uniforms();
1310   curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]);
1311   curr_effect->set_texture("LastPass", ct->last_texture);
1312   curr_effect->set_bool("Passthrough", false);
1313
1314   next_index = rt->next_index(next_index);
1315   blit(rt->prescale_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2);
1316
1317   // Pass along our phosphor'd screen
1318   curr_effect->update_uniforms();
1319   curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]);
1320   curr_effect->set_texture("LastPass", rt->prescale_texture[next_index]);
1321   curr_effect->set_bool("Passthrough", true);
1322
1323   // Avoid changing targets due to page flipping
1324   blit(ct->last_target, true, D3DPT_TRIANGLELIST, 0, 2);
1325
1326   return next_index;
1327}
1328
1329int shaders::post_pass(render_target *rt, int source_index, poly_info *poly, int vertnum, bool prepare_bloom)
1330{
1331   int next_index = source_index;
1332
1333   texture_info *texture = poly->get_texture();
1334
1335   bool prepare_vector =
1336      (machine->first_screen()->screen_type() &  SCREEN_TYPE_VECTOR) == SCREEN_TYPE_VECTOR;
1337   bool prepare_raster =
1338      (machine->first_screen()->screen_type() &  SCREEN_TYPE_RASTER) == SCREEN_TYPE_RASTER;
1339   bool orientation_swap_xy =
1340      (d3d->window().machine().system().flags & ORIENTATION_SWAP_XY) == ORIENTATION_SWAP_XY;
1341   bool rotation_swap_xy =
1342      (d3d->window().target()->orientation() & ROT90) == ROT90 ||
1343      (d3d->window().target()->orientation() & ROT270) == ROT270;
1344   int rotation_type =
1345      (d3d->window().target()->orientation() & ROT90) == ROT90
1346         ? 1
1347         : (d3d->window().target()->orientation() & ROT180) == ROT180
1348            ? 2
1349            : (d3d->window().target()->orientation() & ROT270) == ROT270
1350               ? 3
1351               : 0;
1352
1353   curr_effect = post_effect;
1354   curr_effect->update_uniforms();
1355   curr_effect->set_texture("ShadowTexture", shadow_texture == NULL ? NULL : shadow_texture->get_finaltex());
1356   curr_effect->set_texture("DiffuseTexture", rt->prescale_texture[next_index]);
1357   curr_effect->set_float("ScanlineOffset", texture->get_cur_frame() == 0 ? 0.0f : options->scanline_offset);
1358   curr_effect->set_bool("OrientationSwapXY", orientation_swap_xy);
1359   curr_effect->set_bool("RotationSwapXY", rotation_swap_xy);
1360   curr_effect->set_int("RotationType", rotation_type); // backward compatibility
1361   curr_effect->set_bool("PrepareBloom", prepare_bloom);
1362   curr_effect->set_bool("PrepareVector", prepare_vector);
1363   curr_effect->set_bool("PrepareRaster", prepare_raster);
1364
1365   next_index = rt->next_index(next_index);
1366   blit(prepare_bloom ? rt->native_target[next_index] : rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count());
1367
1368   return next_index;
1369}
1370
1371int shaders::downsample_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1372{
1373   int next_index = source_index;
1374
1375   bool prepare_vector =
1376      (machine->first_screen()->screen_type() &  SCREEN_TYPE_VECTOR) == SCREEN_TYPE_VECTOR;
1377   float bloom_rescale = options->bloom_scale;
1378
1379   // skip downsample if no influencing settings
1380   if (bloom_rescale == 0.0f)
1381   {
1382      return next_index;
1383   }
1384
1385   curr_effect = downsample_effect;
1386   curr_effect->update_uniforms();
1387   curr_effect->set_bool("PrepareVector", prepare_vector);
1388
1389   int bloom_index = 0;
1390   float bloom_size = (d3d->get_width() < d3d->get_height()) ? d3d->get_width() : d3d->get_height();
1391   float bloom_width = prepare_vector ? rt->target_width : rt->target_width / hlsl_prescale_x;
1392   float bloom_height = prepare_vector ? rt->target_height : rt->target_height / hlsl_prescale_y;
1393   for (; bloom_size >= 2.0f && bloom_index < 11; bloom_size *= 0.5f)
1394   {
1395      bloom_dims[bloom_index][0] = (float)(int)bloom_width;
1396      bloom_dims[bloom_index][1] = (float)(int)bloom_height;
1397
1398      curr_effect->set_vector("TargetDims", 2, bloom_dims[bloom_index]);
1399      curr_effect->set_texture("DiffuseTexture",
1400         bloom_index == 0
1401            ? rt->native_texture[next_index]
1402            : rt->bloom_texture[bloom_index - 1]);
1403
1404      blit(rt->bloom_target[bloom_index], true, poly->get_type(), vertnum, poly->get_count());
1405
1406      bloom_width *= 0.5f;
1407      bloom_height *= 0.5f;
1408
1409      bloom_index++;
1410   }
1411
1412   bloom_count = bloom_index;
1413
1414   return next_index;
1415}
1416
1417int shaders::bloom_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1418{
1419   int next_index = source_index;
1420
1421   float bloom_rescale = options->bloom_scale;
1422
1423   // skip bloom if no influencing settings
1424   if (bloom_rescale == 0.0f)
1425   {
1426      return next_index;
1427   }
1428
1429   curr_effect = bloom_effect;
1430   curr_effect->update_uniforms();
1431
1432   float weight0123[4] = {
1433      options->bloom_level0_weight,
1434      options->bloom_level1_weight * bloom_rescale,
1435      options->bloom_level2_weight * bloom_rescale,
1436      options->bloom_level3_weight * bloom_rescale
1437   };
1438   float weight4567[4] = {
1439      options->bloom_level4_weight * bloom_rescale,
1440      options->bloom_level5_weight * bloom_rescale,
1441      options->bloom_level6_weight * bloom_rescale,
1442      options->bloom_level7_weight * bloom_rescale
1443   };
1444   float weight89A[3]  = {
1445      options->bloom_level8_weight * bloom_rescale,
1446      options->bloom_level9_weight * bloom_rescale,
1447      options->bloom_level10_weight * bloom_rescale
1448   };
1449   curr_effect->set_vector("Level0123Weight", 4, weight0123);
1450   curr_effect->set_vector("Level4567Weight", 4, weight4567);
1451   curr_effect->set_vector("Level89AWeight", 3, weight89A);
1452   curr_effect->set_vector("Level01Size", 4, bloom_dims[0]);
1453   curr_effect->set_vector("Level23Size", 4, bloom_dims[2]);
1454   curr_effect->set_vector("Level45Size", 4, bloom_dims[4]);
1455   curr_effect->set_vector("Level67Size", 4, bloom_dims[6]);
1456   curr_effect->set_vector("Level89Size", 4, bloom_dims[8]);
1457   curr_effect->set_vector("LevelASize", 2, bloom_dims[10]);
1458
1459   curr_effect->set_vector("OverdriveWeight", 3, options->bloom_overdrive);
1460
1461   curr_effect->set_texture("DiffuseA", rt->prescale_texture[next_index]);
1462
1463   char name[9] = "Diffuse*";
1464   for (int index = 1; index < bloom_count; index++)
1465   {
1466      name[7] = 'A' + index;
1467      curr_effect->set_texture(name, rt->bloom_texture[index - 1]);
1468   }
1469   for (int index = bloom_count; index < 11; index++)
1470   {
1471      name[7] = 'A' + index;
1472      curr_effect->set_texture(name, black_texture);
1473   }
1474
1475   next_index = rt->next_index(next_index);
1476   blit(rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count());
1477
1478   return next_index;
1479}
1480
1481int shaders::distortion_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1482{
1483   int next_index = source_index;
1484
1485   // skip distortion if no influencing settings
1486   if (options->reflection == 0 &&
1487      options->vignetting == 0 &&
1488      options->curvature == 0 &&
1489      options->round_corner == 0 &&
1490      options->smooth_border == 0)
1491   {
1492      return next_index;
1493   }
1494
1495   int screen_count = d3d->window().target()->current_view()->screens().count();
1496
1497   // only one screen is supported
1498   if (screen_count > 1)
1499   {
1500      return next_index;
1501   }
1502
1503   render_bounds bounds = d3d->window().target()->current_view()->bounds();
1504   render_bounds screen_bounds = d3d->window().target()->current_view()->screen_bounds();
1505
1506   // artworks are not supported
1507   if (bounds.x0 != screen_bounds.x0 ||
1508      bounds.y0 != screen_bounds.y0 ||
1509      bounds.x1 != screen_bounds.x1 ||
1510      bounds.y1 != screen_bounds.y1)
1511   {
1512      return next_index;
1513   }
1514
1515   bool orientation_swap_xy =
1516      (d3d->window().machine().system().flags & ORIENTATION_SWAP_XY) == ORIENTATION_SWAP_XY;
1517   bool rotation_swap_xy =
1518      (d3d->window().target()->orientation() & ROT90) == ROT90 ||
1519      (d3d->window().target()->orientation() & ROT270) == ROT270;
1520   int rotation_type =
1521      (d3d->window().target()->orientation() & ROT90) == ROT90
1522         ? 1
1523         : (d3d->window().target()->orientation() & ROT180) == ROT180
1524            ? 2
1525            : (d3d->window().target()->orientation() & ROT270) == ROT270
1526               ? 3
1527               : 0;
1528
1529   curr_effect = distortion_effect;
1530   curr_effect->update_uniforms();
1531   curr_effect->set_texture("DiffuseTexture", rt->prescale_texture[next_index]);
1532   curr_effect->set_bool("OrientationSwapXY", orientation_swap_xy);
1533   curr_effect->set_bool("RotationSwapXY", rotation_swap_xy);
1534   curr_effect->set_int("RotationType", rotation_type);
1535
1536   next_index = rt->next_index(next_index);
1537   blit(rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count());
1538
1539   return next_index;
1540}
1541
1542int shaders::vector_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1543{
1544   int next_index = source_index;
1545
1546   float time_params[2] = { 0.0f, 0.0f };
1547   float length_params[3] = { poly->get_line_length(), options->vector_length_scale, options->vector_length_ratio };
1548
1549   curr_effect = vector_effect;
1550   curr_effect->update_uniforms();
1551   curr_effect->set_vector("TimeParams", 2, time_params);
1552   curr_effect->set_vector("LengthParams", 3, length_params);
1553
1554   blit(rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count());
1555
1556   return next_index;
1557}
1558
1559int shaders::vector_buffer_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1560{
1561   int next_index = source_index;
1562
1563   curr_effect = default_effect;
1564   curr_effect->update_uniforms();
1565
1566   curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]);
1567   curr_effect->set_bool("PostPass", true);
1568   curr_effect->set_float("Brighten", 1.0f);
1569
1570   next_index = rt->next_index(next_index);
1571   blit(rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count());
1572
1573   return next_index;
1574}
1575
1576int shaders::screen_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1577{
1578   int next_index = source_index;
1579
1580   bool prepare_vector =
1581      (machine->first_screen()->screen_type() &  SCREEN_TYPE_VECTOR) == SCREEN_TYPE_VECTOR;
1582
1583   curr_effect = default_effect;
1584   curr_effect->update_uniforms();
1585
1586   curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]);
1587   curr_effect->set_bool("PostPass", true);
1588   curr_effect->set_float("Brighten", prepare_vector ? 1.0f : 0.0f);
1589
1590   // we do not clear the backbuffe here because multiple screens might rendered into
1591   blit(backbuffer, false, poly->get_type(), vertnum, poly->get_count());
1592
1593   if (avi_output_file != NULL)
1594   {
1595      blit(avi_final_target, false, poly->get_type(), vertnum, poly->get_count());
1596   }
1597
1598   if (render_snap)
1599   {
1600      blit(snap_target, false, poly->get_type(), vertnum, poly->get_count());
1601
1602      snap_rendered = true;
1603   }
1604
1605   return next_index;
1606}
1607
1608void shaders::menu_pass(poly_info *poly, int vertnum)
1609{
1610   curr_effect = default_effect;
1611   curr_effect->update_uniforms();
1612   curr_effect->set_bool("PostPass", false);
1613   curr_effect->set_float("Brighten", 0.0f);
1614
1615   blit(NULL, false, poly->get_type(), vertnum, poly->get_count());
1616}
1617
1618
1619//============================================================
1620//  shaders::render_quad
1621//============================================================
1622
1623void shaders::render_quad(poly_info *poly, int vertnum)
1624{
1625   if (!master_enable || !d3dintf->post_fx_available)
1626   {
1627      return;
1628   }
1629
1630   curr_texture = poly->get_texture();
1631   curr_poly = poly;
1632
1633   if (PRIMFLAG_GET_SCREENTEX(d3d->get_last_texture_flags()) && curr_texture != NULL)
1634   {
1635      curr_render_target = find_render_target(curr_texture);
1636
1637      render_target *rt = curr_render_target;
1638      if (rt == NULL)
1639      {
1640         return;
1641      }
1642
1643      cache_target *ct = find_cache_target(rt->screen_index, curr_texture->get_texinfo().width, curr_texture->get_texinfo().height);
1644
1645      int next_index = 0;
1646
1647      next_index = ntsc_pass(rt, next_index, poly, vertnum);
1648      next_index = color_convolution_pass(rt, next_index, poly, vertnum);
1649      next_index = prescale_pass(rt, next_index, poly, vertnum);
1650      next_index = deconverge_pass(rt, next_index, poly, vertnum);
1651      next_index = defocus_pass(rt, next_index, poly, vertnum); // 1st pass
1652      next_index = defocus_pass(rt, next_index, poly, vertnum); // 2nd pass
1653      next_index = phosphor_pass(rt, ct, next_index, poly, vertnum);
1654
1655      // create bloom textures
1656      int phosphor_index = next_index;
1657      next_index = post_pass(rt, next_index, poly, vertnum, true);
1658      next_index = downsample_pass(rt, next_index, poly, vertnum);
1659
1660      // apply bloom textures
1661      next_index = phosphor_index;
1662      next_index = post_pass(rt, next_index, poly, vertnum, false);
1663      next_index = bloom_pass(rt, next_index, poly, vertnum);
1664
1665      next_index = distortion_pass(rt, next_index, poly, vertnum);
1666
1667      // render on screen
1668      d3d->set_wrap(D3DTADDRESS_MIRROR);
1669      next_index = screen_pass(rt, next_index, poly, vertnum);
1670      d3d->set_wrap(PRIMFLAG_GET_TEXWRAP(poly->get_texture()->get_flags()) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP);
1671
1672      curr_texture->increment_frame_count();
1673      curr_texture->mask_frame_count(options->yiq_phase_count);
1674
1675      options->params_dirty = false;
1676   }
1677   else if (PRIMFLAG_GET_VECTOR(poly->get_flags()) && vector_enable)
1678   {
1679      curr_render_target = find_render_target(d3d->get_width(), d3d->get_height(), 0, 0);
1680
1681      render_target *rt = curr_render_target;
1682      if (rt == NULL)
1683      {
1684         return;
1685      }
1686
1687      lines_pending = true;
1688
1689      int next_index = 0;
1690
1691      next_index = vector_pass(rt, next_index, poly, vertnum);
1692
1693      HRESULT result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, backbuffer);
1694      if (result != D3D_OK)
1695      {
1696         osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result);
1697      }
1698   }
1699   else if (PRIMFLAG_GET_VECTORBUF(poly->get_flags()) && vector_enable)
1700   {
1701      curr_render_target = find_render_target(d3d->get_width(), d3d->get_height(), 0, 0);
1702
1703      render_target *rt = curr_render_target;
1704      if (rt == NULL)
1705      {
1706         return;
1707      }
1708
1709      cache_target *ct = find_cache_target(rt->screen_index, rt->width, rt->height);
1710
1711      int next_index = 0;
1712
1713      next_index = vector_buffer_pass(rt, next_index, poly, vertnum);
1714      next_index = defocus_pass(rt, next_index, poly, vertnum);
1715      next_index = phosphor_pass(rt, ct, next_index, poly, vertnum);
1716
1717      // create bloom textures
1718      int phosphor_index = next_index;
1719      next_index = post_pass(rt, next_index, poly, vertnum, true);
1720      next_index = downsample_pass(rt, next_index, poly, vertnum);
1721
1722      // apply bloom textures
1723      next_index = phosphor_index;
1724      next_index = post_pass(rt, next_index, poly, vertnum, false);
1725      next_index = bloom_pass(rt, next_index, poly, vertnum);
1726
1727      next_index = distortion_pass(rt, next_index, poly, vertnum);
1728
1729      // render on screen
1730      next_index = screen_pass(rt, next_index, poly, vertnum);
1731
1732      HRESULT result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, backbuffer);
1733      if (result != D3D_OK)
1734      {
1735         osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result);
1736      }
1737
1738      lines_pending = false;
1739   }
1740   else
1741   {
1742      menu_pass(poly, vertnum);
1743   }
1744
1745   curr_render_target = NULL;
1746   curr_texture = NULL;
1747   curr_poly = NULL;
1748}
1749
1750
1751//============================================================
1752//  shaders::end_draw
1753//============================================================
1754
1755void shaders::end_draw()
1756{
1757   if (!master_enable || !d3dintf->post_fx_available)
1758   {
1759      return;
1760   }
1761
1762   (*d3dintf->surface.release)(backbuffer);
1763}
1764
1765
1766//============================================================
1767//  shaders::register_prescaled_texture
1768//============================================================
1769
1770bool shaders::register_prescaled_texture(texture_info *texture)
1771{
1772   return register_texture(texture);
1773}
1774
1775
1776//============================================================
1777//  shaders::add_cache_target - register a cache target
1778//============================================================
1779bool shaders::add_cache_target(renderer* d3d, texture_info* info, int width, int height, int xprescale, int yprescale, int screen_index)
1780{
1781   cache_target* target = (cache_target*)global_alloc_clear(cache_target);
1782
1783   if (!target->init(d3d, d3dintf, width, height, xprescale, yprescale))
1784   {
1785      global_free(target);
1786      return false;
1787   }
1788
1789   if (info != NULL)
1790   {
1791      target->width = info->get_texinfo().width;
1792      target->height = info->get_texinfo().height;
1793   }
1794   else
1795   {
1796      target->width = d3d->get_width();
1797      target->height = d3d->get_height();
1798   }
1799
1800   target->next = cachehead;
1801   target->prev = NULL;
1802
1803   target->screen_index = screen_index;
1804
1805   if (cachehead != NULL)
1806   {
1807      cachehead->prev = target;
1808   }
1809   cachehead = target;
1810
1811   return true;
1812}
1813
1814render_target* shaders::get_vector_target()
1815{
1816   if (!vector_enable)
1817   {
1818      return NULL;
1819   }
1820
1821   return find_render_target(d3d->get_width(), d3d->get_height(), 0, 0);
1822}
1823
1824void shaders::create_vector_target(render_primitive *prim)
1825{
1826   if (!add_render_target(d3d, NULL, d3d->get_width(), d3d->get_height(), 1, 1))
1827   {
1828      vector_enable = false;
1829   }
1830}
1831
1832
1833//============================================================
1834//  shaders::add_render_target - register a render target
1835//============================================================
1836
1837bool shaders::add_render_target(renderer* d3d, texture_info* info, int width, int height, int xprescale, int yprescale)
1838{
1839   UINT32 screen_index = 0;
1840   UINT32 page_index = 0;
1841   if (info != NULL)
1842   {
1843      render_target *existing_target = find_render_target(info);
1844      if (existing_target != NULL)
1845      {
1846         remove_render_target(existing_target);
1847      }
1848
1849      UINT32 screen_index_data = (UINT32)info->get_texinfo().osddata;
1850      screen_index = screen_index_data >> 1;
1851      page_index = screen_index_data & 1;
1852   }
1853   else
1854   {
1855      render_target *existing_target = find_render_target(d3d->get_width(), d3d->get_height(), 0, 0);
1856      if (existing_target != NULL)
1857      {
1858         remove_render_target(existing_target);
1859      }
1860   }
1861
1862   render_target* target = (render_target*)global_alloc_clear(render_target);
1863
1864   if (!target->init(d3d, d3dintf, width, height, xprescale, yprescale))
1865   {
1866      global_free(target);
1867      return false;
1868   }
1869
1870   if (info != NULL)
1871   {
1872      target->width = info->get_texinfo().width;
1873      target->height = info->get_texinfo().height;
1874   }
1875   else
1876   {
1877      target->width = d3d->get_width();
1878      target->height = d3d->get_height();
1879   }
1880
1881   HRESULT result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, target->prescale_target[0]);
1882   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result);
1883   result = (*d3dintf->device.clear)(d3d->get_device(), 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0);
1884   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result);
1885   result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, backbuffer);
1886   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result);
1887
1888   target->screen_index = screen_index;
1889   target->page_index = page_index;
1890
1891   cache_target* cache = find_cache_target(target->screen_index, target->width, target->height);
1892   if (cache == NULL)
1893   {
1894      if (!add_cache_target(d3d, info, width, height, xprescale, yprescale, target->screen_index))
1895      {
1896         global_free(target);
1897         return false;
1898      }
1899   }
1900
1901   target->next = targethead;
1902   target->prev = NULL;
1903
1904   if (targethead != NULL)
1905   {
1906      targethead->prev = target;
1907   }
1908   targethead = target;
1909
1910   return true;
1911}
1912
1913
1914//============================================================
1915//  shaders::enumerate_screens
1916//============================================================
1917void shaders::enumerate_screens()
1918{
1919   screen_device_iterator iter(machine->root_device());
1920   num_screens = iter.count();
1921}
1922
1923
1924//============================================================
1925//  shaders::register_texture(texture::info)
1926//============================================================
1927
1928bool shaders::register_texture(texture_info *texture)
1929{
1930   int width = texture->get_width();
1931   int height = texture->get_height();
1932   int xscale = texture->get_xscale();
1933   int yscale = texture->get_yscale();
1934
1935   if (!master_enable || !d3dintf->post_fx_available)
1936   {
1937      return false;
1938   }
1939
1940   enumerate_screens();
1941
1942   // Find the nearest prescale factor that is over our screen size
1943   if (hlsl_prescale_x == 0)
1944   {
1945      hlsl_prescale_x = 1;
1946      while (width * xscale * hlsl_prescale_x <= d3d->get_width())
1947      {
1948         hlsl_prescale_x++;
1949      }
1950      hlsl_prescale_x--;
1951   }
1952
1953   if (hlsl_prescale_y == 0)
1954   {
1955      hlsl_prescale_y = 1;
1956      while (height * yscale * hlsl_prescale_y <= d3d->get_height())
1957      {
1958         hlsl_prescale_y++;
1959      }
1960      hlsl_prescale_y--;
1961   }
1962
1963   hlsl_prescale_x = ((hlsl_prescale_x == 0) ? 1 : hlsl_prescale_x);
1964   hlsl_prescale_y = ((hlsl_prescale_y == 0) ? 1 : hlsl_prescale_y);
1965
1966   if (!add_render_target(d3d, texture, width, height, xscale * hlsl_prescale_x, yscale * hlsl_prescale_y))
1967   {
1968      return false;
1969   }
1970
1971   options->params_dirty = true;
1972
1973   return true;
1974}
1975
1976
1977//============================================================
1978//  shaders::delete_resources
1979//============================================================
1980
1981void shaders::delete_resources(bool reset)
1982{
1983   if (!master_enable || !d3dintf->post_fx_available)
1984   {
1985      return;
1986   }
1987
1988   initialized = false;
1989
1990   options = NULL;
1991
1992   cache_target *currcache = cachehead;
1993   while(cachehead != NULL)
1994   {
1995      cachehead = currcache->next;
1996      global_free(currcache);
1997      currcache = cachehead;
1998   }
1999
2000   render_target *currtarget = targethead;
2001   while(targethead != NULL)
2002   {
2003      targethead = currtarget->next;
2004      global_free(currtarget);
2005      currtarget = targethead;
2006   }
2007
2008   if (downsample_effect != NULL)
2009   {
2010      delete downsample_effect;
2011      downsample_effect = NULL;
2012   }
2013   if (bloom_effect != NULL)
2014   {
2015      delete bloom_effect;
2016      bloom_effect = NULL;
2017   }
2018   if (vector_effect != NULL)
2019   {
2020      delete vector_effect;
2021      vector_effect = NULL;
2022   }
2023   if (default_effect != NULL)
2024   {
2025      delete default_effect;
2026      default_effect = NULL;
2027   }
2028   if (post_effect != NULL)
2029   {
2030      delete post_effect;
2031      post_effect = NULL;
2032   }
2033   if (distortion_effect != NULL)
2034   {
2035      delete distortion_effect;
2036      distortion_effect = NULL;
2037   }
2038   if (prescale_effect != NULL)
2039   {
2040      delete prescale_effect;
2041      prescale_effect = NULL;
2042   }
2043   if (phosphor_effect != NULL)
2044   {
2045      delete phosphor_effect;
2046      phosphor_effect = NULL;
2047   }
2048   if (focus_effect != NULL)
2049   {
2050      delete focus_effect;
2051      focus_effect = NULL;
2052   }
2053   if (deconverge_effect != NULL)
2054   {
2055      delete deconverge_effect;
2056      deconverge_effect = NULL;
2057   }
2058   if (color_effect != NULL)
2059   {
2060      delete color_effect;
2061      color_effect = NULL;
2062   }
2063   if (yiq_encode_effect != NULL)
2064   {
2065      delete yiq_encode_effect;
2066      yiq_encode_effect = NULL;
2067   }
2068   if (yiq_decode_effect != NULL)
2069   {
2070      delete yiq_decode_effect;
2071      yiq_decode_effect = NULL;
2072   }
2073
2074   if (backbuffer != NULL)
2075   {
2076      (*d3dintf->surface.release)(backbuffer);
2077      backbuffer = NULL;
2078   }
2079
2080   if (black_surface != NULL)
2081   {
2082      (*d3dintf->surface.release)(black_surface);
2083      black_surface = NULL;
2084   }
2085   if (black_texture != NULL)
2086   {
2087      (*d3dintf->texture.release)(black_texture);
2088      black_texture = NULL;
2089   }
2090
2091   if (avi_copy_texture != NULL)
2092   {
2093      (*d3dintf->texture.release)(avi_copy_texture);
2094      avi_copy_texture = NULL;
2095   }
2096
2097   if (avi_copy_surface != NULL)
2098   {
2099      (*d3dintf->surface.release)(avi_copy_surface);
2100      avi_copy_surface = NULL;
2101   }
2102
2103   if (avi_final_texture != NULL)
2104   {
2105      (*d3dintf->texture.release)(avi_final_texture);
2106      avi_final_texture = NULL;
2107   }
2108
2109   if (avi_final_target != NULL)
2110   {
2111      (*d3dintf->surface.release)(avi_final_target);
2112      avi_final_target = NULL;
2113   }
2114
2115   shadow_bitmap.reset();
2116}
2117
2118
2119//============================================================
2120//  get_vector
2121//============================================================
2122
2123static void get_vector(const char *data, int count, float *out, bool report_error)
2124{
2125   if (count > 3 &&
2126      sscanf(data, "%f,%f,%f,%f", &out[0], &out[1], &out[2], &out[3]) < 4 && report_error)
2127   {
2128      osd_printf_error("Illegal quad vector value = %s\n", data);
2129   }
2130   else if (count > 2 &&
2131      sscanf(data, "%f,%f,%f", &out[0], &out[1], &out[2]) < 3 && report_error)
2132   {
2133      osd_printf_error("Illegal triple vector value = %s\n", data);
2134   }
2135   else if (count > 1 &&
2136      sscanf(data, "%f,%f", &out[0], &out[1]) < 2 && report_error)
2137   {
2138      osd_printf_error("Illegal double vector value = %s\n", data);
2139   }
2140   else if (count > 0 &&
2141      sscanf(data, "%f", &out[0]) < 1 && report_error)
2142   {
2143      osd_printf_error("Illegal single vector value = %s\n", data);
2144   }
2145}
2146
2147
2148/*-------------------------------------------------
2149    slider_alloc - allocate a new slider entry
2150    currently duplicated from ui.c, this could
2151    be done in a more ideal way.
2152-------------------------------------------------*/
2153
2154static slider_state *slider_alloc(running_machine &machine, const char *title, INT32 minval, INT32 defval, INT32 maxval, INT32 incval, slider_update update, void *arg)
2155{
2156   int size = sizeof(slider_state) + strlen(title);
2157   slider_state *state = (slider_state *)auto_alloc_array_clear(machine, UINT8, size);
2158
2159   state->minval = minval;
2160   state->defval = defval;
2161   state->maxval = maxval;
2162   state->incval = incval;
2163   state->update = update;
2164   state->arg = arg;
2165   strcpy(state->description, title);
2166
2167   return state;
2168}
2169
2170
2171//============================================================
2172//  assorted global slider accessors
2173//============================================================
2174
2175static INT32 slider_set(float *option, float scale, const char *fmt, std::string *str, INT32 newval)
2176{
2177   if (option != NULL && newval != SLIDER_NOCHANGE)
2178   {
2179      *option = (float)newval * scale;
2180   }
2181   if (str != NULL)
2182   {
2183      strprintf(*str, fmt, *option);
2184   }
2185
2186   return floor(*option / scale + 0.5f);
2187}
2188
2189static INT32 slider_shadow_mask_alpha(running_machine &machine, void *arg, std::string *str, INT32 newval)
2190{
2191   return slider_set(&(((hlsl_options*)arg)->shadow_mask_alpha), 0.01f, "%2.2f", str, newval);
2192}
2193
2194static INT32 slider_shadow_mask_x_count(running_machine &machine, void *arg, std::string *str, INT32 newval)
2195{
2196   hlsl_options *options = (hlsl_options*)arg;
2197   if (newval != SLIDER_NOCHANGE)
2198   {
2199      options->shadow_mask_count_x = newval;
2200   }
2201   if (str != NULL)
2202   {
2203      strprintf(*str, "%d", options->shadow_mask_count_x);
2204   }
2205   options->params_dirty = true;
2206
2207   return options->shadow_mask_count_x;
2208}
2209
2210static INT32 slider_shadow_mask_y_count(running_machine &machine, void *arg, std::string *str, INT32 newval)
2211{
2212   hlsl_options *options = (hlsl_options*)arg;
2213   if (newval != SLIDER_NOCHANGE)
2214   {
2215      options->shadow_mask_count_y = newval;
2216   }
2217   if (str != NULL)
2218   {
2219      strprintf(*str, "%d", options->shadow_mask_count_y);
2220   }
2221   options->params_dirty = true;
2222
2223   return options->shadow_mask_count_y;
2224}
2225
2226static INT32 slider_shadow_mask_usize(running_machine &machine, void *arg, std::string *str, INT32 newval)
2227{
2228   ((hlsl_options*)arg)->params_dirty = true;
2229   return slider_set(&(((hlsl_options*)arg)->shadow_mask_u_size), 1.0f / 32.0f, "%2.5f", str, newval);
2230}
2231
2232static INT32 slider_shadow_mask_vsize(running_machine &machine, void *arg, std::string *str, INT32 newval)
2233{
2234   ((hlsl_options*)arg)->params_dirty = true;
2235   return slider_set(&(((hlsl_options*)arg)->shadow_mask_v_size), 1.0f / 32.0f, "%2.5f", str, newval);
2236}
2237
2238static INT32 slider_shadow_mask_uoffset(running_machine &machine, void *arg, std::string *str, INT32 newval)
2239{
2240   ((hlsl_options*)arg)->params_dirty = true;
2241   return slider_set(&(((hlsl_options*)arg)->shadow_mask_u_offset), 0.01f, "%2.2f", str, newval);
2242}
2243
2244static INT32 slider_shadow_mask_voffset(running_machine &machine, void *arg, std::string *str, INT32 newval)
2245{
2246   ((hlsl_options*)arg)->params_dirty = true;
2247   return slider_set(&(((hlsl_options*)arg)->shadow_mask_v_offset), 0.01f, "%2.2f", str, newval);
2248}
2249
2250static INT32 slider_curvature(running_machine &machine, void *arg, std::string *str, INT32 newval)
2251{
2252   ((hlsl_options*)arg)->params_dirty = true;
2253   return slider_set(&(((hlsl_options*)arg)->curvature), 0.01f, "%2.2f", str, newval);
2254}
2255
2256static INT32 slider_round_corner(running_machine &machine, void *arg, std::string *str, INT32 newval)
2257{
2258   ((hlsl_options*)arg)->params_dirty = true;
2259   return slider_set(&(((hlsl_options*)arg)->round_corner), 0.01f, "%2.2f", str, newval);
2260}
2261
2262static INT32 slider_smooth_border(running_machine &machine, void *arg, std::string *str, INT32 newval)
2263{
2264   ((hlsl_options*)arg)->params_dirty = true;
2265   return slider_set(&(((hlsl_options*)arg)->smooth_border), 0.01f, "%2.2f", str, newval);
2266}
2267
2268static INT32 slider_reflection(running_machine &machine, void *arg, std::string *str, INT32 newval)
2269{
2270   ((hlsl_options*)arg)->params_dirty = true;
2271   return slider_set(&(((hlsl_options*)arg)->reflection), 0.01f, "%2.2f", str, newval);
2272}
2273
2274static INT32 slider_vignetting(running_machine &machine, void *arg, std::string *str, INT32 newval)
2275{
2276   ((hlsl_options*)arg)->params_dirty = true;
2277   return slider_set(&(((hlsl_options*)arg)->vignetting), 0.01f, "%2.2f", str, newval);
2278}
2279
2280static INT32 slider_scanline_alpha(running_machine &machine, void *arg, std::string *str, INT32 newval)
2281{
2282   ((hlsl_options*)arg)->params_dirty = true;
2283   return slider_set(&(((hlsl_options*)arg)->scanline_alpha), 0.01f, "%2.2f", str, newval);
2284}
2285
2286static INT32 slider_scanline_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2287{
2288   ((hlsl_options*)arg)->params_dirty = true;
2289   return slider_set(&(((hlsl_options*)arg)->scanline_scale), 0.05f, "%2.2f", str, newval);
2290}
2291
2292static INT32 slider_scanline_height(running_machine &machine, void *arg, std::string *str, INT32 newval)
2293{
2294   ((hlsl_options*)arg)->params_dirty = true;
2295   return slider_set(&(((hlsl_options*)arg)->scanline_height), 0.05f, "%2.2f", str, newval);
2296}
2297
2298static INT32 slider_scanline_bright_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2299{
2300   ((hlsl_options*)arg)->params_dirty = true;
2301   return slider_set(&(((hlsl_options*)arg)->scanline_bright_scale), 0.05f, "%2.2f", str, newval);
2302}
2303
2304static INT32 slider_scanline_bright_offset(running_machine &machine, void *arg, std::string *str, INT32 newval)
2305{
2306   ((hlsl_options*)arg)->params_dirty = true;
2307   return slider_set(&(((hlsl_options*)arg)->scanline_bright_offset), 0.05f, "%2.2f", str, newval);
2308}
2309
2310static INT32 slider_scanline_offset(running_machine &machine, void *arg, std::string *str, INT32 newval)
2311{
2312   ((hlsl_options*)arg)->params_dirty = true;
2313   return slider_set(&(((hlsl_options*)arg)->scanline_offset), 0.05f, "%2.2f", str, newval);
2314}
2315
2316static INT32 slider_defocus_x(running_machine &machine, void *arg, std::string *str, INT32 newval)
2317{
2318   ((hlsl_options*)arg)->params_dirty = true;
2319   return slider_set(&(((hlsl_options*)arg)->defocus[0]), 0.5f, "%2.1f", str, newval);
2320}
2321
2322static INT32 slider_defocus_y(running_machine &machine, void *arg, std::string *str, INT32 newval)
2323{
2324   ((hlsl_options*)arg)->params_dirty = true;
2325   return slider_set(&(((hlsl_options*)arg)->defocus[1]), 0.5f, "%2.1f", str, newval);
2326}
2327
2328static INT32 slider_red_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval)
2329{
2330   ((hlsl_options*)arg)->params_dirty = true;
2331   return slider_set(&(((hlsl_options*)arg)->converge_x[0]), 0.1f, "%3.1f", str, newval);
2332}
2333
2334static INT32 slider_red_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval)
2335{
2336   ((hlsl_options*)arg)->params_dirty = true;
2337   return slider_set(&(((hlsl_options*)arg)->converge_y[0]), 0.1f, "%3.1f", str, newval);
2338}
2339
2340static INT32 slider_green_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval)
2341{
2342   ((hlsl_options*)arg)->params_dirty = true;
2343   return slider_set(&(((hlsl_options*)arg)->converge_x[1]), 0.1f, "%3.1f", str, newval);
2344}
2345
2346static INT32 slider_green_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval)
2347{
2348   ((hlsl_options*)arg)->params_dirty = true;
2349   return slider_set(&(((hlsl_options*)arg)->converge_y[1]), 0.1f, "%3.1f", str, newval);
2350}
2351
2352static INT32 slider_blue_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval)
2353{
2354   ((hlsl_options*)arg)->params_dirty = true;
2355   return slider_set(&(((hlsl_options*)arg)->converge_x[2]), 0.1f, "%3.1f", str, newval);
2356}
2357
2358static INT32 slider_blue_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval)
2359{
2360   ((hlsl_options*)arg)->params_dirty = true;
2361   return slider_set(&(((hlsl_options*)arg)->converge_y[2]), 0.1f, "%3.1f", str, newval);
2362}
2363
2364static INT32 slider_red_radial_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval)
2365{
2366   ((hlsl_options*)arg)->params_dirty = true;
2367   return slider_set(&(((hlsl_options*)arg)->radial_converge_x[0]), 0.1f, "%3.1f", str, newval);
2368}
2369
2370static INT32 slider_red_radial_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval)
2371{
2372   ((hlsl_options*)arg)->params_dirty = true;
2373   return slider_set(&(((hlsl_options*)arg)->radial_converge_y[0]), 0.1f, "%3.1f", str, newval);
2374}
2375
2376static INT32 slider_green_radial_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval)
2377{
2378   ((hlsl_options*)arg)->params_dirty = true;
2379   return slider_set(&(((hlsl_options*)arg)->radial_converge_x[1]), 0.1f, "%3.1f", str, newval);
2380}
2381
2382static INT32 slider_green_radial_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval)
2383{
2384   ((hlsl_options*)arg)->params_dirty = true;
2385   return slider_set(&(((hlsl_options*)arg)->radial_converge_y[1]), 0.1f, "%3.1f", str, newval);
2386}
2387
2388static INT32 slider_blue_radial_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval)
2389{
2390   ((hlsl_options*)arg)->params_dirty = true;
2391   return slider_set(&(((hlsl_options*)arg)->radial_converge_x[2]), 0.1f, "%3.1f", str, newval);
2392}
2393
2394static INT32 slider_blue_radial_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval)
2395{
2396   ((hlsl_options*)arg)->params_dirty = true;
2397   return slider_set(&(((hlsl_options*)arg)->radial_converge_y[2]), 0.1f, "%3.1f", str, newval);
2398}
2399
2400static INT32 slider_red_from_r(running_machine &machine, void *arg, std::string *str, INT32 newval)
2401{
2402   ((hlsl_options*)arg)->params_dirty = true;
2403   return slider_set(&(((hlsl_options*)arg)->red_ratio[0]), 0.005f, "%2.3f", str, newval);
2404}
2405
2406static INT32 slider_red_from_g(running_machine &machine, void *arg, std::string *str, INT32 newval)
2407{
2408   ((hlsl_options*)arg)->params_dirty = true;
2409   return slider_set(&(((hlsl_options*)arg)->red_ratio[1]), 0.005f, "%2.3f", str, newval);
2410}
2411
2412static INT32 slider_red_from_b(running_machine &machine, void *arg, std::string *str, INT32 newval)
2413{
2414   ((hlsl_options*)arg)->params_dirty = true;
2415   return slider_set(&(((hlsl_options*)arg)->red_ratio[2]), 0.005f, "%2.3f", str, newval);
2416}
2417
2418static INT32 slider_green_from_r(running_machine &machine, void *arg, std::string *str, INT32 newval)
2419{
2420   ((hlsl_options*)arg)->params_dirty = true;
2421   return slider_set(&(((hlsl_options*)arg)->grn_ratio[0]), 0.005f, "%2.3f", str, newval);
2422}
2423
2424static INT32 slider_green_from_g(running_machine &machine, void *arg, std::string *str, INT32 newval)
2425{
2426   ((hlsl_options*)arg)->params_dirty = true;
2427   return slider_set(&(((hlsl_options*)arg)->grn_ratio[1]), 0.005f, "%2.3f", str, newval);
2428}
2429
2430static INT32 slider_green_from_b(running_machine &machine, void *arg, std::string *str, INT32 newval)
2431{
2432   ((hlsl_options*)arg)->params_dirty = true;
2433   return slider_set(&(((hlsl_options*)arg)->grn_ratio[2]), 0.005f, "%2.3f", str, newval);
2434}
2435
2436static INT32 slider_blue_from_r(running_machine &machine, void *arg, std::string *str, INT32 newval)
2437{
2438   ((hlsl_options*)arg)->params_dirty = true;
2439   return slider_set(&(((hlsl_options*)arg)->blu_ratio[0]), 0.005f, "%2.3f", str, newval);
2440}
2441
2442static INT32 slider_blue_from_g(running_machine &machine, void *arg, std::string *str, INT32 newval)
2443{
2444   ((hlsl_options*)arg)->params_dirty = true;
2445   return slider_set(&(((hlsl_options*)arg)->blu_ratio[1]), 0.005f, "%2.3f", str, newval);
2446}
2447
2448static INT32 slider_blue_from_b(running_machine &machine, void *arg, std::string *str, INT32 newval)
2449{
2450   ((hlsl_options*)arg)->params_dirty = true;
2451   return slider_set(&(((hlsl_options*)arg)->blu_ratio[2]), 0.005f, "%2.3f", str, newval);
2452}
2453
2454static INT32 slider_red_offset(running_machine &machine, void *arg, std::string *str, INT32 newval)
2455{
2456   ((hlsl_options*)arg)->params_dirty = true;
2457   return slider_set(&(((hlsl_options*)arg)->offset[0]), 0.01f, "%2.2f", str, newval);
2458}
2459
2460static INT32 slider_green_offset(running_machine &machine, void *arg, std::string *str, INT32 newval)
2461{
2462   ((hlsl_options*)arg)->params_dirty = true;
2463   return slider_set(&(((hlsl_options*)arg)->offset[1]), 0.01f, "%2.2f", str, newval);
2464}
2465
2466static INT32 slider_blue_offset(running_machine &machine, void *arg, std::string *str, INT32 newval)
2467{
2468   ((hlsl_options*)arg)->params_dirty = true;
2469   return slider_set(&(((hlsl_options*)arg)->offset[2]), 0.01f, "%2.2f", str, newval);
2470}
2471
2472static INT32 slider_red_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2473{
2474   ((hlsl_options*)arg)->params_dirty = true;
2475   return slider_set(&(((hlsl_options*)arg)->scale[0]), 0.01f, "%2.2f", str, newval);
2476}
2477
2478static INT32 slider_green_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2479{
2480   ((hlsl_options*)arg)->params_dirty = true;
2481   return slider_set(&(((hlsl_options*)arg)->scale[1]), 0.01f, "%2.2f", str, newval);
2482}
2483
2484static INT32 slider_blue_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2485{
2486   ((hlsl_options*)arg)->params_dirty = true;
2487   return slider_set(&(((hlsl_options*)arg)->scale[2]), 0.01f, "%2.2f", str, newval);
2488}
2489
2490static INT32 slider_red_power(running_machine &machine, void *arg, std::string *str, INT32 newval)
2491{
2492   ((hlsl_options*)arg)->params_dirty = true;
2493   return slider_set(&(((hlsl_options*)arg)->power[0]), 0.05f, "%2.2f", str, newval);
2494}
2495
2496static INT32 slider_green_power(running_machine &machine, void *arg, std::string *str, INT32 newval)
2497{
2498   ((hlsl_options*)arg)->params_dirty = true;
2499   return slider_set(&(((hlsl_options*)arg)->power[1]), 0.05f, "%2.2f", str, newval);
2500}
2501
2502static INT32 slider_blue_power(running_machine &machine, void *arg, std::string *str, INT32 newval)
2503{
2504   ((hlsl_options*)arg)->params_dirty = true;
2505   return slider_set(&(((hlsl_options*)arg)->power[2]), 0.05f, "%2.2f", str, newval);
2506}
2507
2508static INT32 slider_red_floor(running_machine &machine, void *arg, std::string *str, INT32 newval)
2509{
2510   ((hlsl_options*)arg)->params_dirty = true;
2511   return slider_set(&(((hlsl_options*)arg)->floor[0]), 0.01f, "%2.2f", str, newval);
2512}
2513
2514static INT32 slider_green_floor(running_machine &machine, void *arg, std::string *str, INT32 newval)
2515{
2516   ((hlsl_options*)arg)->params_dirty = true;
2517   return slider_set(&(((hlsl_options*)arg)->floor[1]), 0.01f, "%2.2f", str, newval);
2518}
2519
2520static INT32 slider_blue_floor(running_machine &machine, void *arg, std::string *str, INT32 newval)
2521{
2522   ((hlsl_options*)arg)->params_dirty = true;
2523   return slider_set(&(((hlsl_options*)arg)->floor[2]), 0.01f, "%2.2f", str, newval);
2524}
2525
2526static INT32 slider_red_phosphor_life(running_machine &machine, void *arg, std::string *str, INT32 newval)
2527{
2528   ((hlsl_options*)arg)->params_dirty = true;
2529   return slider_set(&(((hlsl_options*)arg)->phosphor[0]), 0.01f, "%2.2f", str, newval);
2530}
2531
2532static INT32 slider_green_phosphor_life(running_machine &machine, void *arg, std::string *str, INT32 newval)
2533{
2534   ((hlsl_options*)arg)->params_dirty = true;
2535   return slider_set(&(((hlsl_options*)arg)->phosphor[1]), 0.01f, "%2.2f", str, newval);
2536}
2537
2538static INT32 slider_blue_phosphor_life(running_machine &machine, void *arg, std::string *str, INT32 newval)
2539{
2540   ((hlsl_options*)arg)->params_dirty = true;
2541   return slider_set(&(((hlsl_options*)arg)->phosphor[2]), 0.01f, "%2.2f", str, newval);
2542}
2543
2544static INT32 slider_saturation(running_machine &machine, void *arg, std::string *str, INT32 newval)
2545{
2546   ((hlsl_options*)arg)->params_dirty = true;
2547   return slider_set(&(((hlsl_options*)arg)->saturation), 0.01f, "%2.2f", str, newval);
2548}
2549
2550static INT32 slider_vector_attenuation(running_machine &machine, void *arg, std::string *str, INT32 newval)
2551{
2552   ((hlsl_options*)arg)->params_dirty = true;
2553   return slider_set(&(((hlsl_options*)arg)->vector_length_scale), 0.01f, "%1.2f", str, newval);
2554}
2555
2556static INT32 slider_vector_length_max(running_machine &machine, void *arg, std::string *str, INT32 newval)
2557{
2558   ((hlsl_options*)arg)->params_dirty = true;
2559   return slider_set(&(((hlsl_options*)arg)->vector_length_ratio), 1.0f, "%4f", str, newval);
2560}
2561
2562static INT32 slider_bloom_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2563{
2564   ((hlsl_options*)arg)->params_dirty = true;
2565   return slider_set(&(((hlsl_options*)arg)->bloom_scale), 0.001f, "%1.3f", str, newval);
2566}
2567
2568static INT32 slider_bloom_red_overdrive(running_machine &machine, void *arg, std::string *str, INT32 newval)
2569{
2570   ((hlsl_options*)arg)->params_dirty = true;
2571   return slider_set(&(((hlsl_options*)arg)->bloom_overdrive[0]), 0.001f, "%1.3f", str, newval);
2572}
2573
2574static INT32 slider_bloom_green_overdrive(running_machine &machine, void *arg, std::string *str, INT32 newval)
2575{
2576   ((hlsl_options*)arg)->params_dirty = true;
2577   return slider_set(&(((hlsl_options*)arg)->bloom_overdrive[1]), 0.001f, "%1.3f", str, newval);
2578}
2579
2580static INT32 slider_bloom_blue_overdrive(running_machine &machine, void *arg, std::string *str, INT32 newval)
2581{
2582   ((hlsl_options*)arg)->params_dirty = true;
2583   return slider_set(&(((hlsl_options*)arg)->bloom_overdrive[2]), 0.001f, "%1.3f", str, newval);
2584}
2585
2586static INT32 slider_bloom_lvl0_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2587{
2588   ((hlsl_options*)arg)->params_dirty = true;
2589   return slider_set(&(((hlsl_options*)arg)->bloom_level0_weight), 0.01f, "%1.2f", str, newval);
2590}
2591
2592static INT32 slider_bloom_lvl1_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2593{
2594   ((hlsl_options*)arg)->params_dirty = true;
2595   return slider_set(&(((hlsl_options*)arg)->bloom_level1_weight), 0.01f, "%1.2f", str, newval);
2596}
2597
2598static INT32 slider_bloom_lvl2_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2599{
2600   ((hlsl_options*)arg)->params_dirty = true;
2601   return slider_set(&(((hlsl_options*)arg)->bloom_level2_weight), 0.01f, "%1.2f", str, newval);
2602}
2603
2604static INT32 slider_bloom_lvl3_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2605{
2606   ((hlsl_options*)arg)->params_dirty = true;
2607   return slider_set(&(((hlsl_options*)arg)->bloom_level3_weight), 0.01f, "%1.2f", str, newval);
2608}
2609
2610static INT32 slider_bloom_lvl4_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2611{
2612   ((hlsl_options*)arg)->params_dirty = true;
2613   return slider_set(&(((hlsl_options*)arg)->bloom_level4_weight), 0.01f, "%1.2f", str, newval);
2614}
2615
2616static INT32 slider_bloom_lvl5_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2617{
2618   ((hlsl_options*)arg)->params_dirty = true;
2619   return slider_set(&(((hlsl_options*)arg)->bloom_level5_weight), 0.01f, "%1.2f", str, newval);
2620}
2621
2622static INT32 slider_bloom_lvl6_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2623{
2624   ((hlsl_options*)arg)->params_dirty = true;
2625   return slider_set(&(((hlsl_options*)arg)->bloom_level6_weight), 0.01f, "%1.2f", str, newval);
2626}
2627
2628static INT32 slider_bloom_lvl7_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2629{
2630   ((hlsl_options*)arg)->params_dirty = true;
2631   return slider_set(&(((hlsl_options*)arg)->bloom_level7_weight), 0.01f, "%1.2f", str, newval);
2632}
2633
2634static INT32 slider_bloom_lvl8_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2635{
2636   ((hlsl_options*)arg)->params_dirty = true;
2637   return slider_set(&(((hlsl_options*)arg)->bloom_level8_weight), 0.01f, "%1.2f", str, newval);
2638}
2639
2640static INT32 slider_bloom_lvl9_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2641{
2642   ((hlsl_options*)arg)->params_dirty = true;
2643   return slider_set(&(((hlsl_options*)arg)->bloom_level9_weight), 0.01f, "%1.2f", str, newval);
2644}
2645
2646static INT32 slider_bloom_lvl10_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2647{
2648   ((hlsl_options*)arg)->params_dirty = true;
2649   return slider_set(&(((hlsl_options*)arg)->bloom_level10_weight), 0.01f, "%1.2f", str, newval);
2650}
2651
2652
2653//============================================================
2654//  init_slider_list
2655//============================================================
2656
2657shaders::slider_desc shaders::s_sliders[] =
2658{
2659   { "Vector Length Attenuation",           0,    80,   100, 1, 2, slider_vector_attenuation },
2660   { "Vector Attenuation Length Limit",     1,   500,  1000, 1, 2, slider_vector_length_max },
2661   { "Shadow Mask Darkness",                0,     0,   100, 1, 7, slider_shadow_mask_alpha },
2662   { "Shadow Mask X Count",                 1,     6,  1024, 1, 7, slider_shadow_mask_x_count },
2663   { "Shadow Mask Y Count",                 1,     6,  1024, 1, 7, slider_shadow_mask_y_count },
2664   { "Shadow Mask Pixel Count X",           1,     6,    64, 1, 7, slider_shadow_mask_usize },
2665   { "Shadow Mask Pixel Count Y",           1,     6,    64, 1, 7, slider_shadow_mask_vsize },
2666   { "Shadow Mask Offset X",             -100,     0,   100, 1, 7, slider_shadow_mask_uoffset },
2667   { "Shadow Mask Offset Y",             -100,     0,   100, 1, 7, slider_shadow_mask_voffset },
2668   { "Screen Curvature",                    0,     0,   100, 1, 7, slider_curvature },
2669   { "Screen Round Corner",                 0,     0,   100, 1, 7, slider_round_corner },
2670   { "Screen Smooth Border",                0,     0,   100, 1, 7, slider_smooth_border },
2671   { "Screen Reflection",                   0,     0,   100, 1, 7, slider_reflection },
2672   { "Image Vignetting",                    0,     0,   100, 1, 7, slider_vignetting },
2673   { "Scanline Darkness",                   0,   100,   100, 1, 1, slider_scanline_alpha },
2674   { "Scanline Screen Height",              1,    20,    80, 1, 1, slider_scanline_scale },
2675   { "Scanline Indiv. Height",              1,    20,    80, 1, 1, slider_scanline_height },
2676   { "Scanline Brightness",                 0,    20,    40, 1, 1, slider_scanline_bright_scale },
2677   { "Scanline Brightness Overdrive",       0,     0,    20, 1, 1, slider_scanline_bright_offset },
2678   { "Scanline Jitter",                     0,     0,    40, 1, 1, slider_scanline_offset },
2679   { "Defocus X",                           0,     0,    64, 1, 3, slider_defocus_x },
2680   { "Defocus Y",                           0,     0,    64, 1, 3, slider_defocus_y },
2681   { "Red Position Offset X",           -1500,     3,  1500, 1, 3, slider_red_converge_x },
2682   { "Red Position Offset Y",           -1500,     0,  1500, 1, 3, slider_red_converge_y },
2683   { "Green Position Offset X",         -1500,     0,  1500, 1, 3, slider_green_converge_x },
2684   { "Green Position Offset Y",         -1500,     3,  1500, 1, 3, slider_green_converge_y },
2685   { "Blue Position Offset X",          -1500,     3,  1500, 1, 3, slider_blue_converge_x },
2686   { "Blue Position Offset Y",          -1500,     3,  1500, 1, 3, slider_blue_converge_y },
2687   { "Red Convergence X",               -1500,     0,  1500, 1, 3, slider_red_radial_converge_x },
2688   { "Red Convergence Y",               -1500,     0,  1500, 1, 3, slider_red_radial_converge_y },
2689   { "Green Convergence X",             -1500,     0,  1500, 1, 3, slider_green_radial_converge_x },
2690   { "Green Convergence Y",             -1500,     0,  1500, 1, 3, slider_green_radial_converge_y },
2691   { "Blue Convergence X",              -1500,     0,  1500, 1, 3, slider_blue_radial_converge_x },
2692   { "Blue Convergence Y",              -1500,     0,  1500, 1, 3, slider_blue_radial_converge_y },
2693   { "Red Output from Red Input",        -400,     0,   400, 5, 7, slider_red_from_r },
2694   { "Red Output from Green Input",      -400,     0,   400, 5, 7, slider_red_from_g },
2695   { "Red Output from Blue Input",       -400,     0,   400, 5, 7, slider_red_from_b },
2696   { "Green Output from Red Input",      -400,     0,   400, 5, 7, slider_green_from_r },
2697   { "Green Output from Green Input",    -400,     0,   400, 5, 7, slider_green_from_g },
2698   { "Green Output from Blue Input",     -400,     0,   400, 5, 7, slider_green_from_b },
2699   { "Blue Output from Red Input",       -400,     0,   400, 5, 7, slider_blue_from_r },
2700   { "Blue Output from Green Input",     -400,     0,   400, 5, 7, slider_blue_from_g },
2701   { "Blue Output from Blue Input",      -400,     0,   400, 5, 7, slider_blue_from_b },
2702   { "Saturation",                          0,   140,   400, 1, 7, slider_saturation },
2703   { "Red DC Offset",                    -100,     0,   100, 1, 7, slider_red_offset },
2704   { "Green DC Offset",                  -100,     0,   100, 1, 7, slider_green_offset },
2705   { "Blue DC Offset",                   -100,     0,   100, 1, 7, slider_blue_offset },
2706   { "Red Scale",                        -200,    95,   200, 1, 7, slider_red_scale },
2707   { "Green Scale",                      -200,    95,   200, 1, 7, slider_green_scale },
2708   { "Blue Scale",                       -200,    95,   200, 1, 7, slider_blue_scale },
2709   { "Red Gamma",                         -80,    16,    80, 1, 7, slider_red_power },
2710   { "Green Gamma",                       -80,    16,    80, 1, 7, slider_green_power },
2711   { "Blue Gamma",                        -80,    16,    80, 1, 7, slider_blue_power },
2712   { "Red Floor",                           0,     5,   100, 1, 7, slider_red_floor },
2713   { "Green Floor",                         0,     5,   100, 1, 7, slider_green_floor },
2714   { "Blue Floor",                          0,     5,   100, 1, 7, slider_blue_floor },
2715   { "Red Phosphor Life",                   0,    40,   100, 1, 7, slider_red_phosphor_life },
2716   { "Green Phosphor Life",                 0,    40,   100, 1, 7, slider_green_phosphor_life },
2717   { "Blue Phosphor Life",                  0,    40,   100, 1, 7, slider_blue_phosphor_life },
2718   { "Bloom Scale",                         0,   250,  2000, 5, 7, slider_bloom_scale },
2719   { "Bloom Red Overdrive",                 0,   250,  2000, 5, 7, slider_bloom_red_overdrive },
2720   { "Bloom Green Overdrive",               0,   250,  2000, 5, 7, slider_bloom_green_overdrive },
2721   { "Bloom Blue Overdrive",                0,   250,  2000, 5, 7, slider_bloom_blue_overdrive },
2722   { "Bloom Level 0 Scale",                 0,   100,   100, 1, 7, slider_bloom_lvl0_scale },
2723   { "Bloom Level 1 Scale",                 0,    21,   100, 1, 7, slider_bloom_lvl1_scale },
2724   { "Bloom Level 2 Scale",                 0,    19,   100, 1, 7, slider_bloom_lvl2_scale },
2725   { "Bloom Level 3 Scale",                 0,    17,   100, 1, 7, slider_bloom_lvl3_scale },
2726   { "Bloom Level 4 Scale",                 0,    15,   100, 1, 7, slider_bloom_lvl4_scale },
2727   { "Bloom Level 5 Scale",                 0,    14,   100, 1, 7, slider_bloom_lvl5_scale },
2728   { "Bloom Level 6 Scale",                 0,    13,   100, 1, 7, slider_bloom_lvl6_scale },
2729   { "Bloom Level 7 Scale",                 0,    12,   100, 1, 7, slider_bloom_lvl7_scale },
2730   { "Bloom Level 8 Scale",                 0,    11,   100, 1, 7, slider_bloom_lvl8_scale },
2731   { "Bloom Level 9 Scale",                 0,    10,   100, 1, 7, slider_bloom_lvl9_scale },
2732   { "Bloom Level 10 Scale",                0,     9,   100, 1, 7, slider_bloom_lvl10_scale },
2733   { NULL, 0, 0, 0, 0, 0, NULL },
2734};
2735
2736slider_state *shaders::init_slider_list()
2737{
2738   if (!master_enable || !d3dintf->post_fx_available)
2739   {
2740      g_slider_list = NULL;
2741      return NULL;
2742   }
2743
2744   slider_state *listhead = NULL;
2745   slider_state **tailptr = &listhead;
2746
2747   for (int index = 0; s_sliders[index].name != NULL; index++)
2748   {
2749      slider_desc *slider = &s_sliders[index];
2750
2751      int screen_type = machine->first_screen()->screen_type();
2752      if ((screen_type == SCREEN_TYPE_VECTOR && (slider->screen_type & SLIDER_SCREEN_TYPE_VECTOR) == SLIDER_SCREEN_TYPE_VECTOR) ||
2753         (screen_type == SCREEN_TYPE_RASTER && (slider->screen_type & SLIDER_SCREEN_TYPE_RASTER) == SLIDER_SCREEN_TYPE_RASTER) ||
2754         (screen_type == SCREEN_TYPE_LCD    && (slider->screen_type & SLIDER_SCREEN_TYPE_LCD)    == SLIDER_SCREEN_TYPE_LCD))
2755      {
2756         *tailptr = slider_alloc(*machine, slider->name, slider->minval, slider->defval, slider->maxval, slider->step, slider->adjustor, (void*)options);
2757         tailptr = &(*tailptr)->next;
2758      }
2759   }
2760
2761   return listhead;
2762}
2763
2764
2765//============================================================
2766//  uniform functions
2767//============================================================
2768
2769uniform::uniform(effect *shader, const char *name, uniform_type type, int id)
2770{
2771   m_shader = shader;
2772   m_type = type;
2773   m_next = NULL;
2774   m_handle = m_shader->get_parameter(NULL, name);
2775   m_ival = 0;
2776   memset(m_vec, 0, sizeof(float) * 4);
2777   m_mval = NULL;
2778   m_texture = NULL;
2779   m_id = id;
2780
2781   switch (type)
2782   {
2783      case UT_INT:
2784      case UT_FLOAT:
2785      case UT_MATRIX:
2786      case UT_SAMPLER:
2787         m_count = 1;
2788         break;
2789      case UT_VEC2:
2790         m_count = 2;
2791         break;
2792      case UT_VEC3:
2793         m_count = 3;
2794         break;
2795      case UT_VEC4:
2796         m_count = 4;
2797         break;
2798      default:
2799         m_count = 1;
2800         break;
2801   }
2802}
2803
2804void uniform::set_next(uniform *next)
2805{
2806   m_next = next;
2807}
2808
2809void uniform::update()
2810{
2811   if (m_id >= CU_COUNT)
2812   {
2813      return;
2814   }
2815
2816   shaders *shadersys = m_shader->m_shaders;
2817   hlsl_options *options = shadersys->options;
2818   renderer *d3d = shadersys->d3d;
2819
2820   switch (m_id)
2821   {
2822      case CU_SCREEN_DIMS:
2823      {
2824         vec2f screendims = d3d->get_dims();
2825         m_shader->set_vector("ScreenDims", 2, &screendims.c.x);
2826         break;
2827      }
2828      case CU_SOURCE_DIMS:
2829      {
2830         vec2f sourcedims = shadersys->curr_texture->get_rawdims();
2831         m_shader->set_vector("SourceDims", 2, &sourcedims.c.x);
2832         break;
2833      }
2834      case CU_SOURCE_RECT:
2835      {
2836         vec2f delta = shadersys->curr_texture->get_uvstop() - shadersys->curr_texture->get_uvstart();
2837         m_shader->set_vector("SourceRect", 2, &delta.c.x);
2838         break;
2839      }
2840      case CU_TARGET_DIMS:
2841      {
2842         if (shadersys->curr_render_target == NULL)
2843         {
2844            float targetdims[2] = { 0.0f, 0.0f };
2845            m_shader->set_vector("TargetDims", 2, targetdims);
2846         }
2847         else
2848         {
2849            float targetdims[2] = { shadersys->curr_render_target->target_width, shadersys->curr_render_target->target_height };
2850            m_shader->set_vector("TargetDims", 2, targetdims);
2851         }
2852         break;
2853      }
2854      case CU_QUAD_DIMS:
2855      {
2856         float quaddims[2] = { shadersys->curr_poly->get_prim_width(), shadersys->curr_poly->get_prim_height() };
2857         m_shader->set_vector("QuadDims", 2, quaddims);
2858         break;
2859      }
2860
2861      case CU_NTSC_CCFREQ:
2862         m_shader->set_float("CCValue", options->yiq_cc);
2863         break;
2864      case CU_NTSC_A:
2865         m_shader->set_float("AValue", options->yiq_a);
2866         break;
2867      case CU_NTSC_B:
2868         m_shader->set_float("BValue", options->yiq_b);
2869         break;
2870      case CU_NTSC_O:
2871         m_shader->set_float("OValue", options->yiq_o);
2872         break;
2873      case CU_NTSC_P:
2874         m_shader->set_float("PValue", options->yiq_p);
2875         break;
2876      case CU_NTSC_NOTCH:
2877         m_shader->set_float("NotchHalfWidth", options->yiq_n);
2878         break;
2879      case CU_NTSC_YFREQ:
2880         m_shader->set_float("YFreqResponse", options->yiq_y);
2881         break;
2882      case CU_NTSC_IFREQ:
2883         m_shader->set_float("IFreqResponse", options->yiq_i);
2884         break;
2885      case CU_NTSC_QFREQ:
2886         m_shader->set_float("QFreqResponse", options->yiq_q);
2887         break;
2888      case CU_NTSC_HTIME:
2889         m_shader->set_float("ScanTime", options->yiq_scan_time);
2890         break;
2891      case CU_NTSC_ENABLE:
2892         m_shader->set_float("YIQEnable", options->yiq_enable ? 1.0f : 0.0f);
2893         break;
2894
2895      case CU_COLOR_RED_RATIOS:
2896         m_shader->set_vector("RedRatios", 3, options->red_ratio);
2897         break;
2898      case CU_COLOR_GRN_RATIOS:
2899         m_shader->set_vector("GrnRatios", 3, options->grn_ratio);
2900         break;
2901      case CU_COLOR_BLU_RATIOS:
2902         m_shader->set_vector("BluRatios", 3, options->blu_ratio);
2903         break;
2904      case CU_COLOR_OFFSET:
2905         m_shader->set_vector("Offset", 3, options->offset);
2906         break;
2907      case CU_COLOR_SCALE:
2908         m_shader->set_vector("Scale", 3, options->scale);
2909         break;
2910      case CU_COLOR_SATURATION:
2911         m_shader->set_float("Saturation", options->saturation);
2912         break;
2913
2914      case CU_CONVERGE_LINEAR_X:
2915         m_shader->set_vector("ConvergeX", 3, options->converge_x);
2916         break;
2917      case CU_CONVERGE_LINEAR_Y:
2918         m_shader->set_vector("ConvergeY", 3, options->converge_y);
2919         break;
2920      case CU_CONVERGE_RADIAL_X:
2921         m_shader->set_vector("RadialConvergeX", 3, options->radial_converge_x);
2922         break;
2923      case CU_CONVERGE_RADIAL_Y:
2924         m_shader->set_vector("RadialConvergeY", 3, options->radial_converge_y);
2925         break;
2926
2927      case CU_FOCUS_SIZE:
2928         m_shader->set_vector("Defocus", 2, &options->defocus[0]);
2929         break;
2930
2931      case CU_PHOSPHOR_LIFE:
2932         m_shader->set_vector("Phosphor", 3, options->phosphor);
2933         break;
2934
2935      case CU_POST_REFLECTION:
2936         m_shader->set_float("ReflectionAmount", options->reflection);
2937         break;
2938      case CU_POST_VIGNETTING:
2939         m_shader->set_float("VignettingAmount", options->vignetting);
2940         break;
2941      case CU_POST_CURVATURE:
2942         m_shader->set_float("CurvatureAmount", options->curvature);
2943         break;
2944      case CU_POST_ROUND_CORNER:
2945         m_shader->set_float("RoundCornerAmount", options->round_corner);
2946         break;
2947      case CU_POST_SMOOTH_BORDER:
2948         m_shader->set_float("SmoothBorderAmount", options->smooth_border);
2949         break;
2950      case CU_POST_SHADOW_ALPHA:
2951         m_shader->set_float("ShadowAlpha", shadersys->shadow_texture == NULL ? 0.0f : options->shadow_mask_alpha);
2952         break;
2953      case CU_POST_SHADOW_COUNT:
2954      {
2955         float shadowcount[2] = { options->shadow_mask_count_x, options->shadow_mask_count_y };
2956         m_shader->set_vector("ShadowCount", 2, shadowcount);
2957         break;
2958      }
2959      case CU_POST_SHADOW_UV:
2960      {
2961         float shadowuv[2] = { options->shadow_mask_u_size, options->shadow_mask_v_size };
2962         m_shader->set_vector("ShadowUV", 2, shadowuv);
2963         break;
2964      }
2965      case CU_POST_SHADOW_UV_OFFSET:
2966      {
2967         float shadowuv[2] = { options->shadow_mask_u_offset, options->shadow_mask_v_offset };
2968         m_shader->set_vector("ShadowUVOffset", 2, shadowuv);
2969         break;
2970      }
2971      case CU_POST_SHADOW_DIMS:
2972      {
2973         vec2f shadow_dims;
2974
2975         if (shadersys->shadow_texture)
2976         {
2977            shadow_dims = shadersys->shadow_texture->get_rawdims();
2978         }
2979         else
2980         {
2981            shadow_dims.c.x = 1.0f;
2982            shadow_dims.c.y = 1.0f;
2983         }
2984
2985         m_shader->set_vector("ShadowDims", 2, &shadow_dims.c.x);
2986         break;
2987      }
2988      case CU_POST_SCANLINE_ALPHA:
2989         m_shader->set_float("ScanlineAlpha", options->scanline_alpha);
2990         break;
2991      case CU_POST_SCANLINE_SCALE:
2992         m_shader->set_float("ScanlineScale", options->scanline_scale);
2993         break;
2994      case CU_POST_SCANLINE_HEIGHT:
2995         m_shader->set_float("ScanlineHeight", options->scanline_height);
2996         break;
2997      case CU_POST_SCANLINE_BRIGHT_SCALE:
2998         m_shader->set_float("ScanlineBrightScale", options->scanline_bright_scale);
2999         break;
3000      case CU_POST_SCANLINE_BRIGHT_OFFSET:
3001         m_shader->set_float("ScanlineBrightOffset", options->scanline_bright_offset);
3002         break;
3003      case CU_POST_POWER:
3004         m_shader->set_vector("Power", 3, options->power);
3005         break;
3006      case CU_POST_FLOOR:
3007         m_shader->set_vector("Floor", 3, options->floor);
3008         break;
3009
3010      case CU_BLOOM_RESCALE:
3011         m_shader->set_float("BloomRescale", options->bloom_scale);
3012         break;
3013      case CU_BLOOM_LVL0123_WEIGHTS:
3014      {
3015         float weight0123[4] = { options->bloom_level0_weight, options->bloom_level1_weight, options->bloom_level2_weight, options->bloom_level3_weight };
3016         m_shader->set_vector("Level0123Weight", 4, weight0123);
3017         break;
3018      }
3019      case CU_BLOOM_LVL4567_WEIGHTS:
3020      {
3021         float weight4567[4] = { options->bloom_level4_weight, options->bloom_level5_weight, options->bloom_level6_weight, options->bloom_level7_weight };
3022         m_shader->set_vector("Level4567Weight", 4, weight4567);
3023         break;
3024      }
3025      case CU_BLOOM_LVL89A_WEIGHTS:
3026      {
3027         float weight89A[3]  = { options->bloom_level8_weight, options->bloom_level9_weight, options->bloom_level10_weight };
3028         m_shader->set_vector("Level89AWeight", 3, weight89A);
3029         break;
3030      }
3031   }
3032}
3033
3034void uniform::set(float x, float y, float z, float w)
3035{
3036   m_vec[0] = x;
3037   m_vec[1] = y;
3038   m_vec[2] = z;
3039   m_vec[3] = w;
3040}
3041
3042void uniform::set(float x, float y, float z)
3043{
3044   m_vec[0] = x;
3045   m_vec[1] = y;
3046   m_vec[2] = z;
3047}
3048
3049void uniform::set(float x, float y)
3050{
3051   m_vec[0] = x;
3052   m_vec[1] = y;
3053}
3054
3055void uniform::set(float x)
3056{
3057   m_vec[0] = x;
3058}
3059
3060void uniform::set(int x)
3061{
3062   m_ival = x;
3063}
3064
3065void uniform::set(matrix *mat)
3066{
3067   m_mval = mat;
3068}
3069
3070void uniform::set(texture *tex)
3071{
3072   m_texture = tex;
3073}
3074
3075void uniform::upload()
3076{
3077   switch (m_type)
3078   {
3079      case UT_INT:
3080         m_shader->set_int(m_handle, m_ival);
3081         break;
3082      case UT_FLOAT:
3083         m_shader->set_float(m_handle, m_vec[0]);
3084         break;
3085      case UT_VEC2:
3086      case UT_VEC3:
3087      case UT_VEC4:
3088         m_shader->set_vector(m_handle, m_count, m_vec);
3089         break;
3090      case UT_MATRIX:
3091         m_shader->set_matrix(m_handle, m_mval);
3092         break;
3093      case UT_SAMPLER:
3094         m_shader->set_texture(m_handle, m_texture);
3095         break;
3096   }
3097}
3098
3099
3100//============================================================
3101//  effect functions
3102//============================================================
3103
3104effect::effect(shaders *shadersys, device *dev, const char *name, const char *path)
3105{
3106   IDirect3DDevice9 *device = (IDirect3DDevice9 *)dev;
3107   LPD3DXBUFFER buffer_errors = NULL;
3108
3109   m_shaders = shadersys;
3110   m_uniform_head = NULL;
3111   m_uniform_tail = NULL;
3112   m_effect = NULL;
3113   m_valid = false;
3114
3115   char name_cstr[1024];
3116   sprintf(name_cstr, "%s\\%s", path, name);
3117   TCHAR *effect_name = tstring_from_utf8(name_cstr);
3118
3119   HRESULT hr = (*g_load_effect)(device, effect_name, NULL, NULL, 0, NULL, &m_effect, &buffer_errors);
3120   if (FAILED(hr))
3121   {
3122      if (buffer_errors != NULL)
3123      {
3124         LPVOID compile_errors = buffer_errors->GetBufferPointer();
3125         printf("Unable to compile shader: %s\n", (const char*)compile_errors); fflush(stdout);
3126      }
3127      else
3128      {
3129         printf("Shader %s is missing, corrupt or cannot be compiled.\n", (const char*)name); fflush(stdout);
3130      }
3131   }
3132   else
3133   {
3134      m_valid = true;
3135   }
3136
3137   osd_free(effect_name);
3138}
3139
3140effect::~effect()
3141{
3142   m_effect->Release();
3143   m_effect = NULL;
3144   uniform *curr = m_uniform_head;
3145   while (curr != NULL)
3146   {
3147      uniform *next = curr->get_next();
3148      delete curr;
3149      curr = next;
3150   }
3151   m_uniform_head = NULL;
3152   m_uniform_tail = NULL;
3153}
3154
3155void effect::add_uniform(const char *name, uniform::uniform_type type, int id)
3156{
3157   uniform *newuniform = new uniform(this, name, type, id);
3158   if (newuniform == NULL)
3159   {
3160      return;
3161   }
3162
3163   if (m_uniform_head == NULL)
3164   {
3165      m_uniform_head = newuniform;
3166   }
3167   if (m_uniform_tail != NULL)
3168   {
3169      m_uniform_tail->set_next(newuniform);
3170   }
3171   m_uniform_tail = newuniform;
3172}
3173
3174void effect::update_uniforms()
3175{
3176   uniform *curr = m_uniform_head;
3177   while(curr != NULL)
3178   {
3179      curr->update();
3180      curr = curr->get_next();
3181   }
3182}
3183
3184void effect::begin(UINT *passes, DWORD flags)
3185{
3186   m_effect->Begin(passes, flags);
3187}
3188
3189void effect::end()
3190{
3191   m_effect->End();
3192}
3193
3194void effect::begin_pass(UINT pass)
3195{
3196   m_effect->BeginPass(pass);
3197}
3198
3199void effect::end_pass()
3200{
3201   m_effect->EndPass();
3202}
3203
3204void effect::set_technique(const char *name)
3205{
3206   m_effect->SetTechnique(name);
3207}
3208
3209void effect::set_vector(D3DXHANDLE param, int count, float *vector)
3210{
3211   static D3DXVECTOR4 out_vector;
3212   if (count > 0)
3213   {
3214      out_vector.x = vector[0];
3215   }
3216   if (count > 1)
3217   {
3218      out_vector.y = vector[1];
3219   }
3220   if (count > 2)
3221   {
3222      out_vector.z = vector[2];
3223   }
3224   if (count > 3)
3225   {
3226      out_vector.w = vector[3];
3227   }
3228   m_effect->SetVector(param, &out_vector);
3229}
3230
3231void effect::set_float(D3DXHANDLE param, float value)
3232{
3233   m_effect->SetFloat(param, value);
3234}
3235
3236void effect::set_int(D3DXHANDLE param, int value)
3237{
3238   m_effect->SetInt(param, value);
3239}
3240
3241void effect::set_bool(D3DXHANDLE param, bool value)
3242{
3243   m_effect->SetBool(param, value);
3244}
3245
3246void effect::set_matrix(D3DXHANDLE param, matrix *matrix)
3247{
3248   m_effect->SetMatrix(param, (D3DXMATRIX*)matrix);
3249}
3250
3251void effect::set_texture(D3DXHANDLE param, texture *tex)
3252{
3253   m_effect->SetTexture(param, (IDirect3DTexture9*)tex);
3254}
3255
3256D3DXHANDLE effect::get_parameter(D3DXHANDLE param, const char *name)
3257{
3258   return m_effect->GetParameterByName(param, name);
3259}
3260
3261ULONG effect::release()
3262{
3263   return m_effect->Release();
3264}
3265
3266}
3267
3268
3269//============================================================
3270//  get_slider_list
3271//============================================================
3272
3273void *windows_osd_interface::get_slider_list()
3274{
3275   return (void*)g_slider_list;
3276}
3277
3278
3279// NOTE: The function below is taken directly from src/emu/video.c and should likely be moved into a global helper function.
3280//-------------------------------------------------
3281//  open_next - open the next non-existing file of
3282//  type filetype according to our numbering
3283//  scheme
3284//-------------------------------------------------
3285
3286static file_error open_next(d3d::renderer *d3d, emu_file &file, const char *templ, const char *extension, int idx)
3287{
3288   UINT32 origflags = file.openflags();
3289
3290   // handle defaults
3291   const char *snapname = templ ? templ : d3d->window().machine().options().snap_name();
3292
3293   if (snapname == NULL || snapname[0] == 0)
3294   {
3295      snapname = "%g/%i";
3296   }
3297   std::string snapstr(snapname);
3298
3299   // strip any extension in the provided name
3300   int index = snapstr.find_last_of('.');
3301   if (index != -1)
3302   {
3303      snapstr.substr(0, index);
3304   }
3305
3306   // handle %d in the template (for image devices)
3307   std::string snapdev("%d_");
3308   int pos = snapstr.find(snapdev,0);
3309
3310   if (pos != -1)
3311   {
3312      // if more %d are found, revert to default and ignore them all
3313      if (snapstr.find(snapdev, pos + 3) != -1)
3314      {
3315         snapstr.assign("%g/%i");
3316      }
3317      // else if there is a single %d, try to create the correct snapname
3318      else
3319      {
3320         int name_found = 0;
3321
3322         // find length of the device name
3323         int end1 = snapstr.find("/", pos + 3);
3324         int end2 = snapstr.find("%", pos + 3);
3325         int end = -1;
3326
3327         if ((end1 != -1) && (end2 != -1))
3328         {
3329            end = MIN(end1, end2);
3330         }
3331         else if (end1 != -1)
3332         {
3333            end = end1;
3334         }
3335         else if (end2 != -1)
3336         {
3337            end = end2;
3338         }
3339         else
3340         {
3341            end = snapstr.length();
3342         }
3343
3344         if (end - pos < 3)
3345         {
3346            fatalerror("Something very wrong is going on!!!\n");
3347         }
3348
3349         // copy the device name to a string
3350         std::string snapdevname;
3351         snapdevname.assign(snapstr.substr(pos + 3, end - pos - 3));
3352
3353         // verify that there is such a device for this system
3354         image_interface_iterator iter(d3d->window().machine().root_device());
3355         for (device_image_interface *image = iter.first(); image != NULL; iter.next())
3356         {
3357            // get the device name
3358            std::string tempdevname(image->brief_instance_name());
3359
3360            if (snapdevname.compare(tempdevname) == 0)
3361            {
3362               // verify that such a device has an image mounted
3363               if (image->basename() != NULL)
3364               {
3365                  std::string filename(image->basename());
3366
3367                  // strip extension
3368                  filename.substr(0, filename.find_last_of('.'));
3369
3370                  // setup snapname and remove the %d_
3371                  strreplace(snapstr, snapdevname.c_str(), filename.c_str());
3372                  snapstr.erase(pos, 3);
3373
3374                  name_found = 1;
3375               }
3376            }
3377         }
3378
3379         // or fallback to default
3380         if (name_found == 0)
3381         {
3382            snapstr.assign("%g/%i");
3383         }
3384      }
3385   }
3386
3387   // add our own index
3388   // add our own extension
3389   snapstr.append(".").append(extension);
3390
3391   // substitute path and gamename up front
3392   strreplace(snapstr, "/", PATH_SEPARATOR);
3393   strreplace(snapstr, "%g", d3d->window().machine().basename());
3394
3395   // determine if the template has an index; if not, we always use the same name
3396   std::string fname;
3397   if (snapstr.find("%i") == -1)
3398   {
3399      fname.assign(snapstr);
3400   }
3401
3402   // otherwise, we scan for the next available filename
3403   else
3404   {
3405      // try until we succeed
3406      std::string seqtext;
3407      file.set_openflags(OPEN_FLAG_READ);
3408      for (int seq = 0; ; seq++)
3409      {
3410         // build up the filename
3411         strprintf(seqtext, "%04d_%d", seq, idx);
3412         strreplace(fname.assign(snapstr), "%i", seqtext.c_str());
3413
3414         // try to open the file; stop when we fail
3415         file_error filerr = file.open(fname.c_str());
3416         if (filerr != FILERR_NONE)
3417         {
3418            break;
3419         }
3420      }
3421   }
3422
3423   // create the final file
3424   file.set_openflags(origflags);
3425   return file.open(fname.c_str());
3426}
trunk/src/osd/modules/render/d3d/d3dhlsl.cpp
r0r250288
1// license:BSD-3-Clause
2// copyright-holders:Aaron Giles
3//============================================================
4//
5//  d3dhlsl.c - Win32 Direct3D HLSL implementation
6//
7//============================================================
8
9// Useful info:
10//  Windows XP/2003 shipped with DirectX 8.1
11//  Windows 2000 shipped with DirectX 7a
12//  Windows 98SE shipped with DirectX 6.1a
13//  Windows 98 shipped with DirectX 5
14//  Windows NT shipped with DirectX 3.0a
15//  Windows 95 shipped with DirectX 2
16
17// standard windows headers
18#define WIN32_LEAN_AND_MEAN
19#include <windows.h>
20#include <tchar.h>
21#include <mmsystem.h>
22#include <d3d9.h>
23#include <d3dx9.h>
24#include <math.h>
25#undef interface
26
27// MAME headers
28#include "emu.h"
29#include "render.h"
30#include "ui/ui.h"
31#include "rendutil.h"
32#include "options.h"
33#include "emuopts.h"
34#include "aviio.h"
35#include "png.h"
36#include "screen.h"
37
38// MAMEOS headers
39#include "d3dintf.h"
40#include "winmain.h"
41#include "window.h"
42#include "config.h"
43#include "d3dcomm.h"
44#include "modules/render/drawd3d.h"
45#include "strconv.h"
46
47
48//============================================================
49//  GLOBALS
50//============================================================
51
52static slider_state *g_slider_list;
53static file_error open_next(d3d::renderer *d3d, emu_file &file, const char *templ, const char *extension, int idx);
54
55namespace d3d
56{
57
58//============================================================
59//  PROTOTYPES
60//============================================================
61
62static void get_vector(const char *data, int count, float *out, bool report_error);
63
64
65//============================================================
66//  TYPE DEFINITIONS
67//============================================================
68
69typedef HRESULT (WINAPI *direct3dx9_loadeffect_ptr)(LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, const D3DXMACRO *pDefines, LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXEFFECTPOOL pPool, LPD3DXEFFECT *ppEffect, LPD3DXBUFFER *ppCompilationErrors);
70static direct3dx9_loadeffect_ptr g_load_effect = NULL;
71
72
73//============================================================
74//  shader manager constructor
75//============================================================
76
77shaders::shaders()
78{
79   master_enable = false;
80   vector_enable = true;
81   hlsl_prescale_x = 1;
82   hlsl_prescale_x = 1;
83   preset = -1;
84   shadow_texture = NULL;
85   options = NULL;
86   paused = true;
87   lastidx = -1;
88   targethead = NULL;
89   cachehead = NULL;
90   initialized = false;
91}
92
93
94//============================================================
95//  shaders destructor
96//============================================================
97
98shaders::~shaders()
99{
100   cache_target *currcache = cachehead;
101   while(cachehead != NULL)
102   {
103      cachehead = currcache->next;
104      global_free(currcache);
105      currcache = cachehead;
106   }
107
108   render_target *currtarget = targethead;
109   while(targethead != NULL)
110   {
111      targethead = currtarget->next;
112      global_free(currtarget);
113      currtarget = targethead;
114   }
115}
116
117
118//============================================================
119//  shaders::window_save
120//============================================================
121
122void shaders::window_save()
123{
124   if (!master_enable || !d3dintf->post_fx_available)
125   {
126      return;
127   }
128
129   HRESULT result = (*d3dintf->device.create_texture)(d3d->get_device(), snap_width, snap_height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &snap_copy_texture);
130   if (result != D3D_OK)
131   {
132      osd_printf_verbose("Direct3D: Unable to init system-memory target for HLSL snapshot (%08x), bailing\n", (UINT32)result);
133      return;
134   }
135   (*d3dintf->texture.get_surface_level)(snap_copy_texture, 0, &snap_copy_target);
136
137   result = (*d3dintf->device.create_texture)(d3d->get_device(), snap_width, snap_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &snap_texture);
138   if (result != D3D_OK)
139   {
140      osd_printf_verbose("Direct3D: Unable to init video-memory target for HLSL snapshot (%08x), bailing\n", (UINT32)result);
141      return;
142   }
143   (*d3dintf->texture.get_surface_level)(snap_texture, 0, &snap_target);
144
145   render_snap = true;
146   snap_rendered = false;
147}
148
149
150//============================================================
151//  shaders::window_record
152//============================================================
153
154void shaders::window_record()
155{
156   if (!master_enable || !d3dintf->post_fx_available)
157   {
158      return;
159   }
160
161   windows_options &options = downcast<windows_options &>(machine->options());
162   const char *filename = options.d3d_hlsl_write();
163
164   if (avi_output_file != NULL)
165   {
166      end_avi_recording();
167   }
168   else if (filename[0] != 0)
169   {
170      begin_avi_recording(filename);
171   }
172}
173
174
175//============================================================
176//  shaders::avi_update_snap
177//============================================================
178
179void shaders::avi_update_snap(surface *surface)
180{
181   if (!master_enable || !d3dintf->post_fx_available)
182   {
183      return;
184   }
185
186   D3DLOCKED_RECT rect;
187
188   // if we don't have a bitmap, or if it's not the right size, allocate a new one
189   if (!avi_snap.valid() || (int)snap_width != avi_snap.width() || (int)snap_height != avi_snap.height())
190   {
191      avi_snap.allocate((int)snap_width, (int)snap_height);
192   }
193
194   // copy the texture
195   HRESULT result = (*d3dintf->device.get_render_target_data)(d3d->get_device(), surface, avi_copy_surface);
196   if (result != D3D_OK)
197   {
198      return;
199   }
200
201   // lock the texture
202   result = (*d3dintf->surface.lock_rect)(avi_copy_surface, &rect, NULL, D3DLOCK_DISCARD);
203   if (result != D3D_OK)
204   {
205      return;
206   }
207
208   // loop over Y
209   for (int srcy = 0; srcy < (int)snap_height; srcy++)
210   {
211      DWORD *src = (DWORD *)((BYTE *)rect.pBits + srcy * rect.Pitch);
212      UINT32 *dst = &avi_snap.pix32(srcy);
213
214      for (int x = 0; x < snap_width; x++)
215      {
216         *dst++ = *src++;
217      }
218   }
219
220   // unlock
221   result = (*d3dintf->surface.unlock_rect)(avi_copy_surface);
222   if (result != D3D_OK)
223   {
224      osd_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result);
225   }
226}
227
228
229
230//============================================================
231//  hlsl_render_snapshot
232//============================================================
233
234void shaders::render_snapshot(surface *surface)
235{
236   if (!master_enable || !d3dintf->post_fx_available)
237   {
238      return;
239   }
240
241   D3DLOCKED_RECT rect;
242
243   render_snap = false;
244
245   // if we don't have a bitmap, or if it's not the right size, allocate a new one
246   if (!avi_snap.valid() || snap_width != (avi_snap.width() / 2) || snap_height != (avi_snap.height() / 2))
247   {
248      avi_snap.allocate(snap_width / 2, snap_height / 2);
249   }
250
251   // copy the texture
252   HRESULT result = (*d3dintf->device.get_render_target_data)(d3d->get_device(), surface, snap_copy_target);
253   if (result != D3D_OK)
254   {
255      return;
256   }
257
258   // lock the texture
259   result = (*d3dintf->surface.lock_rect)(snap_copy_target, &rect, NULL, D3DLOCK_DISCARD);
260   if (result != D3D_OK)
261   {
262      return;
263   }
264
265   for (int cy = 0; cy < 2; cy++)
266   {
267      for (int cx = 0; cx < 2; cx++)
268      {
269         // loop over Y
270         for (int srcy = 0; srcy < snap_height / 2; srcy++)
271         {
272            int toty = (srcy + cy * (snap_height / 2));
273            int totx = cx * (snap_width / 2);
274            DWORD *src = (DWORD *)((BYTE *)rect.pBits + toty * rect.Pitch + totx * 4);
275            UINT32 *dst = &avi_snap.pix32(srcy);
276
277            for (int x = 0; x < snap_width / 2; x++)
278            {
279               *dst++ = *src++;
280            }
281         }
282
283         int idx = cy * 2 + cx;
284
285         emu_file file(machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
286         file_error filerr = open_next(d3d, file, NULL, "png", idx);
287         if (filerr != FILERR_NONE)
288         {
289            return;
290         }
291
292         // add two text entries describing the image
293         std::string text1 = std::string(emulator_info::get_appname()).append(" ").append(build_version);
294         std::string text2 = std::string(machine->system().manufacturer).append(" ").append(machine->system().description);
295         png_info pnginfo = { 0 };
296         png_add_text(&pnginfo, "Software", text1.c_str());
297         png_add_text(&pnginfo, "System", text2.c_str());
298
299         // now do the actual work
300         png_error error = png_write_bitmap(file, &pnginfo, avi_snap, 1 << 24, NULL);
301         if (error != PNGERR_NONE)
302         {
303            osd_printf_error("Error generating PNG for HLSL snapshot: png_error = %d\n", error);
304         }
305
306         // free any data allocated
307         png_free(&pnginfo);
308      }
309   }
310
311   // unlock
312   result = (*d3dintf->surface.unlock_rect)(snap_copy_target);
313   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result);
314
315   if (snap_texture != NULL)
316   {
317      (*d3dintf->texture.release)(snap_texture);
318      snap_texture = NULL;
319   }
320
321   if (snap_target != NULL)
322   {
323      (*d3dintf->surface.release)(snap_target);
324      snap_target = NULL;
325   }
326
327   if (snap_copy_texture != NULL)
328   {
329      (*d3dintf->texture.release)(snap_copy_texture);
330      snap_copy_texture = NULL;
331   }
332
333   if (snap_copy_target != NULL)
334   {
335      (*d3dintf->surface.release)(snap_copy_target);
336      snap_copy_target = NULL;
337   }
338}
339
340
341//============================================================
342//  shaders::record_texture
343//============================================================
344
345void shaders::record_texture()
346{
347   if (!master_enable || !d3dintf->post_fx_available)
348   {
349      return;
350   }
351
352   surface *surface = avi_final_target;
353
354   // ignore if nothing to do
355   if (avi_output_file == NULL || surface == NULL)
356   {
357      return;
358   }
359
360   // get the current time
361   attotime curtime = machine->time();
362
363   avi_update_snap(surface);
364
365   // loop until we hit the right time
366   while (avi_next_frame_time <= curtime)
367   {
368      // handle an AVI recording
369      // write the next frame
370      avi_error avierr = avi_append_video_frame(avi_output_file, avi_snap);
371      if (avierr != AVIERR_NONE)
372      {
373         end_avi_recording();
374         return;
375      }
376
377      // advance time
378      avi_next_frame_time += avi_frame_period;
379      avi_frame++;
380   }
381}
382
383
384//============================================================
385//  shaders::end_hlsl_avi_recording
386//============================================================
387
388void shaders::end_avi_recording()
389{
390   if (!master_enable || !d3dintf->post_fx_available)
391   {
392      return;
393   }
394
395   if (avi_output_file != NULL)
396   {
397      avi_close(avi_output_file);
398   }
399
400   avi_output_file = NULL;
401   avi_frame = 0;
402}
403
404
405//============================================================
406//  shaders::toggle
407//============================================================
408
409void shaders::toggle()
410{
411   if (master_enable)
412   {
413      if (initialized)
414      {
415         delete_resources(false);
416      }
417      master_enable = !master_enable;
418   }
419   else
420   {
421      if (!initialized)
422      {
423         master_enable = !master_enable;
424         bool failed = create_resources(false);
425         if (failed)
426         {
427            master_enable = false;
428         }
429      }
430      else
431      {
432         master_enable = !master_enable;
433      }
434   }
435}
436
437//============================================================
438//  shaders::begin_avi_recording
439//============================================================
440
441void shaders::begin_avi_recording(const char *name)
442{
443   if (!master_enable || !d3dintf->post_fx_available)
444   {
445      return;
446   }
447
448   // stop any existing recording
449   end_avi_recording();
450
451   // reset the state
452   avi_frame = 0;
453   avi_next_frame_time = machine->time();
454
455   // build up information about this new movie
456   avi_movie_info info;
457   info.video_format = 0;
458   info.video_timescale = 1000 * ((machine->first_screen() != NULL) ? ATTOSECONDS_TO_HZ(machine->first_screen()->frame_period().m_attoseconds) : screen_device::DEFAULT_FRAME_RATE);
459   info.video_sampletime = 1000;
460   info.video_numsamples = 0;
461   info.video_width = snap_width;
462   info.video_height = snap_height;
463   info.video_depth = 24;
464
465   info.audio_format = 0;
466   info.audio_timescale = machine->sample_rate();
467   info.audio_sampletime = 1;
468   info.audio_numsamples = 0;
469   info.audio_channels = 2;
470   info.audio_samplebits = 16;
471   info.audio_samplerate = machine->sample_rate();
472
473   // create a new temporary movie file
474   file_error filerr;
475   std::string fullpath;
476   {
477      emu_file tempfile(machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
478      if (name != NULL)
479      {
480         filerr = tempfile.open(name);
481      }
482      else
483      {
484         filerr = open_next(d3d, tempfile, NULL, "avi", 0);
485      }
486
487      // compute the frame time
488      {
489         avi_frame_period = attotime::from_seconds(1000) / info.video_timescale;
490      }
491
492      // if we succeeded, make a copy of the name and create the real file over top
493      if (filerr == FILERR_NONE)
494      {
495         fullpath = tempfile.fullpath();
496      }
497   }
498
499   if (filerr == FILERR_NONE)
500   {
501      // create the file and free the string
502      avi_error avierr = avi_create(fullpath.c_str(), &info, &avi_output_file);
503      if (avierr != AVIERR_NONE)
504      {
505         osd_printf_error("Error creating AVI: %s\n", avi_error_string(avierr));
506      }
507   }
508}
509
510
511//============================================================
512//  remove_cache_target - remove an active cache target when
513//  refcount hits zero
514//============================================================
515
516void shaders::remove_cache_target(cache_target *cache)
517{
518   if (cache != NULL)
519   {
520      if (cache == cachehead)
521      {
522         cachehead = cachehead->next;
523      }
524
525      if (cache->prev != NULL)
526      {
527         cache->prev->next = cache->next;
528      }
529
530      if (cache->next != NULL)
531      {
532         cache->next->prev = cache->prev;
533      }
534
535      global_free(cache);
536   }
537}
538
539
540//============================================================
541//  remove_render_target - remove an active target
542//============================================================
543
544void shaders::remove_render_target(texture_info *texture)
545{
546   remove_render_target(find_render_target(texture));
547}
548
549void shaders::remove_render_target(int width, int height, UINT32 screen_index, UINT32 page_index)
550{
551   render_target *target = find_render_target(width, height, screen_index, page_index);
552   if (target != NULL)
553   {
554      remove_render_target(target);
555   }
556}
557
558void shaders::remove_render_target(render_target *rt)
559{
560   if (rt != NULL)
561   {
562      if (rt == targethead)
563      {
564         targethead = targethead->next;
565      }
566
567      if (rt->prev != NULL)
568      {
569         rt->prev->next = rt->next;
570      }
571
572      if (rt->next != NULL)
573      {
574         rt->next->prev = rt->prev;
575      }
576
577      cache_target *cache = find_cache_target(rt->screen_index, rt->width, rt->height);
578      if (cache != NULL)
579      {
580         remove_cache_target(cache);
581      }
582
583      int screen_index = rt->screen_index;
584      int other_page = 1 - rt->page_index;
585      int width = rt->width;
586      int height = rt->height;
587
588      global_free(rt);
589
590      // Remove other double-buffered page (if it exists)
591      remove_render_target(width, height, screen_index, other_page);
592   }
593}
594
595
596//============================================================
597//  shaders::set_texture
598//============================================================
599
600void shaders::set_texture(texture_info *texture)
601{
602   if (!master_enable || !d3dintf->post_fx_available)
603   {
604      return;
605   }
606
607   if (texture != NULL)
608   {
609      paused = texture->paused();
610      texture->advance_frame();
611   }
612
613   // set initial texture to use
614   texture_info *default_texture = d3d->get_default_texture();
615   default_effect->set_texture("Diffuse", (texture == NULL) ? default_texture->get_finaltex() : texture->get_finaltex());
616   if (options->yiq_enable)
617   {
618      yiq_encode_effect->set_texture("Diffuse", (texture == NULL) ? default_texture->get_finaltex() : texture->get_finaltex());
619   }
620   else
621   {
622      color_effect->set_texture("Diffuse", (texture == NULL) ? default_texture->get_finaltex() : texture->get_finaltex());
623   }
624}
625
626
627//============================================================
628//  shaders::init
629//============================================================
630
631void shaders::init(base *d3dintf, running_machine *machine, d3d::renderer *renderer)
632{
633   if (!d3dintf->post_fx_available)
634   {
635      return;
636   }
637
638   g_load_effect = (direct3dx9_loadeffect_ptr)GetProcAddress(d3dintf->libhandle, "D3DXCreateEffectFromFileW");
639   if (g_load_effect == NULL)
640   {
641      printf("Direct3D: Unable to find D3DXCreateEffectFromFileW\n");
642      d3dintf->post_fx_available = false;
643      return;
644   }
645
646   this->d3dintf = d3dintf;
647   this->machine = machine;
648   this->d3d = renderer;
649   this->options = renderer->get_shaders_options();
650
651   windows_options &winoptions = downcast<windows_options &>(machine->options());
652
653   master_enable = winoptions.d3d_hlsl_enable();
654   hlsl_prescale_x = winoptions.d3d_hlsl_prescale_x();
655   hlsl_prescale_y = winoptions.d3d_hlsl_prescale_y();
656   snap_width = winoptions.d3d_snap_width();
657   snap_height = winoptions.d3d_snap_height();
658
659   if (!options->params_init)
660   {
661      strncpy(options->shadow_mask_texture, winoptions.screen_shadow_mask_texture(), sizeof(options->shadow_mask_texture));
662      options->shadow_mask_alpha = winoptions.screen_shadow_mask_alpha();
663      options->shadow_mask_count_x = winoptions.screen_shadow_mask_count_x();
664      options->shadow_mask_count_y = winoptions.screen_shadow_mask_count_y();
665      options->shadow_mask_u_size = winoptions.screen_shadow_mask_u_size();
666      options->shadow_mask_v_size = winoptions.screen_shadow_mask_v_size();
667      options->shadow_mask_u_offset = winoptions.screen_shadow_mask_u_offset();
668      options->shadow_mask_v_offset = winoptions.screen_shadow_mask_v_offset();
669      options->curvature = winoptions.screen_curvature();
670      options->round_corner = winoptions.screen_round_corner();
671      options->smooth_border = winoptions.screen_smooth_border();
672      options->reflection = winoptions.screen_reflection();
673      options->vignetting = winoptions.screen_vignetting();
674      options->scanline_alpha = winoptions.screen_scanline_amount();
675      options->scanline_scale = winoptions.screen_scanline_scale();
676      options->scanline_height = winoptions.screen_scanline_height();
677      options->scanline_bright_scale = winoptions.screen_scanline_bright_scale();
678      options->scanline_bright_offset = winoptions.screen_scanline_bright_offset();
679      options->scanline_offset = winoptions.screen_scanline_offset();
680      get_vector(winoptions.screen_defocus(), 2, options->defocus, TRUE);
681      get_vector(winoptions.screen_converge_x(), 3, options->converge_x, TRUE);
682      get_vector(winoptions.screen_converge_y(), 3, options->converge_y, TRUE);
683      get_vector(winoptions.screen_radial_converge_x(), 3, options->radial_converge_x, TRUE);
684      get_vector(winoptions.screen_radial_converge_y(), 3, options->radial_converge_y, TRUE);
685      get_vector(winoptions.screen_red_ratio(), 3, options->red_ratio, TRUE);
686      get_vector(winoptions.screen_grn_ratio(), 3, options->grn_ratio, TRUE);
687      get_vector(winoptions.screen_blu_ratio(), 3, options->blu_ratio, TRUE);
688      get_vector(winoptions.screen_offset(), 3, options->offset, TRUE);
689      get_vector(winoptions.screen_scale(), 3, options->scale, TRUE);
690      get_vector(winoptions.screen_power(), 3, options->power, TRUE);
691      get_vector(winoptions.screen_floor(), 3, options->floor, TRUE);
692      get_vector(winoptions.screen_phosphor(), 3, options->phosphor, TRUE);
693      options->saturation = winoptions.screen_saturation();
694      options->yiq_enable = winoptions.screen_yiq_enable();
695      options->yiq_cc = winoptions.screen_yiq_cc();
696      options->yiq_a = winoptions.screen_yiq_a();
697      options->yiq_b = winoptions.screen_yiq_b();
698      options->yiq_o = winoptions.screen_yiq_o();
699      options->yiq_p = winoptions.screen_yiq_p();
700      options->yiq_n = winoptions.screen_yiq_n();
701      options->yiq_y = winoptions.screen_yiq_y();
702      options->yiq_i = winoptions.screen_yiq_i();
703      options->yiq_q = winoptions.screen_yiq_q();
704      options->yiq_scan_time = winoptions.screen_yiq_scan_time();
705      options->yiq_phase_count = winoptions.screen_yiq_phase_count();
706      options->vector_length_scale = winoptions.screen_vector_length_scale();
707      options->vector_length_ratio = winoptions.screen_vector_length_ratio();
708      options->bloom_scale = winoptions.screen_bloom_scale();
709      get_vector(winoptions.screen_bloom_overdrive(), 3, options->bloom_overdrive, TRUE);
710      options->bloom_level0_weight = winoptions.screen_bloom_lvl0_weight();
711      options->bloom_level1_weight = winoptions.screen_bloom_lvl1_weight();
712      options->bloom_level2_weight = winoptions.screen_bloom_lvl2_weight();
713      options->bloom_level3_weight = winoptions.screen_bloom_lvl3_weight();
714      options->bloom_level4_weight = winoptions.screen_bloom_lvl4_weight();
715      options->bloom_level5_weight = winoptions.screen_bloom_lvl5_weight();
716      options->bloom_level6_weight = winoptions.screen_bloom_lvl6_weight();
717      options->bloom_level7_weight = winoptions.screen_bloom_lvl7_weight();
718      options->bloom_level8_weight = winoptions.screen_bloom_lvl8_weight();
719      options->bloom_level9_weight = winoptions.screen_bloom_lvl9_weight();
720      options->bloom_level10_weight = winoptions.screen_bloom_lvl10_weight();
721
722      options->params_init = true;
723   }
724
725   options->params_dirty = true;
726
727   g_slider_list = init_slider_list();
728}
729
730
731//============================================================
732//  shaders::init_fsfx_quad
733//============================================================
734
735void shaders::init_fsfx_quad(void *vertbuf)
736{
737   // Called at the start of each frame by the D3D code in order to reserve two triangles
738   // that are guaranteed to be at a fixed position so as to simply use D3DPT_TRIANGLELIST, 0, 2
739   // instead of having to do bookkeeping about a specific screen quad
740   if (!master_enable || !d3dintf->post_fx_available)
741   {
742      return;
743   }
744
745   // get a pointer to the vertex buffer
746   fsfx_vertices = (vertex *)vertbuf;
747   if (fsfx_vertices == NULL)
748   {
749      return;
750   }
751
752   // fill in the vertexes clockwise
753   fsfx_vertices[0].x = 0.0f;
754   fsfx_vertices[0].y = 0.0f;
755   fsfx_vertices[1].x = d3d->get_width();
756   fsfx_vertices[1].y = 0.0f;
757   fsfx_vertices[2].x = 0.0f;
758   fsfx_vertices[2].y = d3d->get_height();
759   fsfx_vertices[3].x = d3d->get_width();
760   fsfx_vertices[3].y = 0.0f;
761   fsfx_vertices[4].x = 0.0f;
762   fsfx_vertices[4].y = d3d->get_height();
763   fsfx_vertices[5].x = d3d->get_width();
764   fsfx_vertices[5].y = d3d->get_height();
765
766   fsfx_vertices[0].u0 = 0.0f;
767   fsfx_vertices[0].v0 = 0.0f;
768
769   fsfx_vertices[1].u0 = 1.0f;
770   fsfx_vertices[1].v0 = 0.0f;
771
772   fsfx_vertices[2].u0 = 0.0f;
773   fsfx_vertices[2].v0 = 1.0f;
774
775   fsfx_vertices[3].u0 = 1.0f;
776   fsfx_vertices[3].v0 = 0.0f;
777
778   fsfx_vertices[4].u0 = 0.0f;
779   fsfx_vertices[4].v0 = 1.0f;
780
781   fsfx_vertices[5].u0 = 1.0f;
782   fsfx_vertices[5].v0 = 1.0f;
783
784   fsfx_vertices[0].u1 = 0.0f;
785   fsfx_vertices[0].v1 = 0.0f;
786   fsfx_vertices[1].u1 = 0.0f;
787   fsfx_vertices[1].v1 = 0.0f;
788   fsfx_vertices[2].u1 = 0.0f;
789   fsfx_vertices[2].v1 = 0.0f;
790   fsfx_vertices[3].u1 = 0.0f;
791   fsfx_vertices[3].v1 = 0.0f;
792   fsfx_vertices[4].u1 = 0.0f;
793   fsfx_vertices[4].v1 = 0.0f;
794   fsfx_vertices[5].u1 = 0.0f;
795   fsfx_vertices[5].v1 = 0.0f;
796
797   // set the color, Z parameters to standard values
798   for (int i = 0; i < 6; i++)
799   {
800      fsfx_vertices[i].z = 0.0f;
801      fsfx_vertices[i].rhw = 1.0f;
802      fsfx_vertices[i].color = D3DCOLOR_ARGB(255, 255, 255, 255);
803   }
804}
805
806
807//============================================================
808//  shaders::create_resources
809//============================================================
810
811int shaders::create_resources(bool reset)
812{
813   if (!master_enable || !d3dintf->post_fx_available)
814   {
815      return 0;
816   }
817
818   HRESULT result = (*d3dintf->device.get_render_target)(d3d->get_device(), 0, &backbuffer);
819   if (result != D3D_OK)
820   {
821      osd_printf_verbose("Direct3D: Error %08X during device get_render_target call\n", (int)result);
822   }
823
824   result = (*d3dintf->device.create_texture)(d3d->get_device(), 4, 4, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &black_texture);
825   if (result != D3D_OK)
826   {
827      osd_printf_verbose("Direct3D: Unable to init video-memory target for black texture (%08x)\n", (UINT32)result);
828      return 1;
829   }
830   (*d3dintf->texture.get_surface_level)(black_texture, 0, &black_surface);
831   result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, black_surface);
832   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result);
833   result = (*d3dintf->device.clear)(d3d->get_device(), 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0);
834   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result);
835   result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, backbuffer);
836   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result);
837
838   result = (*d3dintf->device.create_texture)(d3d->get_device(), (int)snap_width, (int)snap_height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &avi_copy_texture);
839   if (result != D3D_OK)
840   {
841      osd_printf_verbose("Direct3D: Unable to init system-memory target for HLSL AVI dumping (%08x)\n", (UINT32)result);
842      return 1;
843   }
844   (*d3dintf->texture.get_surface_level)(avi_copy_texture, 0, &avi_copy_surface);
845
846   result = (*d3dintf->device.create_texture)(d3d->get_device(), (int)snap_width, (int)snap_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &avi_final_texture);
847   if (result != D3D_OK)
848   {
849      osd_printf_verbose("Direct3D: Unable to init video-memory target for HLSL AVI dumping (%08x)\n", (UINT32)result);
850      return 1;
851   }
852   (*d3dintf->texture.get_surface_level)(avi_final_texture, 0, &avi_final_target);
853
854   emu_file file(machine->options().art_path(), OPEN_FLAG_READ);
855   render_load_png(shadow_bitmap, file, NULL, options->shadow_mask_texture);
856
857   // experimental: if we have a shadow bitmap, create a texture for it
858   if (shadow_bitmap.valid())
859   {
860      render_texinfo texture;
861
862      // fake in the basic data so it looks like it came from render.c
863      texture.base = shadow_bitmap.raw_pixptr(0);
864      texture.rowpixels = shadow_bitmap.rowpixels();
865      texture.width = shadow_bitmap.width();
866      texture.height = shadow_bitmap.height();
867      texture.palette = NULL;
868      texture.seqid = 0;
869
870      // now create it (no prescale, but wrap)
871      shadow_texture = new texture_info(d3d->get_texture_manager(), &texture, 1, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32) | PRIMFLAG_TEXWRAP_MASK);
872   }
873
874   const char *fx_dir = downcast<windows_options &>(machine->options()).screen_post_fx_dir();
875
876   default_effect = new effect(this, d3d->get_device(), "primary.fx", fx_dir);
877   post_effect = new effect(this, d3d->get_device(), "post.fx", fx_dir);
878   distortion_effect = new effect(this, d3d->get_device(), "distortion.fx", fx_dir);
879   prescale_effect = new effect(this, d3d->get_device(), "prescale.fx", fx_dir);
880   phosphor_effect = new effect(this, d3d->get_device(), "phosphor.fx", fx_dir);
881   focus_effect = new effect(this, d3d->get_device(), "focus.fx", fx_dir);
882   deconverge_effect = new effect(this, d3d->get_device(), "deconverge.fx", fx_dir);
883   color_effect = new effect(this, d3d->get_device(), "color.fx", fx_dir);
884   yiq_encode_effect = new effect(this, d3d->get_device(), "yiq_encode.fx", fx_dir);
885   yiq_decode_effect = new effect(this, d3d->get_device(), "yiq_decode.fx", fx_dir);
886   bloom_effect = new effect(this, d3d->get_device(), "bloom.fx", fx_dir);
887   downsample_effect = new effect(this, d3d->get_device(), "downsample.fx", fx_dir);
888   vector_effect = new effect(this, d3d->get_device(), "vector.fx", fx_dir);
889
890   if (!default_effect->is_valid() ||
891      !post_effect->is_valid() ||
892      !distortion_effect->is_valid() ||
893      !prescale_effect->is_valid() ||
894      !phosphor_effect->is_valid() ||
895      !focus_effect->is_valid() ||
896      !deconverge_effect->is_valid() ||
897      !color_effect->is_valid() ||
898      !yiq_encode_effect->is_valid() ||
899      !yiq_decode_effect->is_valid() ||
900      !bloom_effect->is_valid() ||
901      !downsample_effect->is_valid() ||
902      !vector_effect->is_valid())
903   {
904      return 1;
905   }
906
907   yiq_encode_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
908   yiq_encode_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
909   yiq_encode_effect->add_uniform("SourceRect", uniform::UT_VEC2, uniform::CU_SOURCE_RECT);
910   yiq_encode_effect->add_uniform("CCValue", uniform::UT_FLOAT, uniform::CU_NTSC_CCFREQ);
911   yiq_encode_effect->add_uniform("AValue", uniform::UT_FLOAT, uniform::CU_NTSC_A);
912   yiq_encode_effect->add_uniform("BValue", uniform::UT_FLOAT, uniform::CU_NTSC_B);
913   yiq_encode_effect->add_uniform("PValue", uniform::UT_FLOAT, uniform::CU_NTSC_P);
914   yiq_encode_effect->add_uniform("NotchHalfWidth", uniform::UT_FLOAT, uniform::CU_NTSC_NOTCH);
915   yiq_encode_effect->add_uniform("YFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_YFREQ);
916   yiq_encode_effect->add_uniform("IFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_IFREQ);
917   yiq_encode_effect->add_uniform("QFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_QFREQ);
918   yiq_encode_effect->add_uniform("ScanTime", uniform::UT_FLOAT, uniform::CU_NTSC_HTIME);
919
920   yiq_decode_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
921   yiq_decode_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
922   yiq_decode_effect->add_uniform("SourceRect", uniform::UT_VEC2, uniform::CU_SOURCE_RECT);
923   yiq_decode_effect->add_uniform("CCValue", uniform::UT_FLOAT, uniform::CU_NTSC_CCFREQ);
924   yiq_decode_effect->add_uniform("AValue", uniform::UT_FLOAT, uniform::CU_NTSC_A);
925   yiq_decode_effect->add_uniform("BValue", uniform::UT_FLOAT, uniform::CU_NTSC_B);
926   yiq_decode_effect->add_uniform("OValue", uniform::UT_FLOAT, uniform::CU_NTSC_O);
927   yiq_decode_effect->add_uniform("PValue", uniform::UT_FLOAT, uniform::CU_NTSC_P);
928   yiq_decode_effect->add_uniform("NotchHalfWidth", uniform::UT_FLOAT, uniform::CU_NTSC_NOTCH);
929   yiq_decode_effect->add_uniform("YFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_YFREQ);
930   yiq_decode_effect->add_uniform("IFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_IFREQ);
931   yiq_decode_effect->add_uniform("QFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_QFREQ);
932   yiq_decode_effect->add_uniform("ScanTime", uniform::UT_FLOAT, uniform::CU_NTSC_HTIME);
933
934   color_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
935   color_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
936
937   color_effect->add_uniform("YIQEnable", uniform::UT_FLOAT, uniform::CU_NTSC_ENABLE);
938   color_effect->add_uniform("RedRatios", uniform::UT_VEC3, uniform::CU_COLOR_RED_RATIOS);
939   color_effect->add_uniform("GrnRatios", uniform::UT_VEC3, uniform::CU_COLOR_GRN_RATIOS);
940   color_effect->add_uniform("BluRatios", uniform::UT_VEC3, uniform::CU_COLOR_BLU_RATIOS);
941   color_effect->add_uniform("Offset", uniform::UT_VEC3, uniform::CU_COLOR_OFFSET);
942   color_effect->add_uniform("Scale", uniform::UT_VEC3, uniform::CU_COLOR_SCALE);
943   color_effect->add_uniform("Saturation", uniform::UT_FLOAT, uniform::CU_COLOR_SATURATION);
944
945   prescale_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
946   prescale_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
947
948   deconverge_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
949   deconverge_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
950   deconverge_effect->add_uniform("SourceRect", uniform::UT_VEC2, uniform::CU_SOURCE_RECT);
951   deconverge_effect->add_uniform("ConvergeX", uniform::UT_VEC3, uniform::CU_CONVERGE_LINEAR_X);
952   deconverge_effect->add_uniform("ConvergeY", uniform::UT_VEC3, uniform::CU_CONVERGE_LINEAR_Y);
953   deconverge_effect->add_uniform("RadialConvergeX", uniform::UT_VEC3, uniform::CU_CONVERGE_RADIAL_X);
954   deconverge_effect->add_uniform("RadialConvergeY", uniform::UT_VEC3, uniform::CU_CONVERGE_RADIAL_Y);
955
956   focus_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
957   focus_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS);
958   focus_effect->add_uniform("Defocus", uniform::UT_VEC2, uniform::CU_FOCUS_SIZE);
959
960   phosphor_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
961   phosphor_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS);
962   phosphor_effect->add_uniform("Phosphor", uniform::UT_VEC3, uniform::CU_PHOSPHOR_LIFE);
963
964   downsample_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
965
966   bloom_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
967   bloom_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS);
968
969   post_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
970   post_effect->add_uniform("SourceRect", uniform::UT_VEC2, uniform::CU_SOURCE_RECT); // backward compatibility
971   post_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
972   post_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS);
973   post_effect->add_uniform("QuadDims", uniform::UT_VEC2, uniform::CU_QUAD_DIMS); // backward compatibility
974
975   post_effect->add_uniform("VignettingAmount", uniform::UT_FLOAT, uniform::CU_POST_VIGNETTING); // backward compatibility
976   post_effect->add_uniform("CurvatureAmount", uniform::UT_FLOAT, uniform::CU_POST_CURVATURE); // backward compatibility
977   post_effect->add_uniform("RoundCornerAmount", uniform::UT_FLOAT, uniform::CU_POST_ROUND_CORNER); // backward compatibility
978   post_effect->add_uniform("SmoothBorderAmount", uniform::UT_FLOAT, uniform::CU_POST_SMOOTH_BORDER); // backward compatibility
979   post_effect->add_uniform("ReflectionAmount", uniform::UT_FLOAT, uniform::CU_POST_REFLECTION); // backward compatibility
980
981   post_effect->add_uniform("ShadowAlpha", uniform::UT_FLOAT, uniform::CU_POST_SHADOW_ALPHA);
982   post_effect->add_uniform("ShadowCount", uniform::UT_VEC2, uniform::CU_POST_SHADOW_COUNT);
983   post_effect->add_uniform("ShadowUV", uniform::UT_VEC2, uniform::CU_POST_SHADOW_UV);
984   post_effect->add_uniform("ShadowUVOffset", uniform::UT_VEC2, uniform::CU_POST_SHADOW_UV_OFFSET);
985   post_effect->add_uniform("ShadowDims", uniform::UT_VEC2, uniform::CU_POST_SHADOW_DIMS);
986
987   post_effect->add_uniform("ScanlineAlpha", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_ALPHA);
988   post_effect->add_uniform("ScanlineScale", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_SCALE);
989   post_effect->add_uniform("ScanlineHeight", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_HEIGHT);
990   post_effect->add_uniform("ScanlineBrightScale", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_BRIGHT_SCALE);
991   post_effect->add_uniform("ScanlineBrightOffset", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_BRIGHT_OFFSET);
992   post_effect->add_uniform("Power", uniform::UT_VEC3, uniform::CU_POST_POWER);
993   post_effect->add_uniform("Floor", uniform::UT_VEC3, uniform::CU_POST_FLOOR);
994
995   distortion_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
996   distortion_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS);
997   distortion_effect->add_uniform("QuadDims", uniform::UT_VEC2, uniform::CU_QUAD_DIMS);
998
999   distortion_effect->add_uniform("VignettingAmount", uniform::UT_FLOAT, uniform::CU_POST_VIGNETTING);
1000   distortion_effect->add_uniform("CurvatureAmount", uniform::UT_FLOAT, uniform::CU_POST_CURVATURE);
1001   distortion_effect->add_uniform("RoundCornerAmount", uniform::UT_FLOAT, uniform::CU_POST_ROUND_CORNER);
1002   distortion_effect->add_uniform("SmoothBorderAmount", uniform::UT_FLOAT, uniform::CU_POST_SMOOTH_BORDER);
1003   distortion_effect->add_uniform("ReflectionAmount", uniform::UT_FLOAT, uniform::CU_POST_REFLECTION);
1004
1005   vector_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
1006
1007   default_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
1008   default_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS);
1009
1010   initialized = true;
1011
1012   return 0;
1013}
1014
1015
1016//============================================================
1017//  shaders::begin_draw
1018//============================================================
1019
1020void shaders::begin_draw()
1021{
1022   if (!master_enable || !d3dintf->post_fx_available)
1023   {
1024      return;
1025   }
1026
1027   curr_effect = default_effect;
1028
1029   default_effect->set_technique("TestTechnique");
1030   post_effect->set_technique("ScanMaskTechnique");
1031   distortion_effect->set_technique("DistortionTechnique");
1032   phosphor_effect->set_technique("TestTechnique");
1033   focus_effect->set_technique("TestTechnique");
1034   deconverge_effect->set_technique("DeconvergeTechnique");
1035   color_effect->set_technique("ColorTechnique");
1036   yiq_encode_effect->set_technique("EncodeTechnique");
1037   yiq_decode_effect->set_technique("DecodeTechnique");
1038
1039   HRESULT result = (*d3dintf->device.get_render_target)(d3d->get_device(), 0, &backbuffer);
1040   if (result != D3D_OK)
1041   {
1042      osd_printf_verbose("Direct3D: Error %08X during device get_render_target call\n", (int)result);
1043   }
1044}
1045
1046
1047//============================================================
1048//  shaders::begin_frame
1049//============================================================
1050
1051void shaders::begin_frame()
1052{
1053   record_texture();
1054}
1055
1056
1057//============================================================
1058//  shaders::blit
1059//============================================================
1060
1061void shaders::blit(
1062   surface *dst,
1063   bool clear_dst,
1064   D3DPRIMITIVETYPE prim_type,
1065   UINT32 prim_index,
1066   UINT32 prim_count)
1067{
1068   HRESULT result;
1069
1070   if (dst != NULL)
1071   {
1072      result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, dst);
1073      if (result != D3D_OK)
1074      {
1075         osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result);
1076      }
1077
1078      if (clear_dst)
1079      {
1080         result = (*d3dintf->device.clear)(d3d->get_device(), 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(1,0,0,0), 0, 0);
1081         if (result != D3D_OK)
1082         {
1083            osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result);
1084         }
1085      }
1086   }
1087
1088   UINT num_passes = 0;
1089   curr_effect->begin(&num_passes, 0);
1090
1091   for (UINT pass = 0; pass < num_passes; pass++)
1092   {
1093      curr_effect->begin_pass(pass);
1094
1095      // add the primitives
1096      result = (*d3dintf->device.draw_primitive)(d3d->get_device(), prim_type, prim_index, prim_count);
1097      if (result != D3D_OK)
1098      {
1099         osd_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result);
1100      }
1101
1102      curr_effect->end_pass();
1103   }
1104
1105   curr_effect->end();
1106}
1107
1108
1109//============================================================
1110//  shaders::end_frame
1111//============================================================
1112
1113void shaders::end_frame()
1114{
1115   if (!master_enable || !d3dintf->post_fx_available)
1116   {
1117      return;
1118   }
1119
1120   if (render_snap && snap_rendered)
1121   {
1122      render_snapshot(snap_target);
1123   }
1124
1125   if (!lines_pending)
1126   {
1127      return;
1128   }
1129
1130   lines_pending = false;
1131}
1132
1133
1134//============================================================
1135//  shaders::init_effect_info
1136//============================================================
1137
1138void shaders::init_effect_info(poly_info *poly)
1139{
1140   // nothing to do
1141}
1142
1143
1144//============================================================
1145//  shaders::find_render_target
1146//============================================================
1147
1148render_target* shaders::find_render_target(texture_info *info)
1149{
1150   UINT32 screen_index_data = (UINT32)info->get_texinfo().osddata;
1151   UINT32 screen_index = screen_index_data >> 1;
1152   UINT32 page_index = screen_index_data & 1;
1153
1154   render_target *curr = targethead;
1155   while (curr != NULL && (
1156      curr->screen_index != screen_index ||
1157      curr->page_index != page_index ||
1158      curr->width != info->get_texinfo().width ||
1159      curr->height != info->get_texinfo().height))
1160   {
1161      curr = curr->next;
1162   }
1163
1164   return curr;
1165}
1166
1167
1168//============================================================
1169//  shaders::find_render_target
1170//============================================================
1171
1172render_target* shaders::find_render_target(int width, int height, UINT32 screen_index, UINT32 page_index)
1173{
1174   render_target *curr = targethead;
1175   while (curr != NULL && (
1176      curr->width != width ||
1177      curr->height != height ||
1178      curr->screen_index != screen_index ||
1179      curr->page_index != page_index))
1180   {
1181      curr = curr->next;
1182   }
1183
1184   return curr;
1185}
1186
1187
1188//============================================================
1189//  shaders::find_cache_target
1190//============================================================
1191
1192cache_target* shaders::find_cache_target(UINT32 screen_index, int width, int height)
1193{
1194   cache_target *curr = cachehead;
1195   while (curr != NULL && (
1196      curr->screen_index != screen_index ||
1197      curr->width != width ||
1198      curr->height != height))
1199   {
1200      curr = curr->next;
1201   }
1202
1203   return curr;
1204}
1205
1206int shaders::ntsc_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1207{
1208   int next_index = source_index;
1209
1210   if (!options->yiq_enable)
1211   {
1212      return next_index;
1213   }
1214
1215   // Convert our signal into YIQ
1216   curr_effect = yiq_encode_effect;
1217   curr_effect->update_uniforms();
1218
1219   // initial "Diffuse"  texture is set in shaders::set_texture()
1220
1221   next_index = rt->next_index(next_index);
1222   blit(rt->native_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2);
1223
1224   // Convert our signal from YIQ
1225   curr_effect = yiq_decode_effect;
1226   curr_effect->update_uniforms();
1227   curr_effect->set_texture("Composite", rt->native_texture[next_index]);
1228   curr_effect->set_texture("Diffuse", curr_texture->get_finaltex());
1229
1230   next_index = rt->next_index(next_index);
1231   blit(rt->native_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2);
1232
1233   color_effect->set_texture("Diffuse", rt->native_texture[next_index]);
1234
1235   return next_index;
1236}
1237
1238int shaders::color_convolution_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1239{
1240   int next_index = source_index;
1241
1242   curr_effect = color_effect;
1243   curr_effect->update_uniforms();
1244
1245   // initial "Diffuse" texture is set in shaders::set_texture() or the result of shaders::ntsc_pass()
1246
1247   next_index = rt->next_index(next_index);
1248   blit(rt->native_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2);
1249
1250   return next_index;
1251}
1252
1253int shaders::prescale_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1254{
1255   int next_index = source_index;
1256
1257   curr_effect = prescale_effect;
1258   curr_effect->update_uniforms();
1259   curr_effect->set_texture("Diffuse", rt->native_texture[next_index]);
1260
1261   next_index = rt->next_index(next_index);
1262   blit(rt->prescale_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2);
1263
1264   return next_index;
1265}
1266
1267int shaders::deconverge_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1268{
1269   int next_index = source_index;
1270
1271   curr_effect = deconverge_effect;
1272   curr_effect->update_uniforms();
1273   curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]);
1274
1275   next_index = rt->next_index(next_index);
1276   blit(rt->prescale_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2);
1277
1278   return next_index;
1279}
1280
1281int shaders::defocus_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1282{
1283   int next_index = source_index;
1284
1285   float defocus_x = options->defocus[0];
1286   float defocus_y = options->defocus[1];
1287
1288   // skip defocus if no influencing settings
1289   if (defocus_x == 0.0f && defocus_y == 0.0f)
1290   {
1291      return next_index;
1292   }
1293
1294   curr_effect = focus_effect;
1295   curr_effect->update_uniforms();
1296   curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]);
1297
1298   next_index = rt->next_index(next_index);
1299   blit(rt->prescale_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2);
1300
1301   return next_index;
1302}
1303
1304int shaders::phosphor_pass(render_target *rt, cache_target *ct, int source_index, poly_info *poly, int vertnum)
1305{
1306   int next_index = source_index;
1307
1308   curr_effect = phosphor_effect;
1309   curr_effect->update_uniforms();
1310   curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]);
1311   curr_effect->set_texture("LastPass", ct->last_texture);
1312   curr_effect->set_bool("Passthrough", false);
1313
1314   next_index = rt->next_index(next_index);
1315   blit(rt->prescale_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2);
1316
1317   // Pass along our phosphor'd screen
1318   curr_effect->update_uniforms();
1319   curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]);
1320   curr_effect->set_texture("LastPass", rt->prescale_texture[next_index]);
1321   curr_effect->set_bool("Passthrough", true);
1322
1323   // Avoid changing targets due to page flipping
1324   blit(ct->last_target, true, D3DPT_TRIANGLELIST, 0, 2);
1325
1326   return next_index;
1327}
1328
1329int shaders::post_pass(render_target *rt, int source_index, poly_info *poly, int vertnum, bool prepare_bloom)
1330{
1331   int next_index = source_index;
1332
1333   texture_info *texture = poly->get_texture();
1334
1335   bool prepare_vector =
1336      (machine->first_screen()->screen_type() &  SCREEN_TYPE_VECTOR) == SCREEN_TYPE_VECTOR;
1337   bool prepare_raster =
1338      (machine->first_screen()->screen_type() &  SCREEN_TYPE_RASTER) == SCREEN_TYPE_RASTER;
1339   bool orientation_swap_xy =
1340      (d3d->window().machine().system().flags & ORIENTATION_SWAP_XY) == ORIENTATION_SWAP_XY;
1341   bool rotation_swap_xy =
1342      (d3d->window().target()->orientation() & ROT90) == ROT90 ||
1343      (d3d->window().target()->orientation() & ROT270) == ROT270;
1344   int rotation_type =
1345      (d3d->window().target()->orientation() & ROT90) == ROT90
1346         ? 1
1347         : (d3d->window().target()->orientation() & ROT180) == ROT180
1348            ? 2
1349            : (d3d->window().target()->orientation() & ROT270) == ROT270
1350               ? 3
1351               : 0;
1352
1353   curr_effect = post_effect;
1354   curr_effect->update_uniforms();
1355   curr_effect->set_texture("ShadowTexture", shadow_texture == NULL ? NULL : shadow_texture->get_finaltex());
1356   curr_effect->set_texture("DiffuseTexture", rt->prescale_texture[next_index]);
1357   curr_effect->set_float("ScanlineOffset", texture->get_cur_frame() == 0 ? 0.0f : options->scanline_offset);
1358   curr_effect->set_bool("OrientationSwapXY", orientation_swap_xy);
1359   curr_effect->set_bool("RotationSwapXY", rotation_swap_xy);
1360   curr_effect->set_int("RotationType", rotation_type); // backward compatibility
1361   curr_effect->set_bool("PrepareBloom", prepare_bloom);
1362   curr_effect->set_bool("PrepareVector", prepare_vector);
1363   curr_effect->set_bool("PrepareRaster", prepare_raster);
1364
1365   next_index = rt->next_index(next_index);
1366   blit(prepare_bloom ? rt->native_target[next_index] : rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count());
1367
1368   return next_index;
1369}
1370
1371int shaders::downsample_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1372{
1373   int next_index = source_index;
1374
1375   bool prepare_vector =
1376      (machine->first_screen()->screen_type() &  SCREEN_TYPE_VECTOR) == SCREEN_TYPE_VECTOR;
1377   float bloom_rescale = options->bloom_scale;
1378
1379   // skip downsample if no influencing settings
1380   if (bloom_rescale == 0.0f)
1381   {
1382      return next_index;
1383   }
1384
1385   curr_effect = downsample_effect;
1386   curr_effect->update_uniforms();
1387   curr_effect->set_bool("PrepareVector", prepare_vector);
1388
1389   int bloom_index = 0;
1390   float bloom_size = (d3d->get_width() < d3d->get_height()) ? d3d->get_width() : d3d->get_height();
1391   float bloom_width = prepare_vector ? rt->target_width : rt->target_width / hlsl_prescale_x;
1392   float bloom_height = prepare_vector ? rt->target_height : rt->target_height / hlsl_prescale_y;
1393   for (; bloom_size >= 2.0f && bloom_index < 11; bloom_size *= 0.5f)
1394   {
1395      bloom_dims[bloom_index][0] = (float)(int)bloom_width;
1396      bloom_dims[bloom_index][1] = (float)(int)bloom_height;
1397
1398      curr_effect->set_vector("TargetDims", 2, bloom_dims[bloom_index]);
1399      curr_effect->set_texture("DiffuseTexture",
1400         bloom_index == 0
1401            ? rt->native_texture[next_index]
1402            : rt->bloom_texture[bloom_index - 1]);
1403
1404      blit(rt->bloom_target[bloom_index], true, poly->get_type(), vertnum, poly->get_count());
1405
1406      bloom_width *= 0.5f;
1407      bloom_height *= 0.5f;
1408
1409      bloom_index++;
1410   }
1411
1412   bloom_count = bloom_index;
1413
1414   return next_index;
1415}
1416
1417int shaders::bloom_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1418{
1419   int next_index = source_index;
1420
1421   float bloom_rescale = options->bloom_scale;
1422
1423   // skip bloom if no influencing settings
1424   if (bloom_rescale == 0.0f)
1425   {
1426      return next_index;
1427   }
1428
1429   curr_effect = bloom_effect;
1430   curr_effect->update_uniforms();
1431
1432   float weight0123[4] = {
1433      options->bloom_level0_weight,
1434      options->bloom_level1_weight * bloom_rescale,
1435      options->bloom_level2_weight * bloom_rescale,
1436      options->bloom_level3_weight * bloom_rescale
1437   };
1438   float weight4567[4] = {
1439      options->bloom_level4_weight * bloom_rescale,
1440      options->bloom_level5_weight * bloom_rescale,
1441      options->bloom_level6_weight * bloom_rescale,
1442      options->bloom_level7_weight * bloom_rescale
1443   };
1444   float weight89A[3]  = {
1445      options->bloom_level8_weight * bloom_rescale,
1446      options->bloom_level9_weight * bloom_rescale,
1447      options->bloom_level10_weight * bloom_rescale
1448   };
1449   curr_effect->set_vector("Level0123Weight", 4, weight0123);
1450   curr_effect->set_vector("Level4567Weight", 4, weight4567);
1451   curr_effect->set_vector("Level89AWeight", 3, weight89A);
1452   curr_effect->set_vector("Level01Size", 4, bloom_dims[0]);
1453   curr_effect->set_vector("Level23Size", 4, bloom_dims[2]);
1454   curr_effect->set_vector("Level45Size", 4, bloom_dims[4]);
1455   curr_effect->set_vector("Level67Size", 4, bloom_dims[6]);
1456   curr_effect->set_vector("Level89Size", 4, bloom_dims[8]);
1457   curr_effect->set_vector("LevelASize", 2, bloom_dims[10]);
1458
1459   curr_effect->set_vector("OverdriveWeight", 3, options->bloom_overdrive);
1460
1461   curr_effect->set_texture("DiffuseA", rt->prescale_texture[next_index]);
1462
1463   char name[9] = "Diffuse*";
1464   for (int index = 1; index < bloom_count; index++)
1465   {
1466      name[7] = 'A' + index;
1467      curr_effect->set_texture(name, rt->bloom_texture[index - 1]);
1468   }
1469   for (int index = bloom_count; index < 11; index++)
1470   {
1471      name[7] = 'A' + index;
1472      curr_effect->set_texture(name, black_texture);
1473   }
1474
1475   next_index = rt->next_index(next_index);
1476   blit(rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count());
1477
1478   return next_index;
1479}
1480
1481int shaders::distortion_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1482{
1483   int next_index = source_index;
1484
1485   // skip distortion if no influencing settings
1486   if (options->reflection == 0 &&
1487      options->vignetting == 0 &&
1488      options->curvature == 0 &&
1489      options->round_corner == 0 &&
1490      options->smooth_border == 0)
1491   {
1492      return next_index;
1493   }
1494
1495   int screen_count = d3d->window().target()->current_view()->screens().count();
1496
1497   // only one screen is supported
1498   if (screen_count > 1)
1499   {
1500      return next_index;
1501   }
1502
1503   render_bounds bounds = d3d->window().target()->current_view()->bounds();
1504   render_bounds screen_bounds = d3d->window().target()->current_view()->screen_bounds();
1505
1506   // artworks are not supported
1507   if (bounds.x0 != screen_bounds.x0 ||
1508      bounds.y0 != screen_bounds.y0 ||
1509      bounds.x1 != screen_bounds.x1 ||
1510      bounds.y1 != screen_bounds.y1)
1511   {
1512      return next_index;
1513   }
1514
1515   bool orientation_swap_xy =
1516      (d3d->window().machine().system().flags & ORIENTATION_SWAP_XY) == ORIENTATION_SWAP_XY;
1517   bool rotation_swap_xy =
1518      (d3d->window().target()->orientation() & ROT90) == ROT90 ||
1519      (d3d->window().target()->orientation() & ROT270) == ROT270;
1520   int rotation_type =
1521      (d3d->window().target()->orientation() & ROT90) == ROT90
1522         ? 1
1523         : (d3d->window().target()->orientation() & ROT180) == ROT180
1524            ? 2
1525            : (d3d->window().target()->orientation() & ROT270) == ROT270
1526               ? 3
1527               : 0;
1528
1529   curr_effect = distortion_effect;
1530   curr_effect->update_uniforms();
1531   curr_effect->set_texture("DiffuseTexture", rt->prescale_texture[next_index]);
1532   curr_effect->set_bool("OrientationSwapXY", orientation_swap_xy);
1533   curr_effect->set_bool("RotationSwapXY", rotation_swap_xy);
1534   curr_effect->set_int("RotationType", rotation_type);
1535
1536   next_index = rt->next_index(next_index);
1537   blit(rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count());
1538
1539   return next_index;
1540}
1541
1542int shaders::vector_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1543{
1544   int next_index = source_index;
1545
1546   float time_params[2] = { 0.0f, 0.0f };
1547   float length_params[3] = { poly->get_line_length(), options->vector_length_scale, options->vector_length_ratio };
1548
1549   curr_effect = vector_effect;
1550   curr_effect->update_uniforms();
1551   curr_effect->set_vector("TimeParams", 2, time_params);
1552   curr_effect->set_vector("LengthParams", 3, length_params);
1553
1554   blit(rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count());
1555
1556   return next_index;
1557}
1558
1559int shaders::vector_buffer_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1560{
1561   int next_index = source_index;
1562
1563   curr_effect = default_effect;
1564   curr_effect->update_uniforms();
1565
1566   curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]);
1567   curr_effect->set_bool("PostPass", true);
1568   curr_effect->set_float("Brighten", 1.0f);
1569
1570   next_index = rt->next_index(next_index);
1571   blit(rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count());
1572
1573   return next_index;
1574}
1575
1576int shaders::screen_pass(render_target *rt, int source_index, poly_info *poly, int vertnum)
1577{
1578   int next_index = source_index;
1579
1580   bool prepare_vector =
1581      (machine->first_screen()->screen_type() &  SCREEN_TYPE_VECTOR) == SCREEN_TYPE_VECTOR;
1582
1583   curr_effect = default_effect;
1584   curr_effect->update_uniforms();
1585
1586   curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]);
1587   curr_effect->set_bool("PostPass", true);
1588   curr_effect->set_float("Brighten", prepare_vector ? 1.0f : 0.0f);
1589
1590   // we do not clear the backbuffe here because multiple screens might rendered into
1591   blit(backbuffer, false, poly->get_type(), vertnum, poly->get_count());
1592
1593   if (avi_output_file != NULL)
1594   {
1595      blit(avi_final_target, false, poly->get_type(), vertnum, poly->get_count());
1596   }
1597
1598   if (render_snap)
1599   {
1600      blit(snap_target, false, poly->get_type(), vertnum, poly->get_count());
1601
1602      snap_rendered = true;
1603   }
1604
1605   return next_index;
1606}
1607
1608void shaders::menu_pass(poly_info *poly, int vertnum)
1609{
1610   curr_effect = default_effect;
1611   curr_effect->update_uniforms();
1612   curr_effect->set_bool("PostPass", false);
1613   curr_effect->set_float("Brighten", 0.0f);
1614
1615   blit(NULL, false, poly->get_type(), vertnum, poly->get_count());
1616}
1617
1618
1619//============================================================
1620//  shaders::render_quad
1621//============================================================
1622
1623void shaders::render_quad(poly_info *poly, int vertnum)
1624{
1625   if (!master_enable || !d3dintf->post_fx_available)
1626   {
1627      return;
1628   }
1629
1630   curr_texture = poly->get_texture();
1631   curr_poly = poly;
1632
1633   if (PRIMFLAG_GET_SCREENTEX(d3d->get_last_texture_flags()) && curr_texture != NULL)
1634   {
1635      curr_render_target = find_render_target(curr_texture);
1636
1637      render_target *rt = curr_render_target;
1638      if (rt == NULL)
1639      {
1640         return;
1641      }
1642
1643      cache_target *ct = find_cache_target(rt->screen_index, curr_texture->get_texinfo().width, curr_texture->get_texinfo().height);
1644
1645      int next_index = 0;
1646
1647      next_index = ntsc_pass(rt, next_index, poly, vertnum);
1648      next_index = color_convolution_pass(rt, next_index, poly, vertnum);
1649      next_index = prescale_pass(rt, next_index, poly, vertnum);
1650      next_index = deconverge_pass(rt, next_index, poly, vertnum);
1651      next_index = defocus_pass(rt, next_index, poly, vertnum); // 1st pass
1652      next_index = defocus_pass(rt, next_index, poly, vertnum); // 2nd pass
1653      next_index = phosphor_pass(rt, ct, next_index, poly, vertnum);
1654
1655      // create bloom textures
1656      int phosphor_index = next_index;
1657      next_index = post_pass(rt, next_index, poly, vertnum, true);
1658      next_index = downsample_pass(rt, next_index, poly, vertnum);
1659
1660      // apply bloom textures
1661      next_index = phosphor_index;
1662      next_index = post_pass(rt, next_index, poly, vertnum, false);
1663      next_index = bloom_pass(rt, next_index, poly, vertnum);
1664
1665      next_index = distortion_pass(rt, next_index, poly, vertnum);
1666
1667      // render on screen
1668      d3d->set_wrap(D3DTADDRESS_MIRROR);
1669      next_index = screen_pass(rt, next_index, poly, vertnum);
1670      d3d->set_wrap(PRIMFLAG_GET_TEXWRAP(poly->get_texture()->get_flags()) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP);
1671
1672      curr_texture->increment_frame_count();
1673      curr_texture->mask_frame_count(options->yiq_phase_count);
1674
1675      options->params_dirty = false;
1676   }
1677   else if (PRIMFLAG_GET_VECTOR(poly->get_flags()) && vector_enable)
1678   {
1679      curr_render_target = find_render_target(d3d->get_width(), d3d->get_height(), 0, 0);
1680
1681      render_target *rt = curr_render_target;
1682      if (rt == NULL)
1683      {
1684         return;
1685      }
1686
1687      lines_pending = true;
1688
1689      int next_index = 0;
1690
1691      next_index = vector_pass(rt, next_index, poly, vertnum);
1692
1693      HRESULT result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, backbuffer);
1694      if (result != D3D_OK)
1695      {
1696         osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result);
1697      }
1698   }
1699   else if (PRIMFLAG_GET_VECTORBUF(poly->get_flags()) && vector_enable)
1700   {
1701      curr_render_target = find_render_target(d3d->get_width(), d3d->get_height(), 0, 0);
1702
1703      render_target *rt = curr_render_target;
1704      if (rt == NULL)
1705      {
1706         return;
1707      }
1708
1709      cache_target *ct = find_cache_target(rt->screen_index, rt->width, rt->height);
1710
1711      int next_index = 0;
1712
1713      next_index = vector_buffer_pass(rt, next_index, poly, vertnum);
1714      next_index = defocus_pass(rt, next_index, poly, vertnum);
1715      next_index = phosphor_pass(rt, ct, next_index, poly, vertnum);
1716
1717      // create bloom textures
1718      int phosphor_index = next_index;
1719      next_index = post_pass(rt, next_index, poly, vertnum, true);
1720      next_index = downsample_pass(rt, next_index, poly, vertnum);
1721
1722      // apply bloom textures
1723      next_index = phosphor_index;
1724      next_index = post_pass(rt, next_index, poly, vertnum, false);
1725      next_index = bloom_pass(rt, next_index, poly, vertnum);
1726
1727      next_index = distortion_pass(rt, next_index, poly, vertnum);
1728
1729      // render on screen
1730      next_index = screen_pass(rt, next_index, poly, vertnum);
1731
1732      HRESULT result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, backbuffer);
1733      if (result != D3D_OK)
1734      {
1735         osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result);
1736      }
1737
1738      lines_pending = false;
1739   }
1740   else
1741   {
1742      menu_pass(poly, vertnum);
1743   }
1744
1745   curr_render_target = NULL;
1746   curr_texture = NULL;
1747   curr_poly = NULL;
1748}
1749
1750
1751//============================================================
1752//  shaders::end_draw
1753//============================================================
1754
1755void shaders::end_draw()
1756{
1757   if (!master_enable || !d3dintf->post_fx_available)
1758   {
1759      return;
1760   }
1761
1762   (*d3dintf->surface.release)(backbuffer);
1763}
1764
1765
1766//============================================================
1767//  shaders::register_prescaled_texture
1768//============================================================
1769
1770bool shaders::register_prescaled_texture(texture_info *texture)
1771{
1772   return register_texture(texture);
1773}
1774
1775
1776//============================================================
1777//  shaders::add_cache_target - register a cache target
1778//============================================================
1779bool shaders::add_cache_target(renderer* d3d, texture_info* info, int width, int height, int xprescale, int yprescale, int screen_index)
1780{
1781   cache_target* target = (cache_target*)global_alloc_clear(cache_target);
1782
1783   if (!target->init(d3d, d3dintf, width, height, xprescale, yprescale))
1784   {
1785      global_free(target);
1786      return false;
1787   }
1788
1789   if (info != NULL)
1790   {
1791      target->width = info->get_texinfo().width;
1792      target->height = info->get_texinfo().height;
1793   }
1794   else
1795   {
1796      target->width = d3d->get_width();
1797      target->height = d3d->get_height();
1798   }
1799
1800   target->next = cachehead;
1801   target->prev = NULL;
1802
1803   target->screen_index = screen_index;
1804
1805   if (cachehead != NULL)
1806   {
1807      cachehead->prev = target;
1808   }
1809   cachehead = target;
1810
1811   return true;
1812}
1813
1814render_target* shaders::get_vector_target()
1815{
1816   if (!vector_enable)
1817   {
1818      return NULL;
1819   }
1820
1821   return find_render_target(d3d->get_width(), d3d->get_height(), 0, 0);
1822}
1823
1824void shaders::create_vector_target(render_primitive *prim)
1825{
1826   if (!add_render_target(d3d, NULL, d3d->get_width(), d3d->get_height(), 1, 1))
1827   {
1828      vector_enable = false;
1829   }
1830}
1831
1832
1833//============================================================
1834//  shaders::add_render_target - register a render target
1835//============================================================
1836
1837bool shaders::add_render_target(renderer* d3d, texture_info* info, int width, int height, int xprescale, int yprescale)
1838{
1839   UINT32 screen_index = 0;
1840   UINT32 page_index = 0;
1841   if (info != NULL)
1842   {
1843      render_target *existing_target = find_render_target(info);
1844      if (existing_target != NULL)
1845      {
1846         remove_render_target(existing_target);
1847      }
1848
1849      UINT32 screen_index_data = (UINT32)info->get_texinfo().osddata;
1850      screen_index = screen_index_data >> 1;
1851      page_index = screen_index_data & 1;
1852   }
1853   else
1854   {
1855      render_target *existing_target = find_render_target(d3d->get_width(), d3d->get_height(), 0, 0);
1856      if (existing_target != NULL)
1857      {
1858         remove_render_target(existing_target);
1859      }
1860   }
1861
1862   render_target* target = (render_target*)global_alloc_clear(render_target);
1863
1864   if (!target->init(d3d, d3dintf, width, height, xprescale, yprescale))
1865   {
1866      global_free(target);
1867      return false;
1868   }
1869
1870   if (info != NULL)
1871   {
1872      target->width = info->get_texinfo().width;
1873      target->height = info->get_texinfo().height;
1874   }
1875   else
1876   {
1877      target->width = d3d->get_width();
1878      target->height = d3d->get_height();
1879   }
1880
1881   HRESULT result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, target->prescale_target[0]);
1882   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result);
1883   result = (*d3dintf->device.clear)(d3d->get_device(), 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0);
1884   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result);
1885   result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, backbuffer);
1886   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result);
1887
1888   target->screen_index = screen_index;
1889   target->page_index = page_index;
1890
1891   cache_target* cache = find_cache_target(target->screen_index, target->width, target->height);
1892   if (cache == NULL)
1893   {
1894      if (!add_cache_target(d3d, info, width, height, xprescale, yprescale, target->screen_index))
1895      {
1896         global_free(target);
1897         return false;
1898      }
1899   }
1900
1901   target->next = targethead;
1902   target->prev = NULL;
1903
1904   if (targethead != NULL)
1905   {
1906      targethead->prev = target;
1907   }
1908   targethead = target;
1909
1910   return true;
1911}
1912
1913
1914//============================================================
1915//  shaders::enumerate_screens
1916//============================================================
1917void shaders::enumerate_screens()
1918{
1919   screen_device_iterator iter(machine->root_device());
1920   num_screens = iter.count();
1921}
1922
1923
1924//============================================================
1925//  shaders::register_texture(texture::info)
1926//============================================================
1927
1928bool shaders::register_texture(texture_info *texture)
1929{
1930   int width = texture->get_width();
1931   int height = texture->get_height();
1932   int xscale = texture->get_xscale();
1933   int yscale = texture->get_yscale();
1934
1935   if (!master_enable || !d3dintf->post_fx_available)
1936   {
1937      return false;
1938   }
1939
1940   enumerate_screens();
1941
1942   // Find the nearest prescale factor that is over our screen size
1943   if (hlsl_prescale_x == 0)
1944   {
1945      hlsl_prescale_x = 1;
1946      while (width * xscale * hlsl_prescale_x <= d3d->get_width())
1947      {
1948         hlsl_prescale_x++;
1949      }
1950      hlsl_prescale_x--;
1951   }
1952
1953   if (hlsl_prescale_y == 0)
1954   {
1955      hlsl_prescale_y = 1;
1956      while (height * yscale * hlsl_prescale_y <= d3d->get_height())
1957      {
1958         hlsl_prescale_y++;
1959      }
1960      hlsl_prescale_y--;
1961   }
1962
1963   hlsl_prescale_x = ((hlsl_prescale_x == 0) ? 1 : hlsl_prescale_x);
1964   hlsl_prescale_y = ((hlsl_prescale_y == 0) ? 1 : hlsl_prescale_y);
1965
1966   if (!add_render_target(d3d, texture, width, height, xscale * hlsl_prescale_x, yscale * hlsl_prescale_y))
1967   {
1968      return false;
1969   }
1970
1971   options->params_dirty = true;
1972
1973   return true;
1974}
1975
1976
1977//============================================================
1978//  shaders::delete_resources
1979//============================================================
1980
1981void shaders::delete_resources(bool reset)
1982{
1983   if (!master_enable || !d3dintf->post_fx_available)
1984   {
1985      return;
1986   }
1987
1988   initialized = false;
1989
1990   options = NULL;
1991
1992   cache_target *currcache = cachehead;
1993   while(cachehead != NULL)
1994   {
1995      cachehead = currcache->next;
1996      global_free(currcache);
1997      currcache = cachehead;
1998   }
1999
2000   render_target *currtarget = targethead;
2001   while(targethead != NULL)
2002   {
2003      targethead = currtarget->next;
2004      global_free(currtarget);
2005      currtarget = targethead;
2006   }
2007
2008   if (downsample_effect != NULL)
2009   {
2010      delete downsample_effect;
2011      downsample_effect = NULL;
2012   }
2013   if (bloom_effect != NULL)
2014   {
2015      delete bloom_effect;
2016      bloom_effect = NULL;
2017   }
2018   if (vector_effect != NULL)
2019   {
2020      delete vector_effect;
2021      vector_effect = NULL;
2022   }
2023   if (default_effect != NULL)
2024   {
2025      delete default_effect;
2026      default_effect = NULL;
2027   }
2028   if (post_effect != NULL)
2029   {
2030      delete post_effect;
2031      post_effect = NULL;
2032   }
2033   if (distortion_effect != NULL)
2034   {
2035      delete distortion_effect;
2036      distortion_effect = NULL;
2037   }
2038   if (prescale_effect != NULL)
2039   {
2040      delete prescale_effect;
2041      prescale_effect = NULL;
2042   }
2043   if (phosphor_effect != NULL)
2044   {
2045      delete phosphor_effect;
2046      phosphor_effect = NULL;
2047   }
2048   if (focus_effect != NULL)
2049   {
2050      delete focus_effect;
2051      focus_effect = NULL;
2052   }
2053   if (deconverge_effect != NULL)
2054   {
2055      delete deconverge_effect;
2056      deconverge_effect = NULL;
2057   }
2058   if (color_effect != NULL)
2059   {
2060      delete color_effect;
2061      color_effect = NULL;
2062   }
2063   if (yiq_encode_effect != NULL)
2064   {
2065      delete yiq_encode_effect;
2066      yiq_encode_effect = NULL;
2067   }
2068   if (yiq_decode_effect != NULL)
2069   {
2070      delete yiq_decode_effect;
2071      yiq_decode_effect = NULL;
2072   }
2073
2074   if (backbuffer != NULL)
2075   {
2076      (*d3dintf->surface.release)(backbuffer);
2077      backbuffer = NULL;
2078   }
2079
2080   if (black_surface != NULL)
2081   {
2082      (*d3dintf->surface.release)(black_surface);
2083      black_surface = NULL;
2084   }
2085   if (black_texture != NULL)
2086   {
2087      (*d3dintf->texture.release)(black_texture);
2088      black_texture = NULL;
2089   }
2090
2091   if (avi_copy_texture != NULL)
2092   {
2093      (*d3dintf->texture.release)(avi_copy_texture);
2094      avi_copy_texture = NULL;
2095   }
2096
2097   if (avi_copy_surface != NULL)
2098   {
2099      (*d3dintf->surface.release)(avi_copy_surface);
2100      avi_copy_surface = NULL;
2101   }
2102
2103   if (avi_final_texture != NULL)
2104   {
2105      (*d3dintf->texture.release)(avi_final_texture);
2106      avi_final_texture = NULL;
2107   }
2108
2109   if (avi_final_target != NULL)
2110   {
2111      (*d3dintf->surface.release)(avi_final_target);
2112      avi_final_target = NULL;
2113   }
2114
2115   shadow_bitmap.reset();
2116}
2117
2118
2119//============================================================
2120//  get_vector
2121//============================================================
2122
2123static void get_vector(const char *data, int count, float *out, bool report_error)
2124{
2125   if (count > 3 &&
2126      sscanf(data, "%f,%f,%f,%f", &out[0], &out[1], &out[2], &out[3]) < 4 && report_error)
2127   {
2128      osd_printf_error("Illegal quad vector value = %s\n", data);
2129   }
2130   else if (count > 2 &&
2131      sscanf(data, "%f,%f,%f", &out[0], &out[1], &out[2]) < 3 && report_error)
2132   {
2133      osd_printf_error("Illegal triple vector value = %s\n", data);
2134   }
2135   else if (count > 1 &&
2136      sscanf(data, "%f,%f", &out[0], &out[1]) < 2 && report_error)
2137   {
2138      osd_printf_error("Illegal double vector value = %s\n", data);
2139   }
2140   else if (count > 0 &&
2141      sscanf(data, "%f", &out[0]) < 1 && report_error)
2142   {
2143      osd_printf_error("Illegal single vector value = %s\n", data);
2144   }
2145}
2146
2147
2148/*-------------------------------------------------
2149    slider_alloc - allocate a new slider entry
2150    currently duplicated from ui.c, this could
2151    be done in a more ideal way.
2152-------------------------------------------------*/
2153
2154static slider_state *slider_alloc(running_machine &machine, const char *title, INT32 minval, INT32 defval, INT32 maxval, INT32 incval, slider_update update, void *arg)
2155{
2156   int size = sizeof(slider_state) + strlen(title);
2157   slider_state *state = (slider_state *)auto_alloc_array_clear(machine, UINT8, size);
2158
2159   state->minval = minval;
2160   state->defval = defval;
2161   state->maxval = maxval;
2162   state->incval = incval;
2163   state->update = update;
2164   state->arg = arg;
2165   strcpy(state->description, title);
2166
2167   return state;
2168}
2169
2170
2171//============================================================
2172//  assorted global slider accessors
2173//============================================================
2174
2175static INT32 slider_set(float *option, float scale, const char *fmt, std::string *str, INT32 newval)
2176{
2177   if (option != NULL && newval != SLIDER_NOCHANGE)
2178   {
2179      *option = (float)newval * scale;
2180   }
2181   if (str != NULL)
2182   {
2183      strprintf(*str, fmt, *option);
2184   }
2185
2186   return floor(*option / scale + 0.5f);
2187}
2188
2189static INT32 slider_shadow_mask_alpha(running_machine &machine, void *arg, std::string *str, INT32 newval)
2190{
2191   return slider_set(&(((hlsl_options*)arg)->shadow_mask_alpha), 0.01f, "%2.2f", str, newval);
2192}
2193
2194static INT32 slider_shadow_mask_x_count(running_machine &machine, void *arg, std::string *str, INT32 newval)
2195{
2196   hlsl_options *options = (hlsl_options*)arg;
2197   if (newval != SLIDER_NOCHANGE)
2198   {
2199      options->shadow_mask_count_x = newval;
2200   }
2201   if (str != NULL)
2202   {
2203      strprintf(*str, "%d", options->shadow_mask_count_x);
2204   }
2205   options->params_dirty = true;
2206
2207   return options->shadow_mask_count_x;
2208}
2209
2210static INT32 slider_shadow_mask_y_count(running_machine &machine, void *arg, std::string *str, INT32 newval)
2211{
2212   hlsl_options *options = (hlsl_options*)arg;
2213   if (newval != SLIDER_NOCHANGE)
2214   {
2215      options->shadow_mask_count_y = newval;
2216   }
2217   if (str != NULL)
2218   {
2219      strprintf(*str, "%d", options->shadow_mask_count_y);
2220   }
2221   options->params_dirty = true;
2222
2223   return options->shadow_mask_count_y;
2224}
2225
2226static INT32 slider_shadow_mask_usize(running_machine &machine, void *arg, std::string *str, INT32 newval)
2227{
2228   ((hlsl_options*)arg)->params_dirty = true;
2229   return slider_set(&(((hlsl_options*)arg)->shadow_mask_u_size), 1.0f / 32.0f, "%2.5f", str, newval);
2230}
2231
2232static INT32 slider_shadow_mask_vsize(running_machine &machine, void *arg, std::string *str, INT32 newval)
2233{
2234   ((hlsl_options*)arg)->params_dirty = true;
2235   return slider_set(&(((hlsl_options*)arg)->shadow_mask_v_size), 1.0f / 32.0f, "%2.5f", str, newval);
2236}
2237
2238static INT32 slider_shadow_mask_uoffset(running_machine &machine, void *arg, std::string *str, INT32 newval)
2239{
2240   ((hlsl_options*)arg)->params_dirty = true;
2241   return slider_set(&(((hlsl_options*)arg)->shadow_mask_u_offset), 0.01f, "%2.2f", str, newval);
2242}
2243
2244static INT32 slider_shadow_mask_voffset(running_machine &machine, void *arg, std::string *str, INT32 newval)
2245{
2246   ((hlsl_options*)arg)->params_dirty = true;
2247   return slider_set(&(((hlsl_options*)arg)->shadow_mask_v_offset), 0.01f, "%2.2f", str, newval);
2248}
2249
2250static INT32 slider_curvature(running_machine &machine, void *arg, std::string *str, INT32 newval)
2251{
2252   ((hlsl_options*)arg)->params_dirty = true;
2253   return slider_set(&(((hlsl_options*)arg)->curvature), 0.01f, "%2.2f", str, newval);
2254}
2255
2256static INT32 slider_round_corner(running_machine &machine, void *arg, std::string *str, INT32 newval)
2257{
2258   ((hlsl_options*)arg)->params_dirty = true;
2259   return slider_set(&(((hlsl_options*)arg)->round_corner), 0.01f, "%2.2f", str, newval);
2260}
2261
2262static INT32 slider_smooth_border(running_machine &machine, void *arg, std::string *str, INT32 newval)
2263{
2264   ((hlsl_options*)arg)->params_dirty = true;
2265   return slider_set(&(((hlsl_options*)arg)->smooth_border), 0.01f, "%2.2f", str, newval);
2266}
2267
2268static INT32 slider_reflection(running_machine &machine, void *arg, std::string *str, INT32 newval)
2269{
2270   ((hlsl_options*)arg)->params_dirty = true;
2271   return slider_set(&(((hlsl_options*)arg)->reflection), 0.01f, "%2.2f", str, newval);
2272}
2273
2274static INT32 slider_vignetting(running_machine &machine, void *arg, std::string *str, INT32 newval)
2275{
2276   ((hlsl_options*)arg)->params_dirty = true;
2277   return slider_set(&(((hlsl_options*)arg)->vignetting), 0.01f, "%2.2f", str, newval);
2278}
2279
2280static INT32 slider_scanline_alpha(running_machine &machine, void *arg, std::string *str, INT32 newval)
2281{
2282   ((hlsl_options*)arg)->params_dirty = true;
2283   return slider_set(&(((hlsl_options*)arg)->scanline_alpha), 0.01f, "%2.2f", str, newval);
2284}
2285
2286static INT32 slider_scanline_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2287{
2288   ((hlsl_options*)arg)->params_dirty = true;
2289   return slider_set(&(((hlsl_options*)arg)->scanline_scale), 0.05f, "%2.2f", str, newval);
2290}
2291
2292static INT32 slider_scanline_height(running_machine &machine, void *arg, std::string *str, INT32 newval)
2293{
2294   ((hlsl_options*)arg)->params_dirty = true;
2295   return slider_set(&(((hlsl_options*)arg)->scanline_height), 0.05f, "%2.2f", str, newval);
2296}
2297
2298static INT32 slider_scanline_bright_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2299{
2300   ((hlsl_options*)arg)->params_dirty = true;
2301   return slider_set(&(((hlsl_options*)arg)->scanline_bright_scale), 0.05f, "%2.2f", str, newval);
2302}
2303
2304static INT32 slider_scanline_bright_offset(running_machine &machine, void *arg, std::string *str, INT32 newval)
2305{
2306   ((hlsl_options*)arg)->params_dirty = true;
2307   return slider_set(&(((hlsl_options*)arg)->scanline_bright_offset), 0.05f, "%2.2f", str, newval);
2308}
2309
2310static INT32 slider_scanline_offset(running_machine &machine, void *arg, std::string *str, INT32 newval)
2311{
2312   ((hlsl_options*)arg)->params_dirty = true;
2313   return slider_set(&(((hlsl_options*)arg)->scanline_offset), 0.05f, "%2.2f", str, newval);
2314}
2315
2316static INT32 slider_defocus_x(running_machine &machine, void *arg, std::string *str, INT32 newval)
2317{
2318   ((hlsl_options*)arg)->params_dirty = true;
2319   return slider_set(&(((hlsl_options*)arg)->defocus[0]), 0.5f, "%2.1f", str, newval);
2320}
2321
2322static INT32 slider_defocus_y(running_machine &machine, void *arg, std::string *str, INT32 newval)
2323{
2324   ((hlsl_options*)arg)->params_dirty = true;
2325   return slider_set(&(((hlsl_options*)arg)->defocus[1]), 0.5f, "%2.1f", str, newval);
2326}
2327
2328static INT32 slider_red_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval)
2329{
2330   ((hlsl_options*)arg)->params_dirty = true;
2331   return slider_set(&(((hlsl_options*)arg)->converge_x[0]), 0.1f, "%3.1f", str, newval);
2332}
2333
2334static INT32 slider_red_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval)
2335{
2336   ((hlsl_options*)arg)->params_dirty = true;
2337   return slider_set(&(((hlsl_options*)arg)->converge_y[0]), 0.1f, "%3.1f", str, newval);
2338}
2339
2340static INT32 slider_green_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval)
2341{
2342   ((hlsl_options*)arg)->params_dirty = true;
2343   return slider_set(&(((hlsl_options*)arg)->converge_x[1]), 0.1f, "%3.1f", str, newval);
2344}
2345
2346static INT32 slider_green_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval)
2347{
2348   ((hlsl_options*)arg)->params_dirty = true;
2349   return slider_set(&(((hlsl_options*)arg)->converge_y[1]), 0.1f, "%3.1f", str, newval);
2350}
2351
2352static INT32 slider_blue_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval)
2353{
2354   ((hlsl_options*)arg)->params_dirty = true;
2355   return slider_set(&(((hlsl_options*)arg)->converge_x[2]), 0.1f, "%3.1f", str, newval);
2356}
2357
2358static INT32 slider_blue_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval)
2359{
2360   ((hlsl_options*)arg)->params_dirty = true;
2361   return slider_set(&(((hlsl_options*)arg)->converge_y[2]), 0.1f, "%3.1f", str, newval);
2362}
2363
2364static INT32 slider_red_radial_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval)
2365{
2366   ((hlsl_options*)arg)->params_dirty = true;
2367   return slider_set(&(((hlsl_options*)arg)->radial_converge_x[0]), 0.1f, "%3.1f", str, newval);
2368}
2369
2370static INT32 slider_red_radial_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval)
2371{
2372   ((hlsl_options*)arg)->params_dirty = true;
2373   return slider_set(&(((hlsl_options*)arg)->radial_converge_y[0]), 0.1f, "%3.1f", str, newval);
2374}
2375
2376static INT32 slider_green_radial_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval)
2377{
2378   ((hlsl_options*)arg)->params_dirty = true;
2379   return slider_set(&(((hlsl_options*)arg)->radial_converge_x[1]), 0.1f, "%3.1f", str, newval);
2380}
2381
2382static INT32 slider_green_radial_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval)
2383{
2384   ((hlsl_options*)arg)->params_dirty = true;
2385   return slider_set(&(((hlsl_options*)arg)->radial_converge_y[1]), 0.1f, "%3.1f", str, newval);
2386}
2387
2388static INT32 slider_blue_radial_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval)
2389{
2390   ((hlsl_options*)arg)->params_dirty = true;
2391   return slider_set(&(((hlsl_options*)arg)->radial_converge_x[2]), 0.1f, "%3.1f", str, newval);
2392}
2393
2394static INT32 slider_blue_radial_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval)
2395{
2396   ((hlsl_options*)arg)->params_dirty = true;
2397   return slider_set(&(((hlsl_options*)arg)->radial_converge_y[2]), 0.1f, "%3.1f", str, newval);
2398}
2399
2400static INT32 slider_red_from_r(running_machine &machine, void *arg, std::string *str, INT32 newval)
2401{
2402   ((hlsl_options*)arg)->params_dirty = true;
2403   return slider_set(&(((hlsl_options*)arg)->red_ratio[0]), 0.005f, "%2.3f", str, newval);
2404}
2405
2406static INT32 slider_red_from_g(running_machine &machine, void *arg, std::string *str, INT32 newval)
2407{
2408   ((hlsl_options*)arg)->params_dirty = true;
2409   return slider_set(&(((hlsl_options*)arg)->red_ratio[1]), 0.005f, "%2.3f", str, newval);
2410}
2411
2412static INT32 slider_red_from_b(running_machine &machine, void *arg, std::string *str, INT32 newval)
2413{
2414   ((hlsl_options*)arg)->params_dirty = true;
2415   return slider_set(&(((hlsl_options*)arg)->red_ratio[2]), 0.005f, "%2.3f", str, newval);
2416}
2417
2418static INT32 slider_green_from_r(running_machine &machine, void *arg, std::string *str, INT32 newval)
2419{
2420   ((hlsl_options*)arg)->params_dirty = true;
2421   return slider_set(&(((hlsl_options*)arg)->grn_ratio[0]), 0.005f, "%2.3f", str, newval);
2422}
2423
2424static INT32 slider_green_from_g(running_machine &machine, void *arg, std::string *str, INT32 newval)
2425{
2426   ((hlsl_options*)arg)->params_dirty = true;
2427   return slider_set(&(((hlsl_options*)arg)->grn_ratio[1]), 0.005f, "%2.3f", str, newval);
2428}
2429
2430static INT32 slider_green_from_b(running_machine &machine, void *arg, std::string *str, INT32 newval)
2431{
2432   ((hlsl_options*)arg)->params_dirty = true;
2433   return slider_set(&(((hlsl_options*)arg)->grn_ratio[2]), 0.005f, "%2.3f", str, newval);
2434}
2435
2436static INT32 slider_blue_from_r(running_machine &machine, void *arg, std::string *str, INT32 newval)
2437{
2438   ((hlsl_options*)arg)->params_dirty = true;
2439   return slider_set(&(((hlsl_options*)arg)->blu_ratio[0]), 0.005f, "%2.3f", str, newval);
2440}
2441
2442static INT32 slider_blue_from_g(running_machine &machine, void *arg, std::string *str, INT32 newval)
2443{
2444   ((hlsl_options*)arg)->params_dirty = true;
2445   return slider_set(&(((hlsl_options*)arg)->blu_ratio[1]), 0.005f, "%2.3f", str, newval);
2446}
2447
2448static INT32 slider_blue_from_b(running_machine &machine, void *arg, std::string *str, INT32 newval)
2449{
2450   ((hlsl_options*)arg)->params_dirty = true;
2451   return slider_set(&(((hlsl_options*)arg)->blu_ratio[2]), 0.005f, "%2.3f", str, newval);
2452}
2453
2454static INT32 slider_red_offset(running_machine &machine, void *arg, std::string *str, INT32 newval)
2455{
2456   ((hlsl_options*)arg)->params_dirty = true;
2457   return slider_set(&(((hlsl_options*)arg)->offset[0]), 0.01f, "%2.2f", str, newval);
2458}
2459
2460static INT32 slider_green_offset(running_machine &machine, void *arg, std::string *str, INT32 newval)
2461{
2462   ((hlsl_options*)arg)->params_dirty = true;
2463   return slider_set(&(((hlsl_options*)arg)->offset[1]), 0.01f, "%2.2f", str, newval);
2464}
2465
2466static INT32 slider_blue_offset(running_machine &machine, void *arg, std::string *str, INT32 newval)
2467{
2468   ((hlsl_options*)arg)->params_dirty = true;
2469   return slider_set(&(((hlsl_options*)arg)->offset[2]), 0.01f, "%2.2f", str, newval);
2470}
2471
2472static INT32 slider_red_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2473{
2474   ((hlsl_options*)arg)->params_dirty = true;
2475   return slider_set(&(((hlsl_options*)arg)->scale[0]), 0.01f, "%2.2f", str, newval);
2476}
2477
2478static INT32 slider_green_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2479{
2480   ((hlsl_options*)arg)->params_dirty = true;
2481   return slider_set(&(((hlsl_options*)arg)->scale[1]), 0.01f, "%2.2f", str, newval);
2482}
2483
2484static INT32 slider_blue_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2485{
2486   ((hlsl_options*)arg)->params_dirty = true;
2487   return slider_set(&(((hlsl_options*)arg)->scale[2]), 0.01f, "%2.2f", str, newval);
2488}
2489
2490static INT32 slider_red_power(running_machine &machine, void *arg, std::string *str, INT32 newval)
2491{
2492   ((hlsl_options*)arg)->params_dirty = true;
2493   return slider_set(&(((hlsl_options*)arg)->power[0]), 0.05f, "%2.2f", str, newval);
2494}
2495
2496static INT32 slider_green_power(running_machine &machine, void *arg, std::string *str, INT32 newval)
2497{
2498   ((hlsl_options*)arg)->params_dirty = true;
2499   return slider_set(&(((hlsl_options*)arg)->power[1]), 0.05f, "%2.2f", str, newval);
2500}
2501
2502static INT32 slider_blue_power(running_machine &machine, void *arg, std::string *str, INT32 newval)
2503{
2504   ((hlsl_options*)arg)->params_dirty = true;
2505   return slider_set(&(((hlsl_options*)arg)->power[2]), 0.05f, "%2.2f", str, newval);
2506}
2507
2508static INT32 slider_red_floor(running_machine &machine, void *arg, std::string *str, INT32 newval)
2509{
2510   ((hlsl_options*)arg)->params_dirty = true;
2511   return slider_set(&(((hlsl_options*)arg)->floor[0]), 0.01f, "%2.2f", str, newval);
2512}
2513
2514static INT32 slider_green_floor(running_machine &machine, void *arg, std::string *str, INT32 newval)
2515{
2516   ((hlsl_options*)arg)->params_dirty = true;
2517   return slider_set(&(((hlsl_options*)arg)->floor[1]), 0.01f, "%2.2f", str, newval);
2518}
2519
2520static INT32 slider_blue_floor(running_machine &machine, void *arg, std::string *str, INT32 newval)
2521{
2522   ((hlsl_options*)arg)->params_dirty = true;
2523   return slider_set(&(((hlsl_options*)arg)->floor[2]), 0.01f, "%2.2f", str, newval);
2524}
2525
2526static INT32 slider_red_phosphor_life(running_machine &machine, void *arg, std::string *str, INT32 newval)
2527{
2528   ((hlsl_options*)arg)->params_dirty = true;
2529   return slider_set(&(((hlsl_options*)arg)->phosphor[0]), 0.01f, "%2.2f", str, newval);
2530}
2531
2532static INT32 slider_green_phosphor_life(running_machine &machine, void *arg, std::string *str, INT32 newval)
2533{
2534   ((hlsl_options*)arg)->params_dirty = true;
2535   return slider_set(&(((hlsl_options*)arg)->phosphor[1]), 0.01f, "%2.2f", str, newval);
2536}
2537
2538static INT32 slider_blue_phosphor_life(running_machine &machine, void *arg, std::string *str, INT32 newval)
2539{
2540   ((hlsl_options*)arg)->params_dirty = true;
2541   return slider_set(&(((hlsl_options*)arg)->phosphor[2]), 0.01f, "%2.2f", str, newval);
2542}
2543
2544static INT32 slider_saturation(running_machine &machine, void *arg, std::string *str, INT32 newval)
2545{
2546   ((hlsl_options*)arg)->params_dirty = true;
2547   return slider_set(&(((hlsl_options*)arg)->saturation), 0.01f, "%2.2f", str, newval);
2548}
2549
2550static INT32 slider_vector_attenuation(running_machine &machine, void *arg, std::string *str, INT32 newval)
2551{
2552   ((hlsl_options*)arg)->params_dirty = true;
2553   return slider_set(&(((hlsl_options*)arg)->vector_length_scale), 0.01f, "%1.2f", str, newval);
2554}
2555
2556static INT32 slider_vector_length_max(running_machine &machine, void *arg, std::string *str, INT32 newval)
2557{
2558   ((hlsl_options*)arg)->params_dirty = true;
2559   return slider_set(&(((hlsl_options*)arg)->vector_length_ratio), 1.0f, "%4f", str, newval);
2560}
2561
2562static INT32 slider_bloom_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2563{
2564   ((hlsl_options*)arg)->params_dirty = true;
2565   return slider_set(&(((hlsl_options*)arg)->bloom_scale), 0.001f, "%1.3f", str, newval);
2566}
2567
2568static INT32 slider_bloom_red_overdrive(running_machine &machine, void *arg, std::string *str, INT32 newval)
2569{
2570   ((hlsl_options*)arg)->params_dirty = true;
2571   return slider_set(&(((hlsl_options*)arg)->bloom_overdrive[0]), 0.001f, "%1.3f", str, newval);
2572}
2573
2574static INT32 slider_bloom_green_overdrive(running_machine &machine, void *arg, std::string *str, INT32 newval)
2575{
2576   ((hlsl_options*)arg)->params_dirty = true;
2577   return slider_set(&(((hlsl_options*)arg)->bloom_overdrive[1]), 0.001f, "%1.3f", str, newval);
2578}
2579
2580static INT32 slider_bloom_blue_overdrive(running_machine &machine, void *arg, std::string *str, INT32 newval)
2581{
2582   ((hlsl_options*)arg)->params_dirty = true;
2583   return slider_set(&(((hlsl_options*)arg)->bloom_overdrive[2]), 0.001f, "%1.3f", str, newval);
2584}
2585
2586static INT32 slider_bloom_lvl0_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2587{
2588   ((hlsl_options*)arg)->params_dirty = true;
2589   return slider_set(&(((hlsl_options*)arg)->bloom_level0_weight), 0.01f, "%1.2f", str, newval);
2590}
2591
2592static INT32 slider_bloom_lvl1_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2593{
2594   ((hlsl_options*)arg)->params_dirty = true;
2595   return slider_set(&(((hlsl_options*)arg)->bloom_level1_weight), 0.01f, "%1.2f", str, newval);
2596}
2597
2598static INT32 slider_bloom_lvl2_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2599{
2600   ((hlsl_options*)arg)->params_dirty = true;
2601   return slider_set(&(((hlsl_options*)arg)->bloom_level2_weight), 0.01f, "%1.2f", str, newval);
2602}
2603
2604static INT32 slider_bloom_lvl3_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2605{
2606   ((hlsl_options*)arg)->params_dirty = true;
2607   return slider_set(&(((hlsl_options*)arg)->bloom_level3_weight), 0.01f, "%1.2f", str, newval);
2608}
2609
2610static INT32 slider_bloom_lvl4_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2611{
2612   ((hlsl_options*)arg)->params_dirty = true;
2613   return slider_set(&(((hlsl_options*)arg)->bloom_level4_weight), 0.01f, "%1.2f", str, newval);
2614}
2615
2616static INT32 slider_bloom_lvl5_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2617{
2618   ((hlsl_options*)arg)->params_dirty = true;
2619   return slider_set(&(((hlsl_options*)arg)->bloom_level5_weight), 0.01f, "%1.2f", str, newval);
2620}
2621
2622static INT32 slider_bloom_lvl6_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2623{
2624   ((hlsl_options*)arg)->params_dirty = true;
2625   return slider_set(&(((hlsl_options*)arg)->bloom_level6_weight), 0.01f, "%1.2f", str, newval);
2626}
2627
2628static INT32 slider_bloom_lvl7_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2629{
2630   ((hlsl_options*)arg)->params_dirty = true;
2631   return slider_set(&(((hlsl_options*)arg)->bloom_level7_weight), 0.01f, "%1.2f", str, newval);
2632}
2633
2634static INT32 slider_bloom_lvl8_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2635{
2636   ((hlsl_options*)arg)->params_dirty = true;
2637   return slider_set(&(((hlsl_options*)arg)->bloom_level8_weight), 0.01f, "%1.2f", str, newval);
2638}
2639
2640static INT32 slider_bloom_lvl9_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2641{
2642   ((hlsl_options*)arg)->params_dirty = true;
2643   return slider_set(&(((hlsl_options*)arg)->bloom_level9_weight), 0.01f, "%1.2f", str, newval);
2644}
2645
2646static INT32 slider_bloom_lvl10_scale(running_machine &machine, void *arg, std::string *str, INT32 newval)
2647{
2648   ((hlsl_options*)arg)->params_dirty = true;
2649   return slider_set(&(((hlsl_options*)arg)->bloom_level10_weight), 0.01f, "%1.2f", str, newval);
2650}
2651
2652
2653//============================================================
2654//  init_slider_list
2655//============================================================
2656
2657shaders::slider_desc shaders::s_sliders[] =
2658{
2659   { "Vector Length Attenuation",           0,    80,   100, 1, 2, slider_vector_attenuation },
2660   { "Vector Attenuation Length Limit",     1,   500,  1000, 1, 2, slider_vector_length_max },
2661   { "Shadow Mask Darkness",                0,     0,   100, 1, 7, slider_shadow_mask_alpha },
2662   { "Shadow Mask X Count",                 1,     6,  1024, 1, 7, slider_shadow_mask_x_count },
2663   { "Shadow Mask Y Count",                 1,     6,  1024, 1, 7, slider_shadow_mask_y_count },
2664   { "Shadow Mask Pixel Count X",           1,     6,    64, 1, 7, slider_shadow_mask_usize },
2665   { "Shadow Mask Pixel Count Y",           1,     6,    64, 1, 7, slider_shadow_mask_vsize },
2666   { "Shadow Mask Offset X",             -100,     0,   100, 1, 7, slider_shadow_mask_uoffset },
2667   { "Shadow Mask Offset Y",             -100,     0,   100, 1, 7, slider_shadow_mask_voffset },
2668   { "Screen Curvature",                    0,     0,   100, 1, 7, slider_curvature },
2669   { "Screen Round Corner",                 0,     0,   100, 1, 7, slider_round_corner },
2670   { "Screen Smooth Border",                0,     0,   100, 1, 7, slider_smooth_border },
2671   { "Screen Reflection",                   0,     0,   100, 1, 7, slider_reflection },
2672   { "Image Vignetting",                    0,     0,   100, 1, 7, slider_vignetting },
2673   { "Scanline Darkness",                   0,   100,   100, 1, 1, slider_scanline_alpha },
2674   { "Scanline Screen Height",              1,    20,    80, 1, 1, slider_scanline_scale },
2675   { "Scanline Indiv. Height",              1,    20,    80, 1, 1, slider_scanline_height },
2676   { "Scanline Brightness",                 0,    20,    40, 1, 1, slider_scanline_bright_scale },
2677   { "Scanline Brightness Overdrive",       0,     0,    20, 1, 1, slider_scanline_bright_offset },
2678   { "Scanline Jitter",                     0,     0,    40, 1, 1, slider_scanline_offset },
2679   { "Defocus X",                           0,     0,    64, 1, 3, slider_defocus_x },
2680   { "Defocus Y",                           0,     0,    64, 1, 3, slider_defocus_y },
2681   { "Red Position Offset X",           -1500,     3,  1500, 1, 3, slider_red_converge_x },
2682   { "Red Position Offset Y",           -1500,     0,  1500, 1, 3, slider_red_converge_y },
2683   { "Green Position Offset X",         -1500,     0,  1500, 1, 3, slider_green_converge_x },
2684   { "Green Position Offset Y",         -1500,     3,  1500, 1, 3, slider_green_converge_y },
2685   { "Blue Position Offset X",          -1500,     3,  1500, 1, 3, slider_blue_converge_x },
2686   { "Blue Position Offset Y",          -1500,     3,  1500, 1, 3, slider_blue_converge_y },
2687   { "Red Convergence X",               -1500,     0,  1500, 1, 3, slider_red_radial_converge_x },
2688   { "Red Convergence Y",               -1500,     0,  1500, 1, 3, slider_red_radial_converge_y },
2689   { "Green Convergence X",             -1500,     0,  1500, 1, 3, slider_green_radial_converge_x },
2690   { "Green Convergence Y",             -1500,     0,  1500, 1, 3, slider_green_radial_converge_y },
2691   { "Blue Convergence X",              -1500,     0,  1500, 1, 3, slider_blue_radial_converge_x },
2692   { "Blue Convergence Y",              -1500,     0,  1500, 1, 3, slider_blue_radial_converge_y },
2693   { "Red Output from Red Input",        -400,     0,   400, 5, 7, slider_red_from_r },
2694   { "Red Output from Green Input",      -400,     0,   400, 5, 7, slider_red_from_g },
2695   { "Red Output from Blue Input",       -400,     0,   400, 5, 7, slider_red_from_b },
2696   { "Green Output from Red Input",      -400,     0,   400, 5, 7, slider_green_from_r },
2697   { "Green Output from Green Input",    -400,     0,   400, 5, 7, slider_green_from_g },
2698   { "Green Output from Blue Input",     -400,     0,   400, 5, 7, slider_green_from_b },
2699   { "Blue Output from Red Input",       -400,     0,   400, 5, 7, slider_blue_from_r },
2700   { "Blue Output from Green Input",     -400,     0,   400, 5, 7, slider_blue_from_g },
2701   { "Blue Output from Blue Input",      -400,     0,   400, 5, 7, slider_blue_from_b },
2702   { "Saturation",                          0,   140,   400, 1, 7, slider_saturation },
2703   { "Red DC Offset",                    -100,     0,   100, 1, 7, slider_red_offset },
2704   { "Green DC Offset",                  -100,     0,   100, 1, 7, slider_green_offset },
2705   { "Blue DC Offset",                   -100,     0,   100, 1, 7, slider_blue_offset },
2706   { "Red Scale",                        -200,    95,   200, 1, 7, slider_red_scale },
2707   { "Green Scale",                      -200,    95,   200, 1, 7, slider_green_scale },
2708   { "Blue Scale",                       -200,    95,   200, 1, 7, slider_blue_scale },
2709   { "Red Gamma",                         -80,    16,    80, 1, 7, slider_red_power },
2710   { "Green Gamma",                       -80,    16,    80, 1, 7, slider_green_power },
2711   { "Blue Gamma",                        -80,    16,    80, 1, 7, slider_blue_power },
2712   { "Red Floor",                           0,     5,   100, 1, 7, slider_red_floor },
2713   { "Green Floor",                         0,     5,   100, 1, 7, slider_green_floor },
2714   { "Blue Floor",                          0,     5,   100, 1, 7, slider_blue_floor },
2715   { "Red Phosphor Life",                   0,    40,   100, 1, 7, slider_red_phosphor_life },
2716   { "Green Phosphor Life",                 0,    40,   100, 1, 7, slider_green_phosphor_life },
2717   { "Blue Phosphor Life",                  0,    40,   100, 1, 7, slider_blue_phosphor_life },
2718   { "Bloom Scale",                         0,   250,  2000, 5, 7, slider_bloom_scale },
2719   { "Bloom Red Overdrive",                 0,   250,  2000, 5, 7, slider_bloom_red_overdrive },
2720   { "Bloom Green Overdrive",               0,   250,  2000, 5, 7, slider_bloom_green_overdrive },
2721   { "Bloom Blue Overdrive",                0,   250,  2000, 5, 7, slider_bloom_blue_overdrive },
2722   { "Bloom Level 0 Scale",                 0,   100,   100, 1, 7, slider_bloom_lvl0_scale },
2723   { "Bloom Level 1 Scale",                 0,    21,   100, 1, 7, slider_bloom_lvl1_scale },
2724   { "Bloom Level 2 Scale",                 0,    19,   100, 1, 7, slider_bloom_lvl2_scale },
2725   { "Bloom Level 3 Scale",                 0,    17,   100, 1, 7, slider_bloom_lvl3_scale },
2726   { "Bloom Level 4 Scale",                 0,    15,   100, 1, 7, slider_bloom_lvl4_scale },
2727   { "Bloom Level 5 Scale",                 0,    14,   100, 1, 7, slider_bloom_lvl5_scale },
2728   { "Bloom Level 6 Scale",                 0,    13,   100, 1, 7, slider_bloom_lvl6_scale },
2729   { "Bloom Level 7 Scale",                 0,    12,   100, 1, 7, slider_bloom_lvl7_scale },
2730   { "Bloom Level 8 Scale",                 0,    11,   100, 1, 7, slider_bloom_lvl8_scale },
2731   { "Bloom Level 9 Scale",                 0,    10,   100, 1, 7, slider_bloom_lvl9_scale },
2732   { "Bloom Level 10 Scale",                0,     9,   100, 1, 7, slider_bloom_lvl10_scale },
2733   { NULL, 0, 0, 0, 0, 0, NULL },
2734};
2735
2736slider_state *shaders::init_slider_list()
2737{
2738   if (!master_enable || !d3dintf->post_fx_available)
2739   {
2740      g_slider_list = NULL;
2741      return NULL;
2742   }
2743
2744   slider_state *listhead = NULL;
2745   slider_state **tailptr = &listhead;
2746
2747   for (int index = 0; s_sliders[index].name != NULL; index++)
2748   {
2749      slider_desc *slider = &s_sliders[index];
2750
2751      int screen_type = machine->first_screen()->screen_type();
2752      if ((screen_type == SCREEN_TYPE_VECTOR && (slider->screen_type & SLIDER_SCREEN_TYPE_VECTOR) == SLIDER_SCREEN_TYPE_VECTOR) ||
2753         (screen_type == SCREEN_TYPE_RASTER && (slider->screen_type & SLIDER_SCREEN_TYPE_RASTER) == SLIDER_SCREEN_TYPE_RASTER) ||
2754         (screen_type == SCREEN_TYPE_LCD    && (slider->screen_type & SLIDER_SCREEN_TYPE_LCD)    == SLIDER_SCREEN_TYPE_LCD))
2755      {
2756         *tailptr = slider_alloc(*machine, slider->name, slider->minval, slider->defval, slider->maxval, slider->step, slider->adjustor, (void*)options);
2757         tailptr = &(*tailptr)->next;
2758      }
2759   }
2760
2761   return listhead;
2762}
2763
2764
2765//============================================================
2766//  uniform functions
2767//============================================================
2768
2769uniform::uniform(effect *shader, const char *name, uniform_type type, int id)
2770{
2771   m_shader = shader;
2772   m_type = type;
2773   m_next = NULL;
2774   m_handle = m_shader->get_parameter(NULL, name);
2775   m_ival = 0;
2776   memset(m_vec, 0, sizeof(float) * 4);
2777   m_mval = NULL;
2778   m_texture = NULL;
2779   m_id = id;
2780
2781   switch (type)
2782   {
2783      case UT_INT:
2784      case UT_FLOAT:
2785      case UT_MATRIX:
2786      case UT_SAMPLER:
2787         m_count = 1;
2788         break;
2789      case UT_VEC2:
2790         m_count = 2;
2791         break;
2792      case UT_VEC3:
2793         m_count = 3;
2794         break;
2795      case UT_VEC4:
2796         m_count = 4;
2797         break;
2798      default:
2799         m_count = 1;
2800         break;
2801   }
2802}
2803
2804void uniform::set_next(uniform *next)
2805{
2806   m_next = next;
2807}
2808
2809void uniform::update()
2810{
2811   if (m_id >= CU_COUNT)
2812   {
2813      return;
2814   }
2815
2816   shaders *shadersys = m_shader->m_shaders;
2817   hlsl_options *options = shadersys->options;
2818   renderer *d3d = shadersys->d3d;
2819
2820   switch (m_id)
2821   {
2822      case CU_SCREEN_DIMS:
2823      {
2824         vec2f screendims = d3d->get_dims();
2825         m_shader->set_vector("ScreenDims", 2, &screendims.c.x);
2826         break;
2827      }
2828      case CU_SOURCE_DIMS:
2829      {
2830         vec2f sourcedims = shadersys->curr_texture->get_rawdims();
2831         m_shader->set_vector("SourceDims", 2, &sourcedims.c.x);
2832         break;
2833      }
2834      case CU_SOURCE_RECT:
2835      {
2836         vec2f delta = shadersys->curr_texture->get_uvstop() - shadersys->curr_texture->get_uvstart();
2837         m_shader->set_vector("SourceRect", 2, &delta.c.x);
2838         break;
2839      }
2840      case CU_TARGET_DIMS:
2841      {
2842         if (shadersys->curr_render_target == NULL)
2843         {
2844            float targetdims[2] = { 0.0f, 0.0f };
2845            m_shader->set_vector("TargetDims", 2, targetdims);
2846         }
2847         else
2848         {
2849            float targetdims[2] = { shadersys->curr_render_target->target_width, shadersys->curr_render_target->target_height };
2850            m_shader->set_vector("TargetDims", 2, targetdims);
2851         }
2852         break;
2853      }
2854      case CU_QUAD_DIMS:
2855      {
2856         float quaddims[2] = { shadersys->curr_poly->get_prim_width(), shadersys->curr_poly->get_prim_height() };
2857         m_shader->set_vector("QuadDims", 2, quaddims);
2858         break;
2859      }
2860
2861      case CU_NTSC_CCFREQ:
2862         m_shader->set_float("CCValue", options->yiq_cc);
2863         break;
2864      case CU_NTSC_A:
2865         m_shader->set_float("AValue", options->yiq_a);
2866         break;
2867      case CU_NTSC_B:
2868         m_shader->set_float("BValue", options->yiq_b);
2869         break;
2870      case CU_NTSC_O:
2871         m_shader->set_float("OValue", options->yiq_o);
2872         break;
2873      case CU_NTSC_P:
2874         m_shader->set_float("PValue", options->yiq_p);
2875         break;
2876      case CU_NTSC_NOTCH:
2877         m_shader->set_float("NotchHalfWidth", options->yiq_n);
2878         break;
2879      case CU_NTSC_YFREQ:
2880         m_shader->set_float("YFreqResponse", options->yiq_y);
2881         break;
2882      case CU_NTSC_IFREQ:
2883         m_shader->set_float("IFreqResponse", options->yiq_i);
2884         break;
2885      case CU_NTSC_QFREQ:
2886         m_shader->set_float("QFreqResponse", options->yiq_q);
2887         break;
2888      case CU_NTSC_HTIME:
2889         m_shader->set_float("ScanTime", options->yiq_scan_time);
2890         break;
2891      case CU_NTSC_ENABLE:
2892         m_shader->set_float("YIQEnable", options->yiq_enable ? 1.0f : 0.0f);
2893         break;
2894
2895      case CU_COLOR_RED_RATIOS:
2896         m_shader->set_vector("RedRatios", 3, options->red_ratio);
2897         break;
2898      case CU_COLOR_GRN_RATIOS:
2899         m_shader->set_vector("GrnRatios", 3, options->grn_ratio);
2900         break;
2901      case CU_COLOR_BLU_RATIOS:
2902         m_shader->set_vector("BluRatios", 3, options->blu_ratio);
2903         break;
2904      case CU_COLOR_OFFSET:
2905         m_shader->set_vector("Offset", 3, options->offset);
2906         break;
2907      case CU_COLOR_SCALE:
2908         m_shader->set_vector("Scale", 3, options->scale);
2909         break;
2910      case CU_COLOR_SATURATION:
2911         m_shader->set_float("Saturation", options->saturation);
2912         break;
2913
2914      case CU_CONVERGE_LINEAR_X:
2915         m_shader->set_vector("ConvergeX", 3, options->converge_x);
2916         break;
2917      case CU_CONVERGE_LINEAR_Y:
2918         m_shader->set_vector("ConvergeY", 3, options->converge_y);
2919         break;
2920      case CU_CONVERGE_RADIAL_X:
2921         m_shader->set_vector("RadialConvergeX", 3, options->radial_converge_x);
2922         break;
2923      case CU_CONVERGE_RADIAL_Y:
2924         m_shader->set_vector("RadialConvergeY", 3, options->radial_converge_y);
2925         break;
2926
2927      case CU_FOCUS_SIZE:
2928         m_shader->set_vector("Defocus", 2, &options->defocus[0]);
2929         break;
2930
2931      case CU_PHOSPHOR_LIFE:
2932         m_shader->set_vector("Phosphor", 3, options->phosphor);
2933         break;
2934
2935      case CU_POST_REFLECTION:
2936         m_shader->set_float("ReflectionAmount", options->reflection);
2937         break;
2938      case CU_POST_VIGNETTING:
2939         m_shader->set_float("VignettingAmount", options->vignetting);
2940         break;
2941      case CU_POST_CURVATURE:
2942         m_shader->set_float("CurvatureAmount", options->curvature);
2943         break;
2944      case CU_POST_ROUND_CORNER:
2945         m_shader->set_float("RoundCornerAmount", options->round_corner);
2946         break;
2947      case CU_POST_SMOOTH_BORDER:
2948         m_shader->set_float("SmoothBorderAmount", options->smooth_border);
2949         break;
2950      case CU_POST_SHADOW_ALPHA:
2951         m_shader->set_float("ShadowAlpha", shadersys->shadow_texture == NULL ? 0.0f : options->shadow_mask_alpha);
2952         break;
2953      case CU_POST_SHADOW_COUNT:
2954      {
2955         float shadowcount[2] = { options->shadow_mask_count_x, options->shadow_mask_count_y };
2956         m_shader->set_vector("ShadowCount", 2, shadowcount);
2957         break;
2958      }
2959      case CU_POST_SHADOW_UV:
2960      {
2961         float shadowuv[2] = { options->shadow_mask_u_size, options->shadow_mask_v_size };
2962         m_shader->set_vector("ShadowUV", 2, shadowuv);
2963         break;
2964      }
2965      case CU_POST_SHADOW_UV_OFFSET:
2966      {
2967         float shadowuv[2] = { options->shadow_mask_u_offset, options->shadow_mask_v_offset };
2968         m_shader->set_vector("ShadowUVOffset", 2, shadowuv);
2969         break;
2970      }
2971      case CU_POST_SHADOW_DIMS:
2972      {
2973         vec2f shadow_dims;
2974
2975         if (shadersys->shadow_texture)
2976         {
2977            shadow_dims = shadersys->shadow_texture->get_rawdims();
2978         }
2979         else
2980         {
2981            shadow_dims.c.x = 1.0f;
2982            shadow_dims.c.y = 1.0f;
2983         }
2984
2985         m_shader->set_vector("ShadowDims", 2, &shadow_dims.c.x);
2986         break;
2987      }
2988      case CU_POST_SCANLINE_ALPHA:
2989         m_shader->set_float("ScanlineAlpha", options->scanline_alpha);
2990         break;
2991      case CU_POST_SCANLINE_SCALE:
2992         m_shader->set_float("ScanlineScale", options->scanline_scale);
2993         break;
2994      case CU_POST_SCANLINE_HEIGHT:
2995         m_shader->set_float("ScanlineHeight", options->scanline_height);
2996         break;
2997      case CU_POST_SCANLINE_BRIGHT_SCALE:
2998         m_shader->set_float("ScanlineBrightScale", options->scanline_bright_scale);
2999         break;
3000      case CU_POST_SCANLINE_BRIGHT_OFFSET:
3001         m_shader->set_float("ScanlineBrightOffset", options->scanline_bright_offset);
3002         break;
3003      case CU_POST_POWER:
3004         m_shader->set_vector("Power", 3, options->power);
3005         break;
3006      case CU_POST_FLOOR:
3007         m_shader->set_vector("Floor", 3, options->floor);
3008         break;
3009
3010      case CU_BLOOM_RESCALE:
3011         m_shader->set_float("BloomRescale", options->bloom_scale);
3012         break;
3013      case CU_BLOOM_LVL0123_WEIGHTS:
3014      {
3015         float weight0123[4] = { options->bloom_level0_weight, options->bloom_level1_weight, options->bloom_level2_weight, options->bloom_level3_weight };
3016         m_shader->set_vector("Level0123Weight", 4, weight0123);
3017         break;
3018      }
3019      case CU_BLOOM_LVL4567_WEIGHTS:
3020      {
3021         float weight4567[4] = { options->bloom_level4_weight, options->bloom_level5_weight, options->bloom_level6_weight, options->bloom_level7_weight };
3022         m_shader->set_vector("Level4567Weight", 4, weight4567);
3023         break;
3024      }
3025      case CU_BLOOM_LVL89A_WEIGHTS:
3026      {
3027         float weight89A[3]  = { options->bloom_level8_weight, options->bloom_level9_weight, options->bloom_level10_weight };
3028         m_shader->set_vector("Level89AWeight", 3, weight89A);
3029         break;
3030      }
3031   }
3032}
3033
3034void uniform::set(float x, float y, float z, float w)
3035{
3036   m_vec[0] = x;
3037   m_vec[1] = y;
3038   m_vec[2] = z;
3039   m_vec[3] = w;
3040}
3041
3042void uniform::set(float x, float y, float z)
3043{
3044   m_vec[0] = x;
3045   m_vec[1] = y;
3046   m_vec[2] = z;
3047}
3048
3049void uniform::set(float x, float y)
3050{
3051   m_vec[0] = x;
3052   m_vec[1] = y;
3053}
3054
3055void uniform::set(float x)
3056{
3057   m_vec[0] = x;
3058}
3059
3060void uniform::set(int x)
3061{
3062   m_ival = x;
3063}
3064
3065void uniform::set(matrix *mat)
3066{
3067   m_mval = mat;
3068}
3069
3070void uniform::set(texture *tex)
3071{
3072   m_texture = tex;
3073}
3074
3075void uniform::upload()
3076{
3077   switch (m_type)
3078   {
3079      case UT_INT:
3080         m_shader->set_int(m_handle, m_ival);
3081         break;
3082      case UT_FLOAT:
3083         m_shader->set_float(m_handle, m_vec[0]);
3084         break;
3085      case UT_VEC2:
3086      case UT_VEC3:
3087      case UT_VEC4:
3088         m_shader->set_vector(m_handle, m_count, m_vec);
3089         break;
3090      case UT_MATRIX:
3091         m_shader->set_matrix(m_handle, m_mval);
3092         break;
3093      case UT_SAMPLER:
3094         m_shader->set_texture(m_handle, m_texture);
3095         break;
3096   }
3097}
3098
3099
3100//============================================================
3101//  effect functions
3102//============================================================
3103
3104effect::effect(shaders *shadersys, device *dev, const char *name, const char *path)
3105{
3106   IDirect3DDevice9 *device = (IDirect3DDevice9 *)dev;
3107   LPD3DXBUFFER buffer_errors = NULL;
3108
3109   m_shaders = shadersys;
3110   m_uniform_head = NULL;
3111   m_uniform_tail = NULL;
3112   m_effect = NULL;
3113   m_valid = false;
3114
3115   char name_cstr[1024];
3116   sprintf(name_cstr, "%s\\%s", path, name);
3117   TCHAR *effect_name = tstring_from_utf8(name_cstr);
3118
3119   HRESULT hr = (*g_load_effect)(device, effect_name, NULL, NULL, 0, NULL, &m_effect, &buffer_errors);
3120   if (FAILED(hr))
3121   {
3122      if (buffer_errors != NULL)
3123      {
3124         LPVOID compile_errors = buffer_errors->GetBufferPointer();
3125         printf("Unable to compile shader: %s\n", (const char*)compile_errors); fflush(stdout);
3126      }
3127      else
3128      {
3129         printf("Shader %s is missing, corrupt or cannot be compiled.\n", (const char*)name); fflush(stdout);
3130      }
3131   }
3132   else
3133   {
3134      m_valid = true;
3135   }
3136
3137   osd_free(effect_name);
3138}
3139
3140effect::~effect()
3141{
3142   m_effect->Release();
3143   m_effect = NULL;
3144   uniform *curr = m_uniform_head;
3145   while (curr != NULL)
3146   {
3147      uniform *next = curr->get_next();
3148      delete curr;
3149      curr = next;
3150   }
3151   m_uniform_head = NULL;
3152   m_uniform_tail = NULL;
3153}
3154
3155void effect::add_uniform(const char *name, uniform::uniform_type type, int id)
3156{
3157   uniform *newuniform = new uniform(this, name, type, id);
3158   if (newuniform == NULL)
3159   {
3160      return;
3161   }
3162
3163   if (m_uniform_head == NULL)
3164   {
3165      m_uniform_head = newuniform;
3166   }
3167   if (m_uniform_tail != NULL)
3168   {
3169      m_uniform_tail->set_next(newuniform);
3170   }
3171   m_uniform_tail = newuniform;
3172}
3173
3174void effect::update_uniforms()
3175{
3176   uniform *curr = m_uniform_head;
3177   while(curr != NULL)
3178   {
3179      curr->update();
3180      curr = curr->get_next();
3181   }
3182}
3183
3184void effect::begin(UINT *passes, DWORD flags)
3185{
3186   m_effect->Begin(passes, flags);
3187}
3188
3189void effect::end()
3190{
3191   m_effect->End();
3192}
3193
3194void effect::begin_pass(UINT pass)
3195{
3196   m_effect->BeginPass(pass);
3197}
3198
3199void effect::end_pass()
3200{
3201   m_effect->EndPass();
3202}
3203
3204void effect::set_technique(const char *name)
3205{
3206   m_effect->SetTechnique(name);
3207}
3208
3209void effect::set_vector(D3DXHANDLE param, int count, float *vector)
3210{
3211   static D3DXVECTOR4 out_vector;
3212   if (count > 0)
3213   {
3214      out_vector.x = vector[0];
3215   }
3216   if (count > 1)
3217   {
3218      out_vector.y = vector[1];
3219   }
3220   if (count > 2)
3221   {
3222      out_vector.z = vector[2];
3223   }
3224   if (count > 3)
3225   {
3226      out_vector.w = vector[3];
3227   }
3228   m_effect->SetVector(param, &out_vector);
3229}
3230
3231void effect::set_float(D3DXHANDLE param, float value)
3232{
3233   m_effect->SetFloat(param, value);
3234}
3235
3236void effect::set_int(D3DXHANDLE param, int value)
3237{
3238   m_effect->SetInt(param, value);
3239}
3240
3241void effect::set_bool(D3DXHANDLE param, bool value)
3242{
3243   m_effect->SetBool(param, value);
3244}
3245
3246void effect::set_matrix(D3DXHANDLE param, matrix *matrix)
3247{
3248   m_effect->SetMatrix(param, (D3DXMATRIX*)matrix);
3249}
3250
3251void effect::set_texture(D3DXHANDLE param, texture *tex)
3252{
3253   m_effect->SetTexture(param, (IDirect3DTexture9*)tex);
3254}
3255
3256D3DXHANDLE effect::get_parameter(D3DXHANDLE param, const char *name)
3257{
3258   return m_effect->GetParameterByName(param, name);
3259}
3260
3261ULONG effect::release()
3262{
3263   return m_effect->Release();
3264}
3265
3266}
3267
3268
3269//============================================================
3270//  get_slider_list
3271//============================================================
3272
3273void *windows_osd_interface::get_slider_list()
3274{
3275   return (void*)g_slider_list;
3276}
3277
3278
3279// NOTE: The function below is taken directly from src/emu/video.c and should likely be moved into a global helper function.
3280//-------------------------------------------------
3281//  open_next - open the next non-existing file of
3282//  type filetype according to our numbering
3283//  scheme
3284//-------------------------------------------------
3285
3286static file_error open_next(d3d::renderer *d3d, emu_file &file, const char *templ, const char *extension, int idx)
3287{
3288   UINT32 origflags = file.openflags();
3289
3290   // handle defaults
3291   const char *snapname = templ ? templ : d3d->window().machine().options().snap_name();
3292
3293   if (snapname == NULL || snapname[0] == 0)
3294   {
3295      snapname = "%g/%i";
3296   }
3297   std::string snapstr(snapname);
3298
3299   // strip any extension in the provided name
3300   int index = snapstr.find_last_of('.');
3301   if (index != -1)
3302   {
3303      snapstr.substr(0, index);
3304   }
3305
3306   // handle %d in the template (for image devices)
3307   std::string snapdev("%d_");
3308   int pos = snapstr.find(snapdev,0);
3309
3310   if (pos != -1)
3311   {
3312      // if more %d are found, revert to default and ignore them all
3313      if (snapstr.find(snapdev, pos + 3) != -1)
3314      {
3315         snapstr.assign("%g/%i");
3316      }
3317      // else if there is a single %d, try to create the correct snapname
3318      else
3319      {
3320         int name_found = 0;
3321
3322         // find length of the device name
3323         int end1 = snapstr.find("/", pos + 3);
3324         int end2 = snapstr.find("%", pos + 3);
3325         int end = -1;
3326
3327         if ((end1 != -1) && (end2 != -1))
3328         {
3329            end = MIN(end1, end2);
3330         }
3331         else if (end1 != -1)
3332         {
3333            end = end1;
3334         }
3335         else if (end2 != -1)
3336         {
3337            end = end2;
3338         }
3339         else
3340         {
3341            end = snapstr.length();
3342         }
3343
3344         if (end - pos < 3)
3345         {
3346            fatalerror("Something very wrong is going on!!!\n");
3347         }
3348
3349         // copy the device name to a string
3350         std::string snapdevname;
3351         snapdevname.assign(snapstr.substr(pos + 3, end - pos - 3));
3352
3353         // verify that there is such a device for this system
3354         image_interface_iterator iter(d3d->window().machine().root_device());
3355         for (device_image_interface *image = iter.first(); image != NULL; iter.next())
3356         {
3357            // get the device name
3358            std::string tempdevname(image->brief_instance_name());
3359
3360            if (snapdevname.compare(tempdevname) == 0)
3361            {
3362               // verify that such a device has an image mounted
3363               if (image->basename() != NULL)
3364               {
3365                  std::string filename(image->basename());
3366
3367                  // strip extension
3368                  filename.substr(0, filename.find_last_of('.'));
3369
3370                  // setup snapname and remove the %d_
3371                  strreplace(snapstr, snapdevname.c_str(), filename.c_str());
3372                  snapstr.erase(pos, 3);
3373
3374                  name_found = 1;
3375               }
3376            }
3377         }
3378
3379         // or fallback to default
3380         if (name_found == 0)
3381         {
3382            snapstr.assign("%g/%i");
3383         }
3384      }
3385   }
3386
3387   // add our own index
3388   // add our own extension
3389   snapstr.append(".").append(extension);
3390
3391   // substitute path and gamename up front
3392   strreplace(snapstr, "/", PATH_SEPARATOR);
3393   strreplace(snapstr, "%g", d3d->window().machine().basename());
3394
3395   // determine if the template has an index; if not, we always use the same name
3396   std::string fname;
3397   if (snapstr.find("%i") == -1)
3398   {
3399      fname.assign(snapstr);
3400   }
3401
3402   // otherwise, we scan for the next available filename
3403   else
3404   {
3405      // try until we succeed
3406      std::string seqtext;
3407      file.set_openflags(OPEN_FLAG_READ);
3408      for (int seq = 0; ; seq++)
3409      {
3410         // build up the filename
3411         strprintf(seqtext, "%04d_%d", seq, idx);
3412         strreplace(fname.assign(snapstr), "%i", seqtext.c_str());
3413
3414         // try to open the file; stop when we fail
3415         file_error filerr = file.open(fname.c_str());
3416         if (filerr != FILERR_NONE)
3417         {
3418            break;
3419         }
3420      }
3421   }
3422
3423   // create the final file
3424   file.set_openflags(origflags);
3425   return file.open(fname.c_str());
3426}
trunk/src/osd/modules/render/drawd3d.c
r250287r250288
1// license:BSD-3-Clause
2// copyright-holders:Aaron Giles
3//============================================================
4//
5//  drawd3d.c - Win32 Direct3D implementation
6//
7//============================================================
8
9// Useful info:
10//  Windows XP/2003 shipped with DirectX 8.1
11//  Windows 2000 shipped with DirectX 7a
12//  Windows 98SE shipped with DirectX 6.1a
13//  Windows 98 shipped with DirectX 5
14//  Windows NT shipped with DirectX 3.0a
15//  Windows 95 shipped with DirectX 2
16
17// standard windows headers
18#define WIN32_LEAN_AND_MEAN
19#include <windows.h>
20#include <tchar.h>
21#include <mmsystem.h>
22#include <d3d9.h>
23#include <d3dx9.h>
24#include <math.h>
25#undef interface
26
27// MAME headers
28#include "emu.h"
29#include "render.h"
30#include "ui/ui.h"
31#include "rendutil.h"
32#include "options.h"
33#include "emuopts.h"
34#include "aviio.h"
35#include "png.h"
36
37// MAMEOS headers
38#include "modules/render/d3d/d3dintf.h"
39#include "winmain.h"
40#include "window.h"
41#include "config.h"
42#include "strconv.h"
43#include "modules/render/d3d/d3dcomm.h"
44#include "drawd3d.h"
45
46
47//============================================================
48//  DEBUGGING
49//============================================================
50
51extern void mtlog_add(const char *event);
52
53
54//============================================================
55//  CONSTANTS
56//============================================================
57
58#define ENABLE_BORDER_PIX   (1)
59
60enum
61{
62   TEXTURE_TYPE_PLAIN,
63   TEXTURE_TYPE_DYNAMIC,
64   TEXTURE_TYPE_SURFACE
65};
66
67
68//============================================================
69//  MACROS
70//============================================================
71
72#define FSWAP(var1, var2) do { float temp = var1; var1 = var2; var2 = temp; } while (0)
73
74
75//============================================================
76//  GLOBALS
77//============================================================
78
79static const line_aa_step line_aa_1step[] =
80{
81   {  0.00f,  0.00f,  1.00f  },
82   { 0 }
83};
84
85static const line_aa_step line_aa_4step[] =
86{
87   { -0.25f,  0.00f,  0.25f  },
88   {  0.25f,  0.00f,  0.25f  },
89   {  0.00f, -0.25f,  0.25f  },
90   {  0.00f,  0.25f,  0.25f  },
91   { 0 }
92};
93
94
95//============================================================
96//  INLINES
97//============================================================
98
99INLINE BOOL GetClientRectExceptMenu(HWND hWnd, PRECT pRect, BOOL fullscreen)
100{
101   static HMENU last_menu;
102   static RECT last_rect;
103   static RECT cached_rect;
104   HMENU menu = GetMenu(hWnd);
105   BOOL result = GetClientRect(hWnd, pRect);
106
107   if (!fullscreen || !menu)
108      return result;
109
110   // to avoid flicker use cache if we can use
111   if (last_menu != menu || memcmp(&last_rect, pRect, sizeof *pRect) != 0)
112   {
113      last_menu = menu;
114      last_rect = *pRect;
115
116      SetMenu(hWnd, NULL);
117      result = GetClientRect(hWnd, &cached_rect);
118      SetMenu(hWnd, menu);
119   }
120
121   *pRect = cached_rect;
122   return result;
123}
124
125
126INLINE UINT32 ycc_to_rgb(UINT8 y, UINT8 cb, UINT8 cr)
127{
128   /* original equations:
129
130       C = Y - 16
131       D = Cb - 128
132       E = Cr - 128
133
134       R = clip(( 298 * C           + 409 * E + 128) >> 8)
135       G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8)
136       B = clip(( 298 * C + 516 * D           + 128) >> 8)
137
138       R = clip(( 298 * (Y - 16)                    + 409 * (Cr - 128) + 128) >> 8)
139       G = clip(( 298 * (Y - 16) - 100 * (Cb - 128) - 208 * (Cr - 128) + 128) >> 8)
140       B = clip(( 298 * (Y - 16) + 516 * (Cb - 128)                    + 128) >> 8)
141
142       R = clip(( 298 * Y - 298 * 16                        + 409 * Cr - 409 * 128 + 128) >> 8)
143       G = clip(( 298 * Y - 298 * 16 - 100 * Cb + 100 * 128 - 208 * Cr + 208 * 128 + 128) >> 8)
144       B = clip(( 298 * Y - 298 * 16 + 516 * Cb - 516 * 128                        + 128) >> 8)
145
146       R = clip(( 298 * Y - 298 * 16                        + 409 * Cr - 409 * 128 + 128) >> 8)
147       G = clip(( 298 * Y - 298 * 16 - 100 * Cb + 100 * 128 - 208 * Cr + 208 * 128 + 128) >> 8)
148       B = clip(( 298 * Y - 298 * 16 + 516 * Cb - 516 * 128                        + 128) >> 8)
149   */
150   int r, g, b, common;
151
152   common = 298 * y - 298 * 16;
153   r = (common +                        409 * cr - 409 * 128 + 128) >> 8;
154   g = (common - 100 * cb + 100 * 128 - 208 * cr + 208 * 128 + 128) >> 8;
155   b = (common + 516 * cb - 516 * 128                        + 128) >> 8;
156
157   if (r < 0) r = 0;
158   else if (r > 255) r = 255;
159   if (g < 0) g = 0;
160   else if (g > 255) g = 255;
161   if (b < 0) b = 0;
162   else if (b > 255) b = 255;
163
164   return rgb_t(0xff, r, g, b);
165}
166
167
168//============================================================
169//  drawd3d_init
170//============================================================
171
172static d3d::base *               d3dintf; // FIX ME
173
174
175//============================================================
176//  PROTOTYPES
177//============================================================
178
179// core functions
180static void drawd3d_exit(void);
181
182
183//============================================================
184//  drawd3d_window_init
185//============================================================
186
187int d3d::renderer::create()
188{
189   if (!initialize())
190   {
191      destroy();
192      osd_printf_error("Unable to initialize Direct3D.\n");
193      return 1;
194   }
195
196   return 0;
197}
198
199
200//============================================================
201//  drawd3d_exit
202//============================================================
203
204static void drawd3d_exit(void)
205{
206   if (d3dintf != NULL)
207      (*d3dintf->d3d.release)(d3dintf);
208}
209
210void d3d::renderer::toggle_fsfx()
211{
212   set_restarting(true);
213}
214
215void d3d::renderer::record()
216{
217   get_shaders()->window_record();
218}
219
220void d3d::renderer::save()
221{
222   get_shaders()->window_save();
223}
224
225
226//============================================================
227//  drawd3d_window_destroy
228//============================================================
229
230void d3d::renderer::destroy()
231{
232   if (get_shaders() != NULL && get_shaders()->recording())
233      get_shaders()->window_record();
234
235}
236
237
238//============================================================
239//  drawd3d_window_get_primitives
240//============================================================
241
242render_primitive_list *d3d::renderer::get_primitives()
243{
244   RECT client;
245
246   GetClientRectExceptMenu(window().m_hwnd, &client, window().fullscreen());
247   if (rect_width(&client) > 0 && rect_height(&client) > 0)
248   {
249      window().target()->set_bounds(rect_width(&client), rect_height(&client), window().aspect());
250      window().target()->set_max_update_rate((get_refresh() == 0) ? get_origmode().RefreshRate : get_refresh());
251   }
252   return &window().target()->get_primitives();
253}
254
255
256//============================================================
257//  drawnone_create
258//============================================================
259
260static osd_renderer *drawd3d_create(osd_window *window)
261{
262   return global_alloc(d3d::renderer(window));
263}
264
265int drawd3d_init(running_machine &machine, osd_draw_callbacks *callbacks)
266{
267   d3dintf = NULL;
268
269   // Use Direct3D9
270   d3dintf = d3d::drawd3d9_init();
271
272   // if we failed, note the error
273   if (d3dintf == NULL)
274   {
275      osd_printf_error("Unable to initialize Direct3D.\n");
276      return 1;
277   }
278
279   // fill in the callbacks
280   memset(callbacks, 0, sizeof(*callbacks));
281   callbacks->exit = drawd3d_exit;
282   callbacks->create = drawd3d_create;
283   return 0;
284}
285
286
287//============================================================
288//  drawd3d_window_draw
289//============================================================
290
291int d3d::renderer::draw(const int update)
292{
293   int check = pre_window_draw_check();
294   if (check >= 0)
295      return check;
296
297   begin_frame();
298   process_primitives();
299   end_frame();
300
301   return 0;
302}
303
304namespace d3d
305{
306void renderer::set_texture(texture_info *texture)
307{
308   if (texture != m_last_texture)
309   {
310      m_last_texture = texture;
311      m_last_texture_flags = (texture == NULL ? 0 : texture->get_flags());
312      HRESULT result = (*d3dintf->device.set_texture)(m_device, 0, (texture == NULL) ? get_default_texture()->get_finaltex() : texture->get_finaltex());
313      m_shaders->set_texture(texture);
314      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture call\n", (int)result);
315   }
316}
317
318void renderer::set_filter(int filter)
319{
320   if (filter != m_last_filter)
321   {
322      m_last_filter = filter;
323      HRESULT result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MINFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT);
324      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
325      result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MAGFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT);
326      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
327      result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MINFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT);
328      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
329      result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MAGFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT);
330      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
331   }
332}
333
334void renderer::set_wrap(D3DTEXTUREADDRESS wrap)
335{
336   if (wrap != m_last_wrap)
337   {
338      m_last_wrap = wrap;
339      HRESULT result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSU, wrap);
340      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
341      result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSV, wrap);
342      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
343      result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSU, wrap);
344      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
345      result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSV, wrap);
346      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
347   }
348}
349
350void renderer::set_modmode(DWORD modmode)
351{
352   if (modmode != m_last_modmode)
353   {
354      m_last_modmode = modmode;
355      HRESULT result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, D3DTSS_COLOROP, modmode);
356      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
357      result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, D3DTSS_COLOROP, modmode);
358      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
359   }
360}
361
362void renderer::set_blendmode(int blendmode)
363{
364   int blendenable;
365   int blendop;
366   int blendsrc;
367   int blenddst;
368
369   // choose the parameters
370   switch (blendmode)
371   {
372      default:
373      case BLENDMODE_NONE:            blendenable = FALSE;    blendop = D3DBLENDOP_ADD;   blendsrc = D3DBLEND_SRCALPHA;   blenddst = D3DBLEND_INVSRCALPHA;    break;
374      case BLENDMODE_ALPHA:           blendenable = TRUE;     blendop = D3DBLENDOP_ADD;   blendsrc = D3DBLEND_SRCALPHA;   blenddst = D3DBLEND_INVSRCALPHA;    break;
375      case BLENDMODE_RGB_MULTIPLY:    blendenable = TRUE;     blendop = D3DBLENDOP_ADD;   blendsrc = D3DBLEND_DESTCOLOR;  blenddst = D3DBLEND_ZERO;           break;
376      case BLENDMODE_ADD:             blendenable = TRUE;     blendop = D3DBLENDOP_ADD;   blendsrc = D3DBLEND_SRCALPHA;   blenddst = D3DBLEND_ONE;            break;
377   }
378
379   // adjust the bits that changed
380   if (blendenable != m_last_blendenable)
381   {
382      m_last_blendenable = blendenable;
383      HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHABLENDENABLE, blendenable);
384      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result);
385   }
386
387   if (blendop != m_last_blendop)
388   {
389      m_last_blendop = blendop;
390      HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_BLENDOP, blendop);
391      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result);
392   }
393
394   if (blendsrc != m_last_blendsrc)
395   {
396      m_last_blendsrc = blendsrc;
397      HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_SRCBLEND, blendsrc);
398      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result);
399   }
400
401   if (blenddst != m_last_blenddst)
402   {
403      m_last_blenddst = blenddst;
404      HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_DESTBLEND, blenddst);
405      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result);
406   }
407}
408
409void renderer::reset_render_states()
410{
411   // this ensures subsequent calls to the above setters will force-update the data
412   m_last_texture = (texture_info *)~0;
413   m_last_filter = -1;
414   m_last_blendenable = -1;
415   m_last_blendop = -1;
416   m_last_blendsrc = -1;
417   m_last_blenddst = -1;
418   m_last_wrap = (D3DTEXTUREADDRESS)-1;
419}
420
421texture_manager::texture_manager(renderer *d3d)
422{
423   m_renderer = d3d;
424
425   m_texlist = NULL;
426   m_vector_texture = NULL;
427   m_default_texture = NULL;
428
429   // check for dynamic texture support
430   DWORD tempcaps;
431   HRESULT result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_CAPS2, &tempcaps);
432   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
433   m_dynamic_supported = ((tempcaps & D3DCAPS2_DYNAMICTEXTURES) != 0);
434   if (m_dynamic_supported) osd_printf_verbose("Direct3D: Using dynamic textures\n");
435
436   // check for stretchrect support
437   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_STRETCH_RECT_FILTER, &tempcaps);
438   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
439   m_stretch_supported = ((tempcaps & D3DPTFILTERCAPS_MAGFPOINT) != 0);
440   if (m_stretch_supported && video_config.prescale > 1) osd_printf_verbose("Direct3D: Using StretchRect for prescaling\n");
441
442   // get texture caps
443   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_TEXTURE_CAPS, &m_texture_caps);
444   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
445   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_MAX_TEXTURE_ASPECT, &m_texture_max_aspect);
446   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
447   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_MAX_TEXTURE_WIDTH, &m_texture_max_width);
448   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
449   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_MAX_TEXTURE_HEIGHT, &m_texture_max_height);
450   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
451
452   // pick a YUV texture format
453   m_yuv_format = D3DFMT_UYVY;
454   result = (*d3dintf->d3d.check_device_format)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, d3d->get_pixel_format(), 0, D3DRTYPE_TEXTURE, D3DFMT_UYVY);
455   if (result != D3D_OK)
456   {
457      m_yuv_format = D3DFMT_YUY2;
458      result = (*d3dintf->d3d.check_device_format)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, d3d->get_pixel_format(), 0, D3DRTYPE_TEXTURE, D3DFMT_YUY2);
459      if (result != D3D_OK)
460         m_yuv_format = D3DFMT_A8R8G8B8;
461   }
462   osd_printf_verbose("Direct3D: YUV format = %s\n", (m_yuv_format == D3DFMT_YUY2) ? "YUY2" : (m_yuv_format == D3DFMT_UYVY) ? "UYVY" : "RGB");
463
464   // set the max texture size
465   d3d->window().target()->set_max_texture_size(m_texture_max_width, m_texture_max_height);
466   osd_printf_verbose("Direct3D: Max texture size = %dx%d\n", (int)m_texture_max_width, (int)m_texture_max_height);
467}
468
469texture_manager::~texture_manager()
470{
471}
472
473void texture_manager::create_resources()
474{
475   // experimental: load a PNG to use for vector rendering; it is treated
476   // as a brightness map
477   emu_file file(m_renderer->window().machine().options().art_path(), OPEN_FLAG_READ);
478   render_load_png(m_vector_bitmap, file, NULL, "vector.png");
479   if (m_vector_bitmap.valid())
480   {
481      m_vector_bitmap.fill(rgb_t(0xff,0xff,0xff,0xff));
482      render_load_png(m_vector_bitmap, file, NULL, "vector.png", true);
483   }
484
485   m_default_bitmap.allocate(8, 8);
486   m_default_bitmap.fill(rgb_t(0xff,0xff,0xff,0xff));
487
488   if (m_default_bitmap.valid())
489   {
490      render_texinfo texture;
491
492      // fake in the basic data so it looks like it came from render.c
493      texture.base = m_default_bitmap.raw_pixptr(0);
494      texture.rowpixels = m_default_bitmap.rowpixels();
495      texture.width = m_default_bitmap.width();
496      texture.height = m_default_bitmap.height();
497      texture.palette = NULL;
498      texture.seqid = 0;
499
500      // now create it
501      m_default_texture = global_alloc(texture_info(this, &texture, m_renderer->window().prescale(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32)));
502   }
503
504   // experimental: if we have a vector bitmap, create a texture for it
505   if (m_vector_bitmap.valid())
506   {
507      render_texinfo texture;
508
509      // fake in the basic data so it looks like it came from render.c
510      texture.base = &m_vector_bitmap.pix32(0);
511      texture.rowpixels = m_vector_bitmap.rowpixels();
512      texture.width = m_vector_bitmap.width();
513      texture.height = m_vector_bitmap.height();
514      texture.palette = NULL;
515      texture.seqid = 0;
516
517      // now create it
518      m_vector_texture = global_alloc(texture_info(this, &texture, m_renderer->window().prescale(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32)));
519   }
520}
521
522void texture_manager::delete_resources()
523{
524   // is part of m_texlist and will be free'd there
525   //global_free(m_default_texture);
526   m_default_texture = NULL;
527
528   //global_free(m_vector_texture);
529   m_vector_texture = NULL;
530
531   // free all textures
532   while (m_texlist != NULL)
533   {
534      texture_info *tex = m_texlist;
535      m_texlist = tex->get_next();
536      global_free(tex);
537   }
538}
539
540UINT32 texture_manager::texture_compute_hash(const render_texinfo *texture, UINT32 flags)
541{
542   return (FPTR)texture->base ^ (flags & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK));
543}
544
545texture_info *texture_manager::find_texinfo(const render_texinfo *texinfo, UINT32 flags)
546{
547   UINT32 hash = texture_compute_hash(texinfo, flags);
548   texture_info *texture;
549
550   // find a match
551   for (texture = m_renderer->get_texture_manager()->get_texlist(); texture != NULL; texture = texture->get_next())
552   {
553      UINT32 test_screen = (UINT32)texture->get_texinfo().osddata >> 1;
554      UINT32 test_page = (UINT32)texture->get_texinfo().osddata & 1;
555      UINT32 prim_screen = (UINT32)texinfo->osddata >> 1;
556      UINT32 prim_page = (UINT32)texinfo->osddata & 1;
557      if (test_screen != prim_screen || test_page != prim_page)
558      {
559         continue;
560      }
561
562      if (texture->get_hash() == hash &&
563         texture->get_texinfo().base == texinfo->base &&
564         texture->get_texinfo().width == texinfo->width &&
565         texture->get_texinfo().height == texinfo->height &&
566         ((texture->get_flags() ^ flags) & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) == 0)
567      {
568         // Reject a texture if it belongs to an out-of-date render target, so as to cause the HLSL system to re-cache
569         if (m_renderer->get_shaders()->enabled() && texinfo->width != 0 && texinfo->height != 0 && (flags & PRIMFLAG_SCREENTEX_MASK) != 0)
570         {
571            if (m_renderer->get_shaders()->find_render_target(texture) != NULL)
572            {
573               return texture;
574            }
575         }
576         else
577         {
578            return texture;
579         }
580      }
581   }
582
583   // Nothing found, check if we need to unregister something with HLSL
584   if (m_renderer->get_shaders()->enabled())
585   {
586      if (texinfo->width == 0 || texinfo->height == 0)
587      {
588         return NULL;
589      }
590
591      UINT32 prim_screen = texinfo->osddata >> 1;
592      UINT32 prim_page = texinfo->osddata & 1;
593
594      for (texture = m_renderer->get_texture_manager()->get_texlist(); texture != NULL; texture = texture->get_next())
595      {
596         UINT32 test_screen = texture->get_texinfo().osddata >> 1;
597         UINT32 test_page = texture->get_texinfo().osddata & 1;
598         if (test_screen != prim_screen || test_page != prim_page)
599         {
600            continue;
601         }
602
603         // Clear out our old texture reference
604         if (texture->get_hash() == hash &&
605            texture->get_texinfo().base == texinfo->base &&
606            ((texture->get_flags() ^ flags) & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) == 0 &&
607            (texture->get_texinfo().width != texinfo->width ||
608               texture->get_texinfo().height != texinfo->height))
609         {
610            m_renderer->get_shaders()->remove_render_target(texture);
611         }
612      }
613   }
614
615   return NULL;
616}
617
618renderer::renderer(osd_window *window)
619   : osd_renderer(window, FLAG_NONE)
620{
621   m_device = NULL;
622   m_restarting = false;
623   m_shaders = NULL;
624   m_numverts = 0;
625   m_numpolys = 0;
626   m_vertexbuf = NULL;
627   m_lockedbuf = NULL;
628   m_vectorbatch = NULL;
629   m_last_texture = NULL;
630   m_hlsl_buf = NULL;
631   m_texture_manager = NULL;
632}
633
634int renderer::initialize()
635{
636   // configure the adapter for the mode we want
637   if (config_adapter_mode())
638      return false;
639
640   // create the device immediately for the full screen case (defer for window mode)
641   if (window().fullscreen() && device_create(window().m_focus_hwnd))
642      return false;
643
644   return true;
645}
646
647int renderer::pre_window_draw_check()
648{
649   // if we're in the middle of resizing, leave things alone
650   if (window().m_resize_state == RESIZE_STATE_RESIZING)
651      return 0;
652
653   // if we're restarting the renderer, leave things alone
654   if (m_restarting)
655   {
656      m_shaders->toggle();
657
658      // free all existing resources and re-create
659      device_delete_resources();
660      device_create_resources();
661
662      m_restarting = false;
663   }
664
665   // if we have a device, check the cooperative level
666   if (m_device != NULL)
667   {
668      if (device_test_cooperative())
669      {
670         return 1;
671      }
672   }
673
674   // in window mode, we need to track the window size
675   if (!window().fullscreen() || m_device == NULL)
676   {
677      // if the size changes, skip this update since the render target will be out of date
678      if (update_window_size())
679         return 0;
680
681      // if we have no device, after updating the size, return an error so GDI can try
682      if (m_device == NULL)
683         return 1;
684   }
685
686   return -1;
687}
688
689void texture_manager::update_textures()
690{
691   for (render_primitive *prim = m_renderer->window().m_primlist->first(); prim != NULL; prim = prim->next())
692   {
693      if (prim->texture.base != NULL)
694      {
695         texture_info *texture = find_texinfo(&prim->texture, prim->flags);
696         if (texture == NULL)
697         {
698            // if there isn't one, create a new texture
699            global_alloc(texture_info(this, &prim->texture, m_renderer->window().prescale(), prim->flags));
700         }
701         else
702         {
703            // if there is one, but with a different seqid, copy the data
704            if (texture->get_texinfo().seqid != prim->texture.seqid)
705            {
706               texture->set_data(&prim->texture, prim->flags);
707               texture->get_texinfo().seqid = prim->texture.seqid;
708            }
709         }
710      }
711      else if(m_renderer->get_shaders()->vector_enabled() && PRIMFLAG_GET_VECTORBUF(prim->flags))
712      {
713         if (!m_renderer->get_shaders()->get_vector_target())
714         {
715            m_renderer->get_shaders()->create_vector_target(prim);
716         }
717      }
718   }
719}
720
721void renderer::begin_frame()
722{
723   HRESULT result = (*d3dintf->device.clear)(m_device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0);
724   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result);
725
726   m_shaders->begin_frame();
727
728   window().m_primlist->acquire_lock();
729
730   // first update any textures
731   m_texture_manager->update_textures();
732
733   // begin the scene
734   mtlog_add("drawd3d_window_draw: begin_scene");
735   result = (*d3dintf->device.begin_scene)(m_device);
736   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device begin_scene call\n", (int)result);
737
738   m_lockedbuf = NULL;
739
740   if(m_shaders->enabled())
741   {
742      m_hlsl_buf = (void*)mesh_alloc(6);
743      m_shaders->init_fsfx_quad(m_hlsl_buf);
744   }
745
746   m_line_count = 0;
747
748   // loop over primitives
749   for (render_primitive *prim = window().m_primlist->first(); prim != NULL; prim = prim->next())
750      if (prim->type == render_primitive::LINE && PRIMFLAG_GET_VECTOR(prim->flags))
751         m_line_count++;
752}
753
754void renderer::process_primitives()
755{
756   // Rotating index for vector time offsets
757   for (render_primitive *prim = window().m_primlist->first(); prim != NULL; prim = prim->next())
758   {
759      switch (prim->type)
760      {
761         case render_primitive::LINE:
762            if (PRIMFLAG_GET_VECTOR(prim->flags))
763            {
764               if (m_line_count > 0)
765                  batch_vectors();
766               else
767                  continue;
768            }
769            else
770            {
771               draw_line(prim);
772            }
773            break;
774
775         case render_primitive::QUAD:
776            draw_quad(prim);
777            break;
778
779         default:
780            throw emu_fatalerror("Unexpected render_primitive type");
781      }
782   }
783}
784
785void renderer::end_frame()
786{
787   window().m_primlist->release_lock();
788
789   // flush any pending polygons
790   primitive_flush_pending();
791
792   m_shaders->end_frame();
793
794   // finish the scene
795   HRESULT result = (*d3dintf->device.end_scene)(m_device);
796   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device end_scene call\n", (int)result);
797
798   // present the current buffers
799   result = (*d3dintf->device.present)(m_device, NULL, NULL, NULL, NULL, 0);
800   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device present call\n", (int)result);
801}
802
803//============================================================
804//  device_create
805//============================================================
806
807int renderer::device_create(HWND device_hwnd)
808{
809   // if a device exists, free it
810   if (m_device != NULL)
811   {
812      device_delete();
813   }
814
815   // create shader options only once
816   if (m_shaders_options == NULL)
817   {
818      m_shaders_options = (hlsl_options*)global_alloc_clear(hlsl_options);
819   }
820
821   // verify the caps
822   int verify = device_verify_caps();
823   if (verify == 2)
824   {
825      osd_printf_error("Error: Device does not meet minimum requirements for Direct3D rendering\n");
826      return 1;
827   }
828   if (verify == 1)
829   {
830      osd_printf_warning("Warning: Device may not perform well for Direct3D rendering\n");
831   }
832
833   // verify texture formats
834   HRESULT result = (*d3dintf->d3d.check_device_format)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, 0, D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8);
835   if (result != D3D_OK)
836   {
837      osd_printf_error("Error: A8R8G8B8 format textures not supported\n");
838      return 1;
839   }
840
841   m_texture_manager = global_alloc(texture_manager(this));
842
843try_again:
844   // try for XRGB first
845   m_screen_format = D3DFMT_X8R8G8B8;
846   result = (*d3dintf->d3d.check_device_format)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, m_texture_manager->is_dynamic_supported() ? D3DUSAGE_DYNAMIC : 0, D3DRTYPE_TEXTURE, m_screen_format);
847   if (result != D3D_OK)
848   {
849      // if not, try for ARGB
850      m_screen_format = D3DFMT_A8R8G8B8;
851      result = (*d3dintf->d3d.check_device_format)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, m_texture_manager->is_dynamic_supported() ? D3DUSAGE_DYNAMIC : 0, D3DRTYPE_TEXTURE, m_screen_format);
852      if (result != D3D_OK && m_texture_manager->is_dynamic_supported())
853      {
854         m_texture_manager->set_dynamic_supported(FALSE);
855         goto try_again;
856      }
857      if (result != D3D_OK)
858      {
859         osd_printf_error("Error: unable to configure a screen texture format\n");
860         return 1;
861      }
862   }
863
864   // initialize the D3D presentation parameters
865   memset(&m_presentation, 0, sizeof(m_presentation));
866   m_presentation.BackBufferWidth               = m_width;
867   m_presentation.BackBufferHeight              = m_height;
868   m_presentation.BackBufferFormat              = m_pixformat;
869   m_presentation.BackBufferCount               = video_config.triplebuf ? 2 : 1;
870   m_presentation.MultiSampleType               = D3DMULTISAMPLE_NONE;
871   m_presentation.SwapEffect                    = D3DSWAPEFFECT_DISCARD;
872   m_presentation.hDeviceWindow                 = window().m_hwnd;
873   m_presentation.Windowed                      = !window().fullscreen() || window().win_has_menu();
874   m_presentation.EnableAutoDepthStencil        = FALSE;
875   m_presentation.AutoDepthStencilFormat        = D3DFMT_D16;
876   m_presentation.Flags                         = 0;
877   m_presentation.FullScreen_RefreshRateInHz    = m_refresh;
878   m_presentation.PresentationInterval          = ((video_config.triplebuf && window().fullscreen()) ||
879                                       video_config.waitvsync || video_config.syncrefresh) ?
880                                       D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
881
882   // create the D3D device
883   result = (*d3dintf->d3d.create_device)(d3dintf, m_adapter, D3DDEVTYPE_HAL, device_hwnd,
884               D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &m_presentation, &m_device);
885   if (result != D3D_OK)
886   {
887      // if we got a "DEVICELOST" error, it may be transitory; count it and only fail if
888      // we exceed a threshold
889      if (result == D3DERR_DEVICELOST)
890      {
891         m_create_error_count++;
892         if (m_create_error_count < 10)
893         {
894            return 0;
895         }
896      }
897
898      //  fatal error if we just can't do it
899      osd_printf_error("Unable to create the Direct3D device (%08X)\n", (UINT32)result);
900      return 1;
901   }
902   m_create_error_count = 0;
903   osd_printf_verbose("Direct3D: Device created at %dx%d\n", m_width, m_height);
904
905   // set the gamma if we need to
906   if (window().fullscreen())
907   {
908      // only set the gamma if it's not 1.0f
909      windows_options &options = downcast<windows_options &>(window().machine().options());
910      float brightness = options.full_screen_brightness();
911      float contrast = options.full_screen_contrast();
912      float gamma = options.full_screen_gamma();
913      if (brightness != 1.0f || contrast != 1.0f || gamma != 1.0f)
914      {
915         // warn if we can't do it
916         if (!m_gamma_supported)
917         {
918            osd_printf_warning("Direct3D: Warning - device does not support full screen gamma correction.\n");
919         }
920         else
921         {
922            // create a standard ramp and set it
923            D3DGAMMARAMP ramp;
924            for (int i = 0; i < 256; i++)
925            {
926               ramp.red[i] = ramp.green[i] = ramp.blue[i] = apply_brightness_contrast_gamma(i, brightness, contrast, gamma) << 8;
927            }
928            (*d3dintf->device.set_gamma_ramp)(m_device, 0, &ramp);
929         }
930      }
931   }
932
933   int ret = m_shaders->create_resources(false);
934   if (ret != 0)
935      return ret;
936
937   return device_create_resources();
938}
939
940
941//============================================================
942//  device_create_resources
943//============================================================
944
945int renderer::device_create_resources()
946{
947   // allocate a vertex buffer to use
948   HRESULT result = (*d3dintf->device.create_vertex_buffer)(m_device,
949            sizeof(vertex) * VERTEX_BUFFER_SIZE,
950            D3DUSAGE_DYNAMIC | D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_WRITEONLY,
951            VERTEX_BASE_FORMAT | ((m_shaders->enabled() && d3dintf->post_fx_available) ? D3DFVF_XYZW : D3DFVF_XYZRHW),
952            D3DPOOL_DEFAULT, &m_vertexbuf);
953   if (result != D3D_OK)
954   {
955      osd_printf_error("Error creating vertex buffer (%08X)\n", (UINT32)result);
956      return 1;
957   }
958
959   // set the vertex format
960   result = (*d3dintf->device.set_vertex_format)(m_device, (D3DFORMAT)(VERTEX_BASE_FORMAT | ((m_shaders->enabled() &&
961      d3dintf->post_fx_available) ? D3DFVF_XYZW : D3DFVF_XYZRHW)));
962   if (result != D3D_OK)
963   {
964      osd_printf_error("Error setting vertex format (%08X)\n", (UINT32)result);
965      return 1;
966   }
967
968   // set the fixed render state
969   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ZENABLE, D3DZB_FALSE);
970   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_FILLMODE, D3DFILL_SOLID);
971   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_SHADEMODE, D3DSHADE_FLAT);
972   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ZWRITEENABLE, FALSE);
973   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHATESTENABLE, TRUE);
974   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_LASTPIXEL, TRUE);
975   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_CULLMODE, D3DCULL_NONE);
976   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ZFUNC, D3DCMP_LESS);
977   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHAREF, 0);
978   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHAFUNC, D3DCMP_GREATER);
979   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_DITHERENABLE, FALSE);
980   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_FOGENABLE, FALSE);
981   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_SPECULARENABLE, FALSE);
982   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_STENCILENABLE, FALSE);
983   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_WRAP0, FALSE);
984   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_CLIPPING, TRUE);
985   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_LIGHTING, FALSE);
986   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_COLORVERTEX, TRUE);
987
988   result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, D3DTSS_COLOROP, D3DTOP_MODULATE);
989   result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
990   result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, D3DTSS_COLOROP, D3DTOP_MODULATE);
991   result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
992
993   // reset the local states to force updates
994   reset_render_states();
995
996   // clear the buffer
997   result = (*d3dintf->device.clear)(m_device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0);
998   result = (*d3dintf->device.present)(m_device, NULL, NULL, NULL, NULL, 0);
999
1000   m_texture_manager->create_resources();
1001
1002   return 0;
1003}
1004
1005
1006//============================================================
1007//  device_delete
1008//============================================================
1009
1010renderer::~renderer()
1011{
1012   if (m_shaders_options != NULL)
1013   {
1014      global_free(m_shaders_options);
1015   }
1016   m_shaders_options = NULL;
1017
1018   device_delete();
1019}
1020
1021void renderer::device_delete()
1022{
1023   if (m_shaders != NULL)
1024   {
1025      // free our effects
1026      m_shaders->delete_resources(false);
1027
1028      // delete the HLSL interface
1029      global_free(m_shaders);
1030   }
1031
1032   // free our base resources
1033   device_delete_resources();
1034
1035   if (m_texture_manager != NULL)
1036   {
1037      global_free(m_texture_manager);
1038   }
1039   m_texture_manager = NULL;
1040
1041   // free the device itself
1042   if (m_device != NULL)
1043   {
1044      (*d3dintf->device.reset)(m_device, &m_presentation);
1045      (*d3dintf->device.release)(m_device);
1046   }
1047   m_device = NULL;
1048}
1049
1050
1051//============================================================
1052//  device_delete_resources
1053//============================================================
1054
1055void renderer::device_delete_resources()
1056{
1057   if (m_texture_manager != NULL)
1058      m_texture_manager->delete_resources();
1059   // free the vertex buffer
1060   if (m_vertexbuf != NULL)
1061      (*d3dintf->vertexbuf.release)(m_vertexbuf);
1062   m_vertexbuf = NULL;
1063}
1064
1065
1066//============================================================
1067//  device_verify_caps
1068//============================================================
1069
1070int renderer::device_verify_caps()
1071{
1072   int retval = 0;
1073
1074   m_shaders = (shaders*)global_alloc_clear(shaders);
1075   m_shaders->init(d3dintf, &window().machine(), this);
1076
1077   DWORD tempcaps;
1078   HRESULT result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_MAX_PS30_INSN_SLOTS, &tempcaps);
1079   if (result != D3D_OK) osd_printf_verbose("Direct3D Error %08X during get_caps_dword call\n", (int)result);
1080   if (tempcaps < 512)
1081   {
1082      osd_printf_verbose("Direct3D: Warning - Device does not support Pixel Shader 3.0, falling back to non-PS rendering\n");
1083      d3dintf->post_fx_available = false;
1084   }
1085
1086   // verify presentation capabilities
1087   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_PRESENTATION_INTERVALS, &tempcaps);
1088   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
1089   if (!(tempcaps & D3DPRESENT_INTERVAL_IMMEDIATE))
1090   {
1091      osd_printf_verbose("Direct3D: Error - Device does not support immediate presentations\n");
1092      retval = 2;
1093   }
1094   if (!(tempcaps & D3DPRESENT_INTERVAL_ONE))
1095   {
1096      osd_printf_verbose("Direct3D: Error - Device does not support per-refresh presentations\n");
1097      retval = 2;
1098   }
1099
1100   // verify device capabilities
1101   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_DEV_CAPS, &tempcaps);
1102   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
1103   if (!(tempcaps & D3DDEVCAPS_CANRENDERAFTERFLIP))
1104   {
1105      osd_printf_verbose("Direct3D: Warning - Device does not support queued rendering after a page flip\n");
1106      retval = 1;
1107   }
1108   if (!(tempcaps & D3DDEVCAPS_HWRASTERIZATION))
1109   {
1110      osd_printf_verbose("Direct3D: Warning - Device does not support hardware rasterization\n");
1111      retval = 1;
1112   }
1113
1114   // verify texture operation capabilities
1115   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_TEXTURE_OP_CAPS, &tempcaps);
1116   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
1117   if (!(tempcaps & D3DTEXOPCAPS_MODULATE))
1118   {
1119      osd_printf_verbose("Direct3D: Warning - Device does not support texture modulation\n");
1120      retval = 1;
1121   }
1122
1123   // set a simpler flag to indicate mod2x and mod4x texture modes
1124   m_mod2x_supported = ((tempcaps & D3DTEXOPCAPS_MODULATE2X) != 0);
1125   m_mod4x_supported = ((tempcaps & D3DTEXOPCAPS_MODULATE4X) != 0);
1126
1127   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_CAPS2, &tempcaps);
1128   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
1129   m_gamma_supported = ((tempcaps & D3DCAPS2_FULLSCREENGAMMA) != 0);
1130
1131   return retval;
1132}
1133
1134
1135//============================================================
1136//  device_test_cooperative
1137//============================================================
1138
1139int renderer::device_test_cooperative()
1140{
1141   // check our current status; if we lost the device, punt to GDI
1142   HRESULT result = (*d3dintf->device.test_cooperative_level)(m_device);
1143   if (result == D3DERR_DEVICELOST)
1144      return 1;
1145
1146   // if we're able to reset ourselves, try it
1147   if (result == D3DERR_DEVICENOTRESET)
1148   {
1149      osd_printf_verbose("Direct3D: resetting device\n");
1150
1151      // free all existing resources and call reset on the device
1152      //device_delete();
1153      device_delete_resources();
1154      m_shaders->delete_resources(true);
1155      result = (*d3dintf->device.reset)(m_device, &m_presentation);
1156
1157      // if it didn't work, punt to GDI
1158      if (result != D3D_OK)
1159      {
1160         osd_printf_error("Unable to reset, result %08x\n", (UINT32)result);
1161         return 1;
1162      }
1163
1164      // try to create the resources again; if that didn't work, delete the whole thing
1165      if (device_create_resources())
1166      {
1167         osd_printf_verbose("Direct3D: failed to recreate resources for device; failing permanently\n");
1168         device_delete();
1169         return 1;
1170      }
1171
1172      if (m_shaders->create_resources(true))
1173      {
1174         osd_printf_verbose("Direct3D: failed to recreate HLSL resources for device; failing permanently\n");
1175         device_delete();
1176         return 1;
1177      }
1178   }
1179   return 0;
1180}
1181
1182
1183//============================================================
1184//  config_adapter_mode
1185//============================================================
1186
1187int renderer::config_adapter_mode()
1188{
1189   adapter_identifier identifier;
1190
1191   // choose the monitor number
1192   m_adapter = get_adapter_for_monitor();
1193
1194   // get the identifier
1195   HRESULT result = (*d3dintf->d3d.get_adapter_identifier)(d3dintf, m_adapter, 0, &identifier);
1196   if (result != D3D_OK)
1197   {
1198      osd_printf_error("Error getting identifier for adapter #%d\n", m_adapter);
1199      return 1;
1200   }
1201   osd_printf_verbose("Direct3D: Configuring adapter #%d = %s\n", m_adapter, identifier.Description);
1202
1203   // get the current display mode
1204   result = (*d3dintf->d3d.get_adapter_display_mode)(d3dintf, m_adapter, &m_origmode);
1205   if (result != D3D_OK)
1206   {
1207      osd_printf_error("Error getting mode for adapter #%d\n", m_adapter);
1208      return 1;
1209   }
1210
1211   // choose a resolution: window mode case
1212   if (!window().fullscreen() || !video_config.switchres || window().win_has_menu())
1213   {
1214      RECT client;
1215
1216      // bounds are from the window client rect
1217      GetClientRectExceptMenu(window().m_hwnd, &client, window().fullscreen());
1218      m_width = client.right - client.left;
1219      m_height = client.bottom - client.top;
1220
1221      // pix format is from the current mode
1222      m_pixformat = m_origmode.Format;
1223      m_refresh = 0;
1224
1225      // make sure it's a pixel format we can get behind
1226      if (m_pixformat != D3DFMT_X1R5G5B5 && m_pixformat != D3DFMT_R5G6B5 && m_pixformat != D3DFMT_X8R8G8B8)
1227      {
1228         osd_printf_error("Device %s currently in an unsupported mode\n", window().monitor()->devicename());
1229         return 1;
1230      }
1231   }
1232
1233   // choose a resolution: full screen mode case
1234   else
1235   {
1236      // default to the current mode exactly
1237      m_width = m_origmode.Width;
1238      m_height = m_origmode.Height;
1239      m_pixformat = m_origmode.Format;
1240      m_refresh = m_origmode.RefreshRate;
1241
1242      // if we're allowed to switch resolutions, override with something better
1243      if (video_config.switchres)
1244         pick_best_mode();
1245   }
1246
1247   // see if we can handle the device type
1248   result = (*d3dintf->d3d.check_device_type)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, m_pixformat, !window().fullscreen());
1249   if (result != D3D_OK)
1250   {
1251      osd_printf_error("Proposed video mode not supported on device %s\n", window().monitor()->devicename());
1252      return 1;
1253   }
1254   return 0;
1255}
1256
1257
1258//============================================================
1259//  get_adapter_for_monitor
1260//============================================================
1261
1262int renderer::get_adapter_for_monitor()
1263{
1264   int maxadapter = (*d3dintf->d3d.get_adapter_count)(d3dintf);
1265
1266   // iterate over adapters until we error or find a match
1267   for (int adapternum = 0; adapternum < maxadapter; adapternum++)
1268   {
1269      // get the monitor for this adapter
1270      HMONITOR curmonitor = (*d3dintf->d3d.get_adapter_monitor)(d3dintf, adapternum);
1271
1272      // if we match the proposed monitor, this is it
1273      if (curmonitor == *((HMONITOR *)window().monitor()->oshandle()))
1274      {
1275         return adapternum;
1276      }
1277   }
1278
1279   // default to the default
1280   return D3DADAPTER_DEFAULT;
1281}
1282
1283
1284//============================================================
1285//  pick_best_mode
1286//============================================================
1287
1288void renderer::pick_best_mode()
1289{
1290   double target_refresh = 60.0;
1291   INT32 minwidth, minheight;
1292   float best_score = 0.0f;
1293
1294   // determine the refresh rate of the primary screen
1295   const screen_device *primary_screen = window().machine().config().first_screen();
1296   if (primary_screen != NULL)
1297   {
1298      target_refresh = ATTOSECONDS_TO_HZ(primary_screen->refresh_attoseconds());
1299   }
1300
1301   // determine the minimum width/height for the selected target
1302   // note: technically we should not be calling this from an alternate window
1303   // thread; however, it is only done during init time, and the init code on
1304   // the main thread is waiting for us to finish, so it is safe to do so here
1305   window().target()->compute_minimum_size(minwidth, minheight);
1306
1307   // use those as the target for now
1308   INT32 target_width = minwidth;
1309   INT32 target_height = minheight;
1310
1311   // determine the maximum number of modes
1312   int maxmodes = (*d3dintf->d3d.get_adapter_mode_count)(d3dintf, m_adapter, D3DFMT_X8R8G8B8);
1313
1314   // enumerate all the video modes and find the best match
1315   osd_printf_verbose("Direct3D: Selecting video mode...\n");
1316   for (int modenum = 0; modenum < maxmodes; modenum++)
1317   {
1318      // check this mode
1319      D3DDISPLAYMODE mode;
1320      HRESULT result = (*d3dintf->d3d.enum_adapter_modes)(d3dintf, m_adapter, D3DFMT_X8R8G8B8, modenum, &mode);
1321      if (result != D3D_OK)
1322         break;
1323
1324      // skip non-32 bit modes
1325      if (mode.Format != D3DFMT_X8R8G8B8)
1326         continue;
1327
1328      // compute initial score based on difference between target and current
1329      float size_score = 1.0f / (1.0f + fabs((float)(mode.Width - target_width)) + fabs((float)(mode.Height - target_height)));
1330
1331      // if the mode is too small, give a big penalty
1332      if (mode.Width < minwidth || mode.Height < minheight)
1333         size_score *= 0.01f;
1334
1335      // if mode is smaller than we'd like, it only scores up to 0.1
1336      if (mode.Width < target_width || mode.Height < target_height)
1337         size_score *= 0.1f;
1338
1339      // if we're looking for a particular mode, that's a winner
1340      if (mode.Width == window().m_win_config.width && mode.Height == window().m_win_config.height)
1341         size_score = 2.0f;
1342
1343      // compute refresh score
1344      float refresh_score = 1.0f / (1.0f + fabs((double)mode.RefreshRate - target_refresh));
1345
1346      // if refresh is smaller than we'd like, it only scores up to 0.1
1347      if ((double)mode.RefreshRate < target_refresh)
1348         refresh_score *= 0.1f;
1349
1350      // if we're looking for a particular refresh, make sure it matches
1351      if (mode.RefreshRate == window().m_win_config.refresh)
1352         refresh_score = 2.0f;
1353
1354      // weight size and refresh equally
1355      float final_score = size_score + refresh_score;
1356
1357      // best so far?
1358      osd_printf_verbose("  %4dx%4d@%3dHz -> %f\n", mode.Width, mode.Height, mode.RefreshRate, final_score * 1000.0f);
1359      if (final_score > best_score)
1360      {
1361         best_score = final_score;
1362         m_width = mode.Width;
1363         m_height = mode.Height;
1364         m_pixformat = mode.Format;
1365         m_refresh = mode.RefreshRate;
1366      }
1367   }
1368   osd_printf_verbose("Direct3D: Mode selected = %4dx%4d@%3dHz\n", m_width, m_height, m_refresh);
1369}
1370
1371
1372//============================================================
1373//  update_window_size
1374//============================================================
1375
1376int renderer::update_window_size()
1377{
1378   // get the current window bounds
1379   RECT client;
1380   GetClientRectExceptMenu(window().m_hwnd, &client, window().fullscreen());
1381
1382   // if we have a device and matching width/height, nothing to do
1383   if (m_device != NULL && rect_width(&client) == m_width && rect_height(&client) == m_height)
1384   {
1385      // clear out any pending resizing if the area didn't change
1386      if (window().m_resize_state == RESIZE_STATE_PENDING)
1387         window().m_resize_state = RESIZE_STATE_NORMAL;
1388      return FALSE;
1389   }
1390
1391   // if we're in the middle of resizing, leave it alone as well
1392   if (window().m_resize_state == RESIZE_STATE_RESIZING)
1393      return FALSE;
1394
1395   // set the new bounds and create the device again
1396   m_width = rect_width(&client);
1397   m_height = rect_height(&client);
1398   if (device_create(window().m_focus_hwnd))
1399      return FALSE;
1400
1401   // reset the resize state to normal, and indicate we made a change
1402   window().m_resize_state = RESIZE_STATE_NORMAL;
1403   return TRUE;
1404}
1405
1406
1407//============================================================
1408//  batch_vectors
1409//============================================================
1410
1411void renderer::batch_vectors()
1412{
1413   windows_options &options = downcast<windows_options &>(window().machine().options());
1414
1415   int vector_size = (options.antialias() ? 24 : 6);
1416   m_vectorbatch = mesh_alloc(m_line_count * vector_size);
1417   m_batchindex = 0;
1418
1419   static int start_index = 0;
1420   int line_index = 0;
1421   float period = options.screen_vector_time_period();
1422   UINT32 cached_flags = 0;
1423   for (render_primitive *prim = window().m_primlist->first(); prim != NULL; prim = prim->next())
1424   {
1425      switch (prim->type)
1426      {
1427         case render_primitive::LINE:
1428            if (PRIMFLAG_GET_VECTOR(prim->flags))
1429            {
1430               if (period == 0.0f || m_line_count == 0)
1431               {
1432                  batch_vector(prim, 1.0f);
1433               }
1434               else
1435               {
1436                  batch_vector(prim, (float)(start_index + line_index) / ((float)m_line_count * period));
1437                  line_index++;
1438               }
1439               cached_flags = prim->flags;
1440            }
1441            break;
1442
1443         default:
1444            // Skip
1445            break;
1446      }
1447   }
1448
1449   // now add a polygon entry
1450   m_poly[m_numpolys].init(D3DPT_TRIANGLELIST, m_line_count * (options.antialias() ? 8 : 2), vector_size * m_line_count, cached_flags,
1451      m_texture_manager->get_vector_texture(), D3DTOP_MODULATE, 0.0f, 1.0f, 0.0f, 0.0f);
1452   m_numpolys++;
1453
1454   start_index += (int)((float)line_index * period);
1455   if (m_line_count > 0)
1456   {
1457      start_index %= m_line_count;
1458   }
1459
1460   m_line_count = 0;
1461}
1462
1463void renderer::batch_vector(const render_primitive *prim, float line_time)
1464{
1465   // compute the effective width based on the direction of the line
1466   float effwidth = prim->width;
1467   if (effwidth < 0.5f)
1468   {
1469      effwidth = 0.5f;
1470   }
1471
1472   // determine the bounds of a quad to draw this line
1473   render_bounds b0, b1;
1474   render_line_to_quad(&prim->bounds, effwidth, &b0, &b1);
1475
1476   // iterate over AA steps
1477   for (const line_aa_step *step = PRIMFLAG_GET_ANTIALIAS(prim->flags) ? line_aa_4step : line_aa_1step;
1478      step->weight != 0; step++)
1479   {
1480      // get a pointer to the vertex buffer
1481      if (m_vectorbatch == NULL)
1482         return;
1483
1484      m_vectorbatch[m_batchindex + 0].x = b0.x0 + step->xoffs;
1485      m_vectorbatch[m_batchindex + 0].y = b0.y0 + step->yoffs;
1486      m_vectorbatch[m_batchindex + 1].x = b0.x1 + step->xoffs;
1487      m_vectorbatch[m_batchindex + 1].y = b0.y1 + step->yoffs;
1488      m_vectorbatch[m_batchindex + 2].x = b1.x0 + step->xoffs;
1489      m_vectorbatch[m_batchindex + 2].y = b1.y0 + step->yoffs;
1490
1491      m_vectorbatch[m_batchindex + 3].x = b0.x1 + step->xoffs;
1492      m_vectorbatch[m_batchindex + 3].y = b0.y1 + step->yoffs;
1493      m_vectorbatch[m_batchindex + 4].x = b1.x0 + step->xoffs;
1494      m_vectorbatch[m_batchindex + 4].y = b1.y0 + step->yoffs;
1495      m_vectorbatch[m_batchindex + 5].x = b1.x1 + step->xoffs;
1496      m_vectorbatch[m_batchindex + 5].y = b1.y1 + step->yoffs;
1497
1498      float dx = b1.x1 - b0.x1;
1499      float dy = b1.y1 - b0.y1;
1500      float line_length = sqrtf(dx * dx + dy * dy);
1501
1502      // determine the color of the line
1503      INT32 r = (INT32)(prim->color.r * step->weight * 255.0f);
1504      INT32 g = (INT32)(prim->color.g * step->weight * 255.0f);
1505      INT32 b = (INT32)(prim->color.b * step->weight * 255.0f);
1506      INT32 a = (INT32)(prim->color.a * 255.0f);
1507      if (r > 255 || g > 255 || b > 255)
1508      {
1509         if (r > 2*255 || g > 2*255 || b > 2*255)
1510         {
1511            r >>= 2; g >>= 2; b >>= 2;
1512         }
1513         else
1514         {
1515            r >>= 1; g >>= 1; b >>= 1;
1516         }
1517      }
1518      if (r > 255) r = 255;
1519      if (g > 255) g = 255;
1520      if (b > 255) b = 255;
1521      if (a > 255) a = 255;
1522      DWORD color = D3DCOLOR_ARGB(a, r, g, b);
1523
1524      vec2f& start = (get_vector_texture() ? get_vector_texture()->get_uvstart() : get_default_texture()->get_uvstart());
1525      vec2f& stop = (get_vector_texture() ? get_vector_texture()->get_uvstop() : get_default_texture()->get_uvstop());
1526
1527      m_vectorbatch[m_batchindex + 0].u0 = start.c.x;
1528      m_vectorbatch[m_batchindex + 0].v0 = start.c.y;
1529      m_vectorbatch[m_batchindex + 1].u0 = start.c.x;
1530      m_vectorbatch[m_batchindex + 1].v0 = stop.c.y;
1531      m_vectorbatch[m_batchindex + 2].u0 = stop.c.x;
1532      m_vectorbatch[m_batchindex + 2].v0 = start.c.y;
1533
1534      m_vectorbatch[m_batchindex + 3].u0 = start.c.x;
1535      m_vectorbatch[m_batchindex + 3].v0 = stop.c.y;
1536      m_vectorbatch[m_batchindex + 4].u0 = stop.c.x;
1537      m_vectorbatch[m_batchindex + 4].v0 = start.c.y;
1538      m_vectorbatch[m_batchindex + 5].u0 = stop.c.x;
1539      m_vectorbatch[m_batchindex + 5].v0 = stop.c.y;
1540
1541      m_vectorbatch[m_batchindex + 0].u1 = line_length;
1542      m_vectorbatch[m_batchindex + 1].u1 = line_length;
1543      m_vectorbatch[m_batchindex + 2].u1 = line_length;
1544      m_vectorbatch[m_batchindex + 3].u1 = line_length;
1545      m_vectorbatch[m_batchindex + 4].u1 = line_length;
1546      m_vectorbatch[m_batchindex + 5].u1 = line_length;
1547
1548      // set the color, Z parameters to standard values
1549      for (int i = 0; i < 6; i++)
1550      {
1551         m_vectorbatch[m_batchindex + i].z = 0.0f;
1552         m_vectorbatch[m_batchindex + i].rhw = 1.0f;
1553         m_vectorbatch[m_batchindex + i].color = color;
1554      }
1555
1556      m_batchindex += 6;
1557   }
1558}
1559
1560
1561//============================================================
1562//  draw_line
1563//============================================================
1564
1565void renderer::draw_line(const render_primitive *prim)
1566{
1567   // compute the effective width based on the direction of the line
1568   float effwidth = prim->width;
1569   if (effwidth < 0.5f)
1570   {
1571      effwidth = 0.5f;
1572   }
1573
1574   // determine the bounds of a quad to draw this line
1575   render_bounds b0, b1;
1576   render_line_to_quad(&prim->bounds, effwidth, &b0, &b1);
1577
1578   // iterate over AA steps
1579   for (const line_aa_step *step = PRIMFLAG_GET_ANTIALIAS(prim->flags) ? line_aa_4step : line_aa_1step;
1580      step->weight != 0; step++)
1581   {
1582      // get a pointer to the vertex buffer
1583      vertex *vertex = mesh_alloc(4);
1584      if (vertex == NULL)
1585         return;
1586
1587      // rotate the unit vector by 135 degrees and add to point 0
1588      vertex[0].x = b0.x0 + step->xoffs;
1589      vertex[0].y = b0.y0 + step->yoffs;
1590
1591      // rotate the unit vector by -135 degrees and add to point 0
1592      vertex[1].x = b0.x1 + step->xoffs;
1593      vertex[1].y = b0.y1 + step->yoffs;
1594
1595      // rotate the unit vector by 45 degrees and add to point 1
1596      vertex[2].x = b1.x0 + step->xoffs;
1597      vertex[2].y = b1.y0 + step->yoffs;
1598
1599      // rotate the unit vector by -45 degrees and add to point 1
1600      vertex[3].x = b1.x1 + step->xoffs;
1601      vertex[3].y = b1.y1 + step->yoffs;
1602
1603      // determine the color of the line
1604      INT32 r = (INT32)(prim->color.r * step->weight * 255.0f);
1605      INT32 g = (INT32)(prim->color.g * step->weight * 255.0f);
1606      INT32 b = (INT32)(prim->color.b * step->weight * 255.0f);
1607      INT32 a = (INT32)(prim->color.a * 255.0f);
1608      if (r > 255) r = 255;
1609      if (g > 255) g = 255;
1610      if (b > 255) b = 255;
1611      if (a > 255) a = 255;
1612      DWORD color = D3DCOLOR_ARGB(a, r, g, b);
1613
1614      vec2f& start = (get_vector_texture() ? get_vector_texture()->get_uvstart() : get_default_texture()->get_uvstart());
1615      vec2f& stop = (get_vector_texture() ? get_vector_texture()->get_uvstop() : get_default_texture()->get_uvstop());
1616
1617      vertex[0].u0 = start.c.x;
1618      vertex[0].v0 = start.c.y;
1619
1620      vertex[2].u0 = stop.c.x;
1621      vertex[2].v0 = start.c.y;
1622
1623      vertex[1].u0 = start.c.x;
1624      vertex[1].v0 = stop.c.y;
1625
1626      vertex[3].u0 = stop.c.x;
1627      vertex[3].v0 = stop.c.y;
1628
1629      // set the color, Z parameters to standard values
1630      for (int i = 0; i < 4; i++)
1631      {
1632         vertex[i].z = 0.0f;
1633         vertex[i].rhw = 1.0f;
1634         vertex[i].color = color;
1635      }
1636
1637      // now add a polygon entry
1638      m_poly[m_numpolys].init(D3DPT_TRIANGLESTRIP, 2, 4, prim->flags, get_vector_texture(),
1639                        D3DTOP_MODULATE, 0.0f, 1.0f, 0.0f, 0.0f);
1640      m_numpolys++;
1641   }
1642}
1643
1644
1645//============================================================
1646//  draw_quad
1647//============================================================
1648
1649void renderer::draw_quad(const render_primitive *prim)
1650{
1651   texture_info *texture = m_texture_manager->find_texinfo(&prim->texture, prim->flags);
1652
1653   if (texture == NULL)
1654   {
1655      texture = get_default_texture();
1656   }
1657
1658   // get a pointer to the vertex buffer
1659   vertex *vertex = mesh_alloc(4);
1660   if (vertex == NULL)
1661      return;
1662
1663   // fill in the vertexes clockwise
1664   vertex[0].x = prim->bounds.x0;
1665   vertex[0].y = prim->bounds.y0;
1666   vertex[1].x = prim->bounds.x1;
1667   vertex[1].y = prim->bounds.y0;
1668   vertex[2].x = prim->bounds.x0;
1669   vertex[2].y = prim->bounds.y1;
1670   vertex[3].x = prim->bounds.x1;
1671   vertex[3].y = prim->bounds.y1;
1672   float width = prim->bounds.x1 - prim->bounds.x0;
1673   float height = prim->bounds.y1 - prim->bounds.y0;
1674
1675   // set the texture coordinates
1676   if(texture != NULL)
1677   {
1678      vec2f& start = texture->get_uvstart();
1679      vec2f& stop = texture->get_uvstop();
1680      vec2f delta = stop - start;
1681      vertex[0].u0 = start.c.x + delta.c.x * prim->texcoords.tl.u;
1682      vertex[0].v0 = start.c.y + delta.c.y * prim->texcoords.tl.v;
1683      vertex[1].u0 = start.c.x + delta.c.x * prim->texcoords.tr.u;
1684      vertex[1].v0 = start.c.y + delta.c.y * prim->texcoords.tr.v;
1685      vertex[2].u0 = start.c.x + delta.c.x * prim->texcoords.bl.u;
1686      vertex[2].v0 = start.c.y + delta.c.y * prim->texcoords.bl.v;
1687      vertex[3].u0 = start.c.x + delta.c.x * prim->texcoords.br.u;
1688      vertex[3].v0 = start.c.y + delta.c.y * prim->texcoords.br.v;
1689   }
1690
1691   // determine the color, allowing for over modulation
1692   INT32 r = (INT32)(prim->color.r * 255.0f);
1693   INT32 g = (INT32)(prim->color.g * 255.0f);
1694   INT32 b = (INT32)(prim->color.b * 255.0f);
1695   INT32 a = (INT32)(prim->color.a * 255.0f);
1696   DWORD modmode = D3DTOP_MODULATE;
1697   if (texture != NULL)
1698   {
1699      if (m_mod2x_supported && (r > 255 || g > 255 || b > 255))
1700      {
1701         if (m_mod4x_supported && (r > 2*255 || g > 2*255 || b > 2*255))
1702         {
1703            r >>= 2; g >>= 2; b >>= 2;
1704            modmode = D3DTOP_MODULATE4X;
1705         }
1706         else
1707         {
1708            r >>= 1; g >>= 1; b >>= 1;
1709            modmode = D3DTOP_MODULATE2X;
1710         }
1711      }
1712   }
1713   if (r > 255) r = 255;
1714   if (g > 255) g = 255;
1715   if (b > 255) b = 255;
1716   if (a > 255) a = 255;
1717   DWORD color = D3DCOLOR_ARGB(a, r, g, b);
1718
1719   // adjust half pixel X/Y offset, set the color, Z parameters to standard values
1720   for (int i = 0; i < 4; i++)
1721   {
1722      vertex[i].x -= 0.5f;
1723      vertex[i].y -= 0.5f;
1724      vertex[i].z = 0.0f;
1725      vertex[i].rhw = 1.0f;
1726      vertex[i].color = color;
1727   }
1728
1729   // now add a polygon entry
1730   m_poly[m_numpolys].init(D3DPT_TRIANGLESTRIP, 2, 4, prim->flags, texture, modmode, width, height);
1731   m_numpolys++;
1732}
1733
1734void poly_info::init(D3DPRIMITIVETYPE type, UINT32 count, UINT32 numverts,
1735                     UINT32 flags, texture_info *texture, UINT32 modmode,
1736                     float line_time, float line_length,
1737                     float prim_width, float prim_height)
1738{
1739   init(type, count, numverts, flags, texture, modmode, prim_width, prim_height);
1740   m_line_time = line_time;
1741   m_line_length = line_length;
1742}
1743
1744void poly_info::init(D3DPRIMITIVETYPE type, UINT32 count, UINT32 numverts,
1745                     UINT32 flags, texture_info *texture, UINT32 modmode,
1746                     float prim_width, float prim_height)
1747{
1748   m_type = type;
1749   m_count = count;
1750   m_numverts = numverts;
1751   m_flags = flags;
1752   m_texture = texture;
1753   m_modmode = modmode;
1754   m_prim_width = prim_width;
1755   m_prim_height = prim_height;
1756}
1757
1758
1759//============================================================
1760//  primitive_alloc
1761//============================================================
1762
1763vertex *renderer::mesh_alloc(int numverts)
1764{
1765   HRESULT result;
1766
1767   // if we're going to overflow, flush
1768   if (m_lockedbuf != NULL && m_numverts + numverts >= VERTEX_BUFFER_SIZE)
1769   {
1770      primitive_flush_pending();
1771
1772      if(m_shaders->enabled())
1773      {
1774         m_hlsl_buf = (void*)mesh_alloc(6);
1775         m_shaders->init_fsfx_quad(m_hlsl_buf);
1776      }
1777   }
1778
1779   // if we don't have a lock, grab it now
1780   if (m_lockedbuf == NULL)
1781   {
1782      result = (*d3dintf->vertexbuf.lock)(m_vertexbuf, 0, 0, (VOID **)&m_lockedbuf, D3DLOCK_DISCARD);
1783      if (result != D3D_OK)
1784         return NULL;
1785   }
1786
1787   // if we already have the lock and enough room, just return a pointer
1788   if (m_lockedbuf != NULL && m_numverts + numverts < VERTEX_BUFFER_SIZE)
1789   {
1790      int oldverts = m_numverts;
1791      m_numverts += numverts;
1792      return &m_lockedbuf[oldverts];
1793   }
1794   return NULL;
1795}
1796
1797
1798//============================================================
1799//  primitive_flush_pending
1800//============================================================
1801
1802void renderer::primitive_flush_pending()
1803{
1804   // ignore if we're not locked
1805   if (m_lockedbuf == NULL)
1806   {
1807      return;
1808   }
1809
1810   // unlock the buffer
1811   HRESULT result = (*d3dintf->vertexbuf.unlock)(m_vertexbuf);
1812   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during vertex buffer unlock call\n", (int)result);
1813   m_lockedbuf = NULL;
1814
1815   // set the stream
1816   result = (*d3dintf->device.set_stream_source)(m_device, 0, m_vertexbuf, sizeof(vertex));
1817   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_stream_source call\n", (int)result);
1818
1819   m_shaders->begin_draw();
1820
1821   int vertnum = 0;
1822   if (m_shaders->enabled())
1823   {
1824      vertnum = 6;
1825   }
1826
1827   // now do the polys
1828   for (int polynum = 0; polynum < m_numpolys; polynum++)
1829   {
1830      UINT32 flags = m_poly[polynum].get_flags();
1831      texture_info *texture = m_poly[polynum].get_texture();
1832      int newfilter;
1833
1834      // set the texture if different
1835      set_texture(texture);
1836
1837      // set filtering if different
1838      if (texture != NULL)
1839      {
1840         newfilter = FALSE;
1841         if (PRIMFLAG_GET_SCREENTEX(flags))
1842            newfilter = video_config.filter;
1843         set_filter(newfilter);
1844         set_wrap(PRIMFLAG_GET_TEXWRAP(flags) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP);
1845         set_modmode(m_poly[polynum].get_modmode());
1846
1847         m_shaders->init_effect_info(&m_poly[polynum]);
1848      }
1849
1850      // set the blendmode if different
1851      set_blendmode(PRIMFLAG_GET_BLENDMODE(flags));
1852
1853      if (vertnum + m_poly[polynum].get_vertcount() > m_numverts)
1854      {
1855         osd_printf_error("Error: vertnum (%d) plus poly vertex count (%d) > %d\n", vertnum, m_poly[polynum].get_vertcount(), m_numverts);
1856         fflush(stdout);
1857      }
1858
1859      assert(vertnum + m_poly[polynum].get_vertcount() <= m_numverts);
1860
1861      if(m_shaders->enabled() && d3dintf->post_fx_available)
1862      {
1863         m_shaders->render_quad(&m_poly[polynum], vertnum);
1864      }
1865      else
1866      {
1867         // add the primitives
1868         result = (*d3dintf->device.draw_primitive)(m_device, m_poly[polynum].get_type(), vertnum,
1869                                          m_poly[polynum].get_count());
1870         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result);
1871      }
1872
1873      vertnum += m_poly[polynum].get_vertcount();
1874   }
1875
1876   m_shaders->end_draw();
1877
1878   // reset the vertex count
1879   m_numverts = 0;
1880   m_numpolys = 0;
1881}
1882
1883
1884//============================================================
1885//  texture_info destructor
1886//============================================================
1887
1888texture_info::~texture_info()
1889{
1890   if (m_d3dfinaltex != NULL)
1891   {
1892      if (m_d3dtex == m_d3dfinaltex)
1893      {
1894         m_d3dtex = NULL;
1895      }
1896      (*d3dintf->texture.release)(m_d3dfinaltex);
1897      m_d3dfinaltex = NULL;
1898   }
1899   if (m_d3dtex != NULL)
1900   {
1901      (*d3dintf->texture.release)(m_d3dtex);
1902      m_d3dtex = NULL;
1903   }
1904   if (m_d3dsurface != NULL)
1905   {
1906      (*d3dintf->surface.release)(m_d3dsurface);
1907      m_d3dsurface = NULL;
1908   }
1909}
1910
1911
1912//============================================================
1913//  texture_info constructor
1914//============================================================
1915
1916texture_info::texture_info(texture_manager *manager, const render_texinfo* texsource, int prescale, UINT32 flags)
1917{
1918   HRESULT result;
1919
1920   // fill in the core data
1921   m_texture_manager = manager;
1922   m_renderer = m_texture_manager->get_d3d();
1923   m_hash = m_texture_manager->texture_compute_hash(texsource, flags);
1924   m_flags = flags;
1925   m_texinfo = *texsource;
1926   m_xprescale = prescale;
1927   m_yprescale = prescale;
1928
1929   m_d3dtex = NULL;
1930   m_d3dsurface = NULL;
1931   m_d3dfinaltex = NULL;
1932
1933   // compute the size
1934   compute_size(texsource->width, texsource->height);
1935
1936   // non-screen textures are easy
1937   if (!PRIMFLAG_GET_SCREENTEX(flags))
1938   {
1939      assert(PRIMFLAG_TEXFORMAT(flags) != TEXFORMAT_YUY16);
1940      result = (*d3dintf->device.create_texture)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_d3dtex);
1941      if (result != D3D_OK)
1942         goto error;
1943      m_d3dfinaltex = m_d3dtex;
1944      m_type = TEXTURE_TYPE_PLAIN;
1945   }
1946
1947   // screen textures are allocated differently
1948   else
1949   {
1950      D3DFORMAT format;
1951      DWORD usage = m_texture_manager->is_dynamic_supported() ? D3DUSAGE_DYNAMIC : 0;
1952      D3DPOOL pool = m_texture_manager->is_dynamic_supported() ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
1953      int maxdim = MAX(m_renderer->get_presentation()->BackBufferWidth, m_renderer->get_presentation()->BackBufferHeight);
1954
1955      // pick the format
1956      if (PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_YUY16)
1957      {
1958         format = m_texture_manager->get_yuv_format();
1959      }
1960      else if (PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_ARGB32 || PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_PALETTEA16)
1961      {
1962         format = D3DFMT_A8R8G8B8;
1963      }
1964      else
1965      {
1966         format = m_renderer->get_screen_format();
1967      }
1968
1969      // don't prescale above screen size
1970      while (m_xprescale > 1 && m_rawdims.c.x * m_xprescale >= 2 * maxdim)
1971      {
1972         m_xprescale--;
1973      }
1974      while (m_xprescale > 1 && m_rawdims.c.x * m_xprescale > manager->get_max_texture_width())
1975      {
1976         m_xprescale--;
1977      }
1978      while (m_yprescale > 1 && m_rawdims.c.y * m_yprescale >= 2 * maxdim)
1979      {
1980         m_yprescale--;
1981      }
1982      while (m_yprescale > 1 && m_rawdims.c.y * m_yprescale > manager->get_max_texture_height())
1983      {
1984         m_yprescale--;
1985      }
1986
1987      int prescale = m_renderer->window().prescale();
1988      if (m_xprescale != prescale || m_yprescale != prescale)
1989      {
1990         osd_printf_verbose("Direct3D: adjusting prescale from %dx%d to %dx%d\n", prescale, prescale, m_xprescale, m_yprescale);
1991      }
1992
1993      // loop until we allocate something or error
1994      for (int attempt = 0; attempt < 2; attempt++)
1995      {
1996         // second attempt is always 1:1
1997         if (attempt == 1)
1998         {
1999            m_xprescale = m_yprescale = 1;
2000         }
2001
2002         // screen textures with no prescaling are pretty easy
2003         if (m_xprescale == 1 && m_yprescale == 1)
2004         {
2005            result = (*d3dintf->device.create_texture)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, 1, usage, format, pool, &m_d3dtex);
2006            if (result == D3D_OK)
2007            {
2008               m_d3dfinaltex = m_d3dtex;
2009               m_type = m_texture_manager->is_dynamic_supported() ? TEXTURE_TYPE_DYNAMIC : TEXTURE_TYPE_PLAIN;
2010               if (m_renderer->get_shaders()->enabled() && !m_renderer->get_shaders()->register_texture(this))
2011               {
2012                  goto error;
2013               }
2014
2015               break;
2016            }
2017         }
2018
2019         // screen textures with prescaling require two allocations
2020         else
2021         {
2022            // use an offscreen plain surface for stretching if supported
2023            // (won't work for YUY textures)
2024            if (m_texture_manager->is_stretch_supported() && PRIMFLAG_GET_TEXFORMAT(flags) != TEXFORMAT_YUY16)
2025            {
2026               result = (*d3dintf->device.create_offscreen_plain_surface)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, format, D3DPOOL_DEFAULT, &m_d3dsurface);
2027               if (result != D3D_OK)
2028               {
2029                  continue;
2030               }
2031               m_type = TEXTURE_TYPE_SURFACE;
2032            }
2033
2034            // otherwise, we allocate a dynamic texture for the source
2035            else
2036            {
2037               result = (*d3dintf->device.create_texture)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, 1, usage, format, pool, &m_d3dtex);
2038               if (result != D3D_OK)
2039               {
2040                  continue;
2041               }
2042               m_type = m_texture_manager->is_dynamic_supported() ? TEXTURE_TYPE_DYNAMIC : TEXTURE_TYPE_PLAIN;
2043            }
2044
2045            // for the target surface, we allocate a render target texture
2046            int scwidth = m_rawdims.c.x * m_xprescale;
2047            int scheight = m_rawdims.c.y * m_yprescale;
2048
2049            // target surfaces typically cannot be YCbCr, so we always pick RGB in that case
2050            D3DFORMAT finalfmt = (format != m_texture_manager->get_yuv_format()) ? format : D3DFMT_A8R8G8B8;
2051            result = (*d3dintf->device.create_texture)(m_renderer->get_device(), scwidth, scheight, 1, D3DUSAGE_RENDERTARGET, finalfmt, D3DPOOL_DEFAULT, &m_d3dfinaltex);
2052            if (result == D3D_OK)
2053            {
2054               if (m_renderer->get_shaders()->enabled() && !m_renderer->get_shaders()->register_prescaled_texture(this))
2055               {
2056                  goto error;
2057               }
2058               break;
2059            }
2060            (*d3dintf->texture.release)(m_d3dtex);
2061            m_d3dtex = NULL;
2062         }
2063      }
2064   }
2065
2066   // copy the data to the texture
2067   set_data(texsource, flags);
2068
2069   //texsource->osdhandle = (void*)this;
2070   // add us to the texture list
2071   if(m_texture_manager->get_texlist() != NULL)
2072      m_texture_manager->get_texlist()->m_prev = this;
2073   m_prev = NULL;
2074   m_next = m_texture_manager->get_texlist();
2075   m_texture_manager->set_texlist(this);
2076   return;
2077
2078error:
2079   d3dintf->post_fx_available = false;
2080   osd_printf_error("Direct3D: Critical warning: A texture failed to allocate. Expect things to get bad quickly.\n");
2081   if (m_d3dsurface != NULL)
2082      (*d3dintf->surface.release)(m_d3dsurface);
2083   if (m_d3dtex != NULL)
2084      (*d3dintf->texture.release)(m_d3dtex);
2085}
2086
2087
2088//============================================================
2089//  texture_info::compute_size_subroutine
2090//============================================================
2091
2092void texture_info::compute_size_subroutine(int texwidth, int texheight, int* p_width, int* p_height)
2093{
2094   int finalheight = texheight;
2095   int finalwidth = texwidth;
2096
2097   // round width/height up to nearest power of 2 if we need to
2098   if (!(m_texture_manager->get_texture_caps() & D3DPTEXTURECAPS_NONPOW2CONDITIONAL))
2099   {
2100      // first the width
2101      if (finalwidth & (finalwidth - 1))
2102      {
2103         finalwidth |= finalwidth >> 1;
2104         finalwidth |= finalwidth >> 2;
2105         finalwidth |= finalwidth >> 4;
2106         finalwidth |= finalwidth >> 8;
2107         finalwidth++;
2108      }
2109
2110      // then the height
2111      if (finalheight & (finalheight - 1))
2112      {
2113         finalheight |= finalheight >> 1;
2114         finalheight |= finalheight >> 2;
2115         finalheight |= finalheight >> 4;
2116         finalheight |= finalheight >> 8;
2117         finalheight++;
2118      }
2119   }
2120
2121   // round up to square if we need to
2122   if (m_texture_manager->get_texture_caps() & D3DPTEXTURECAPS_SQUAREONLY)
2123   {
2124      if (finalwidth < finalheight)
2125         finalwidth = finalheight;
2126      else
2127         finalheight = finalwidth;
2128   }
2129
2130   // adjust the aspect ratio if we need to
2131   while (finalwidth < finalheight && finalheight / finalwidth > m_texture_manager->get_max_texture_aspect())
2132   {
2133      finalwidth *= 2;
2134   }
2135   while (finalheight < finalwidth && finalwidth / finalheight > m_texture_manager->get_max_texture_aspect())
2136   {
2137      finalheight *= 2;
2138   }
2139
2140   *p_width = finalwidth;
2141   *p_height = finalheight;
2142}
2143
2144
2145//============================================================
2146//  texture_info::compute_size
2147//============================================================
2148
2149void texture_info::compute_size(int texwidth, int texheight)
2150{
2151   int finalheight = texheight;
2152   int finalwidth = texwidth;
2153
2154   m_xborderpix = 0;
2155   m_yborderpix = 0;
2156
2157   // if we're not wrapping, add a 1-2 pixel border on all sides
2158   if (ENABLE_BORDER_PIX && !(m_flags & PRIMFLAG_TEXWRAP_MASK))
2159   {
2160      // note we need 2 pixels in X for YUY textures
2161      m_xborderpix = (PRIMFLAG_GET_TEXFORMAT(m_flags) == TEXFORMAT_YUY16) ? 2 : 1;
2162      m_yborderpix = 1;
2163   }
2164
2165   // compute final texture size
2166   finalwidth += 2 * m_xborderpix;
2167   finalheight += 2 * m_yborderpix;
2168
2169   compute_size_subroutine(finalwidth, finalheight, &finalwidth, &finalheight);
2170
2171   // if we added pixels for the border, and that just barely pushed us over, take it back
2172   if (finalwidth > m_texture_manager->get_max_texture_width() || finalheight > m_texture_manager->get_max_texture_height())
2173   {
2174      finalheight = texheight;
2175      finalwidth = texwidth;
2176
2177      m_xborderpix = 0;
2178      m_yborderpix = 0;
2179
2180      compute_size_subroutine(finalwidth, finalheight, &finalwidth, &finalheight);
2181   }
2182
2183   // if we're above the max width/height, do what?
2184   if (finalwidth > m_texture_manager->get_max_texture_width() || finalheight > m_texture_manager->get_max_texture_height())
2185   {
2186      static int printed = FALSE;
2187      if (!printed) osd_printf_warning("Texture too big! (wanted: %dx%d, max is %dx%d)\n", finalwidth, finalheight, (int)m_texture_manager->get_max_texture_width(), (int)m_texture_manager->get_max_texture_height());
2188      printed = TRUE;
2189   }
2190
2191   // compute the U/V scale factors
2192   m_start.c.x = (float)m_xborderpix / (float)finalwidth;
2193   m_start.c.y = (float)m_yborderpix / (float)finalheight;
2194   m_stop.c.x = (float)(texwidth + m_xborderpix) / (float)finalwidth;
2195   m_stop.c.y = (float)(texheight + m_yborderpix) / (float)finalheight;
2196
2197   // set the final values
2198   m_rawdims.c.x = finalwidth;
2199   m_rawdims.c.y = finalheight;
2200}
2201
2202
2203//============================================================
2204//  copyline_palette16
2205//============================================================
2206
2207INLINE void copyline_palette16(UINT32 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix)
2208{
2209   int x;
2210
2211   assert(xborderpix == 0 || xborderpix == 1);
2212   if (xborderpix)
2213      *dst++ = 0xff000000 | palette[*src];
2214   for (x = 0; x < width; x++)
2215      *dst++ = 0xff000000 | palette[*src++];
2216   if (xborderpix)
2217      *dst++ = 0xff000000 | palette[*--src];
2218}
2219
2220
2221//============================================================
2222//  copyline_palettea16
2223//============================================================
2224
2225INLINE void copyline_palettea16(UINT32 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix)
2226{
2227   int x;
2228
2229   assert(xborderpix == 0 || xborderpix == 1);
2230   if (xborderpix)
2231      *dst++ = palette[*src];
2232   for (x = 0; x < width; x++)
2233      *dst++ = palette[*src++];
2234   if (xborderpix)
2235      *dst++ = palette[*--src];
2236}
2237
2238
2239//============================================================
2240//  copyline_rgb32
2241//============================================================
2242
2243INLINE void copyline_rgb32(UINT32 *dst, const UINT32 *src, int width, const rgb_t *palette, int xborderpix)
2244{
2245   int x;
2246
2247   assert(xborderpix == 0 || xborderpix == 1);
2248
2249   // palette (really RGB map) case
2250   if (palette != NULL)
2251   {
2252      if (xborderpix)
2253      {
2254         rgb_t srcpix = *src;
2255         *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2256      }
2257      for (x = 0; x < width; x++)
2258      {
2259         rgb_t srcpix = *src++;
2260         *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2261      }
2262      if (xborderpix)
2263      {
2264         rgb_t srcpix = *--src;
2265         *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2266      }
2267   }
2268
2269   // direct case
2270   else
2271   {
2272      if (xborderpix)
2273         *dst++ = 0xff000000 | *src;
2274      for (x = 0; x < width; x++)
2275         *dst++ = 0xff000000 | *src++;
2276      if (xborderpix)
2277         *dst++ = 0xff000000 | *--src;
2278   }
2279}
2280
2281
2282//============================================================
2283//  copyline_argb32
2284//============================================================
2285
2286INLINE void copyline_argb32(UINT32 *dst, const UINT32 *src, int width, const rgb_t *palette, int xborderpix)
2287{
2288   int x;
2289
2290   assert(xborderpix == 0 || xborderpix == 1);
2291
2292   // palette (really RGB map) case
2293   if (palette != NULL)
2294   {
2295      if (xborderpix)
2296      {
2297         rgb_t srcpix = *src;
2298         *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2299      }
2300      for (x = 0; x < width; x++)
2301      {
2302         rgb_t srcpix = *src++;
2303         *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2304      }
2305      if (xborderpix)
2306      {
2307         rgb_t srcpix = *--src;
2308         *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2309      }
2310   }
2311
2312   // direct case
2313   else
2314   {
2315      if (xborderpix)
2316         *dst++ = *src;
2317      for (x = 0; x < width; x++)
2318         *dst++ = *src++;
2319      if (xborderpix)
2320         *dst++ = *--src;
2321   }
2322}
2323
2324
2325//============================================================
2326//  copyline_yuy16_to_yuy2
2327//============================================================
2328
2329INLINE void copyline_yuy16_to_yuy2(UINT16 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix)
2330{
2331   int x;
2332
2333   assert(xborderpix == 0 || xborderpix == 2);
2334   assert(width % 2 == 0);
2335
2336   // palette (really RGB map) case
2337   if (palette != NULL)
2338   {
2339      if (xborderpix)
2340      {
2341         UINT16 srcpix0 = *src++;
2342         UINT16 srcpix1 = *src--;
2343         *dst++ = palette[0x000 + (srcpix0 >> 8)] | (srcpix0 << 8);
2344         *dst++ = palette[0x000 + (srcpix0 >> 8)] | (srcpix1 << 8);
2345      }
2346      for (x = 0; x < width; x += 2)
2347      {
2348         UINT16 srcpix0 = *src++;
2349         UINT16 srcpix1 = *src++;
2350         *dst++ = palette[0x000 + (srcpix0 >> 8)] | (srcpix0 << 8);
2351         *dst++ = palette[0x000 + (srcpix1 >> 8)] | (srcpix1 << 8);
2352      }
2353      if (xborderpix)
2354      {
2355         UINT16 srcpix1 = *--src;
2356         UINT16 srcpix0 = *--src;
2357         *dst++ = palette[0x000 + (srcpix1 >> 8)] | (srcpix0 << 8);
2358         *dst++ = palette[0x000 + (srcpix1 >> 8)] | (srcpix1 << 8);
2359      }
2360   }
2361
2362   // direct case
2363   else
2364   {
2365      if (xborderpix)
2366      {
2367         UINT16 srcpix0 = *src++;
2368         UINT16 srcpix1 = *src--;
2369         *dst++ = (srcpix0 >> 8) | (srcpix0 << 8);
2370         *dst++ = (srcpix0 >> 8) | (srcpix1 << 8);
2371      }
2372      for (x = 0; x < width; x += 2)
2373      {
2374         UINT16 srcpix0 = *src++;
2375         UINT16 srcpix1 = *src++;
2376         *dst++ = (srcpix0 >> 8) | (srcpix0 << 8);
2377         *dst++ = (srcpix1 >> 8) | (srcpix1 << 8);
2378      }
2379      if (xborderpix)
2380      {
2381         UINT16 srcpix1 = *--src;
2382         UINT16 srcpix0 = *--src;
2383         *dst++ = (srcpix1 >> 8) | (srcpix0 << 8);
2384         *dst++ = (srcpix1 >> 8) | (srcpix1 << 8);
2385      }
2386   }
2387}
2388
2389
2390//============================================================
2391//  copyline_yuy16_to_uyvy
2392//============================================================
2393
2394INLINE void copyline_yuy16_to_uyvy(UINT16 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix)
2395{
2396   int x;
2397
2398   assert(xborderpix == 0 || xborderpix == 2);
2399   assert(width % 2 == 0);
2400
2401   // palette (really RGB map) case
2402   if (palette != NULL)
2403   {
2404      if (xborderpix)
2405      {
2406         UINT16 srcpix0 = *src++;
2407         UINT16 srcpix1 = *src--;
2408         *dst++ = palette[0x100 + (srcpix0 >> 8)] | (srcpix0 & 0xff);
2409         *dst++ = palette[0x100 + (srcpix0 >> 8)] | (srcpix1 & 0xff);
2410      }
2411      for (x = 0; x < width; x += 2)
2412      {
2413         UINT16 srcpix0 = *src++;
2414         UINT16 srcpix1 = *src++;
2415         *dst++ = palette[0x100 + (srcpix0 >> 8)] | (srcpix0 & 0xff);
2416         *dst++ = palette[0x100 + (srcpix1 >> 8)] | (srcpix1 & 0xff);
2417      }
2418      if (xborderpix)
2419      {
2420         UINT16 srcpix1 = *--src;
2421         UINT16 srcpix0 = *--src;
2422         *dst++ = palette[0x100 + (srcpix1 >> 8)] | (srcpix0 & 0xff);
2423         *dst++ = palette[0x100 + (srcpix1 >> 8)] | (srcpix1 & 0xff);
2424      }
2425   }
2426
2427   // direct case
2428   else
2429   {
2430      if (xborderpix)
2431      {
2432         UINT16 srcpix0 = src[0];
2433         UINT16 srcpix1 = src[1];
2434         *dst++ = srcpix0;
2435         *dst++ = (srcpix0 & 0xff00) | (srcpix1 & 0x00ff);
2436      }
2437      for (x = 0; x < width; x += 2)
2438      {
2439         *dst++ = *src++;
2440         *dst++ = *src++;
2441      }
2442      if (xborderpix)
2443      {
2444         UINT16 srcpix1 = *--src;
2445         UINT16 srcpix0 = *--src;
2446         *dst++ = (srcpix1 & 0xff00) | (srcpix0 & 0x00ff);
2447         *dst++ = srcpix1;
2448      }
2449   }
2450}
2451
2452
2453//============================================================
2454//  copyline_yuy16_to_argb
2455//============================================================
2456
2457INLINE void copyline_yuy16_to_argb(UINT32 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix)
2458{
2459   int x;
2460
2461   assert(xborderpix == 0 || xborderpix == 2);
2462   assert(width % 2 == 0);
2463
2464   // palette (really RGB map) case
2465   if (palette != NULL)
2466   {
2467      if (xborderpix)
2468      {
2469         UINT16 srcpix0 = src[0];
2470         UINT16 srcpix1 = src[1];
2471         UINT8 cb = srcpix0 & 0xff;
2472         UINT8 cr = srcpix1 & 0xff;
2473         *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr);
2474         *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr);
2475      }
2476      for (x = 0; x < width / 2; x++)
2477      {
2478         UINT16 srcpix0 = *src++;
2479         UINT16 srcpix1 = *src++;
2480         UINT8 cb = srcpix0 & 0xff;
2481         UINT8 cr = srcpix1 & 0xff;
2482         *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr);
2483         *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr);
2484      }
2485      if (xborderpix)
2486      {
2487         UINT16 srcpix1 = *--src;
2488         UINT16 srcpix0 = *--src;
2489         UINT8 cb = srcpix0 & 0xff;
2490         UINT8 cr = srcpix1 & 0xff;
2491         *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr);
2492         *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr);
2493      }
2494   }
2495
2496   // direct case
2497   else
2498   {
2499      if (xborderpix)
2500      {
2501         UINT16 srcpix0 = src[0];
2502         UINT16 srcpix1 = src[1];
2503         UINT8 cb = srcpix0 & 0xff;
2504         UINT8 cr = srcpix1 & 0xff;
2505         *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr);
2506         *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr);
2507      }
2508      for (x = 0; x < width; x += 2)
2509      {
2510         UINT16 srcpix0 = *src++;
2511         UINT16 srcpix1 = *src++;
2512         UINT8 cb = srcpix0 & 0xff;
2513         UINT8 cr = srcpix1 & 0xff;
2514         *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr);
2515         *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr);
2516      }
2517      if (xborderpix)
2518      {
2519         UINT16 srcpix1 = *--src;
2520         UINT16 srcpix0 = *--src;
2521         UINT8 cb = srcpix0 & 0xff;
2522         UINT8 cr = srcpix1 & 0xff;
2523         *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr);
2524         *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr);
2525      }
2526   }
2527}
2528
2529
2530//============================================================
2531//  texture_set_data
2532//============================================================
2533
2534void texture_info::set_data(const render_texinfo *texsource, UINT32 flags)
2535{
2536   D3DLOCKED_RECT rect;
2537   HRESULT result;
2538
2539   // lock the texture
2540   switch (m_type)
2541   {
2542      default:
2543      case TEXTURE_TYPE_PLAIN:    result = (*d3dintf->texture.lock_rect)(m_d3dtex, 0, &rect, NULL, 0);                 break;
2544      case TEXTURE_TYPE_DYNAMIC:  result = (*d3dintf->texture.lock_rect)(m_d3dtex, 0, &rect, NULL, D3DLOCK_DISCARD);   break;
2545      case TEXTURE_TYPE_SURFACE:  result = (*d3dintf->surface.lock_rect)(m_d3dsurface, &rect, NULL, D3DLOCK_DISCARD);  break;
2546   }
2547   if (result != D3D_OK)
2548   {
2549      return;
2550   }
2551
2552   // loop over Y
2553   int miny = 0 - m_yborderpix;
2554   int maxy = texsource->height + m_yborderpix;
2555   for (int dsty = miny; dsty < maxy; dsty++)
2556   {
2557      int srcy = (dsty < 0) ? 0 : (dsty >= texsource->height) ? texsource->height - 1 : dsty;
2558      void *dst = (BYTE *)rect.pBits + (dsty + m_yborderpix) * rect.Pitch;
2559
2560      // switch off of the format and
2561      switch (PRIMFLAG_GET_TEXFORMAT(flags))
2562      {
2563         case TEXFORMAT_PALETTE16:
2564            copyline_palette16((UINT32 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix);
2565            break;
2566
2567         case TEXFORMAT_PALETTEA16:
2568            copyline_palettea16((UINT32 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix);
2569            break;
2570
2571         case TEXFORMAT_RGB32:
2572            copyline_rgb32((UINT32 *)dst, (UINT32 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix);
2573            break;
2574
2575         case TEXFORMAT_ARGB32:
2576            copyline_argb32((UINT32 *)dst, (UINT32 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix);
2577            break;
2578
2579         case TEXFORMAT_YUY16:
2580            if (m_texture_manager->get_yuv_format() == D3DFMT_YUY2)
2581               copyline_yuy16_to_yuy2((UINT16 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix);
2582            else if (m_texture_manager->get_yuv_format() == D3DFMT_UYVY)
2583               copyline_yuy16_to_uyvy((UINT16 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix);
2584            else
2585               copyline_yuy16_to_argb((UINT32 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix);
2586            break;
2587
2588         default:
2589            osd_printf_error("Unknown texture blendmode=%d format=%d\n", PRIMFLAG_GET_BLENDMODE(flags), PRIMFLAG_GET_TEXFORMAT(flags));
2590            break;
2591      }
2592   }
2593
2594   // unlock
2595   switch (m_type)
2596   {
2597      default:
2598      case TEXTURE_TYPE_PLAIN:    result = (*d3dintf->texture.unlock_rect)(m_d3dtex, 0);   break;
2599      case TEXTURE_TYPE_DYNAMIC:  result = (*d3dintf->texture.unlock_rect)(m_d3dtex, 0);   break;
2600      case TEXTURE_TYPE_SURFACE:  result = (*d3dintf->surface.unlock_rect)(m_d3dsurface);  break;
2601   }
2602   if (result != D3D_OK)
2603   {
2604      osd_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result);
2605   }
2606
2607   // prescale
2608   prescale();
2609}
2610
2611
2612//============================================================
2613//  texture_info::prescale
2614//============================================================
2615
2616void texture_info::prescale()
2617{
2618   surface *scale_surface;
2619   HRESULT result;
2620   int i;
2621
2622   // if we don't need to, just skip it
2623   if (m_d3dtex == m_d3dfinaltex)
2624      return;
2625
2626   // for all cases, we need to get the surface of the render target
2627   result = (*d3dintf->texture.get_surface_level)(m_d3dfinaltex, 0, &scale_surface);
2628   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during texture get_surface_level call\n", (int)result);
2629
2630   // if we have an offscreen plain surface, we can just StretchRect to it
2631   if (m_type == TEXTURE_TYPE_SURFACE)
2632   {
2633      assert(m_d3dsurface != NULL);
2634
2635      // set the source bounds
2636      RECT source;
2637      source.left = source.top = 0;
2638      source.right = m_texinfo.width + 2 * m_xborderpix;
2639      source.bottom = m_texinfo.height + 2 * m_yborderpix;
2640
2641      // set the target bounds
2642      RECT dest;
2643      dest = source;
2644      dest.right *= m_xprescale;
2645      dest.bottom *= m_yprescale;
2646
2647      // do the stretchrect
2648      result = (*d3dintf->device.stretch_rect)(m_renderer->get_device(), m_d3dsurface, &source, scale_surface, &dest, D3DTEXF_POINT);
2649      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device stretct_rect call\n", (int)result);
2650   }
2651
2652   // if we are using a texture render target, we need to do more preparations
2653   else
2654   {
2655      surface *backbuffer;
2656
2657      assert(m_d3dtex != NULL);
2658
2659      // first remember the original render target and set the new one
2660      result = (*d3dintf->device.get_render_target)(m_renderer->get_device(), 0, &backbuffer);
2661      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device get_render_target call\n", (int)result);
2662      result = (*d3dintf->device.set_render_target)(m_renderer->get_device(), 0, scale_surface);
2663      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call 1\n", (int)result);
2664      m_renderer->reset_render_states();
2665
2666      // start the scene
2667      result = (*d3dintf->device.begin_scene)(m_renderer->get_device());
2668      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device begin_scene call\n", (int)result);
2669
2670      // configure the rendering pipeline
2671      m_renderer->set_filter(FALSE);
2672      m_renderer->set_blendmode(BLENDMODE_NONE);
2673      result = (*d3dintf->device.set_texture)(m_renderer->get_device(), 0, m_d3dtex);
2674      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture call\n", (int)result);
2675
2676      // lock the vertex buffer
2677      result = (*d3dintf->vertexbuf.lock)(m_renderer->get_vertex_buffer(), 0, 0, m_renderer->get_locked_buffer_ptr(), D3DLOCK_DISCARD);
2678      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during vertex buffer lock call\n", (int)result);
2679
2680      // configure the X/Y coordinates on the target surface
2681      vertex *lockedbuf = m_renderer->get_locked_buffer();
2682      lockedbuf[0].x = -0.5f;
2683      lockedbuf[0].y = -0.5f;
2684      lockedbuf[1].x = (float)((m_texinfo.width + 2 * m_xborderpix) * m_xprescale) - 0.5f;
2685      lockedbuf[1].y = -0.5f;
2686      lockedbuf[2].x = -0.5f;
2687      lockedbuf[2].y = (float)((m_texinfo.height + 2 * m_yborderpix) * m_yprescale) - 0.5f;
2688      lockedbuf[3].x = (float)((m_texinfo.width + 2 * m_xborderpix) * m_xprescale) - 0.5f;
2689      lockedbuf[3].y = (float)((m_texinfo.height + 2 * m_yborderpix) * m_yprescale) - 0.5f;
2690
2691      // configure the U/V coordintes on the source texture
2692      lockedbuf[0].u0 = 0.0f;
2693      lockedbuf[0].v0 = 0.0f;
2694      lockedbuf[1].u0 = (float)(m_texinfo.width + 2 * m_xborderpix) / (float)m_rawdims.c.x;
2695      lockedbuf[1].v0 = 0.0f;
2696      lockedbuf[2].u0 = 0.0f;
2697      lockedbuf[2].v0 = (float)(m_texinfo.height + 2 * m_yborderpix) / (float)m_rawdims.c.y;
2698      lockedbuf[3].u0 = (float)(m_texinfo.width + 2 * m_xborderpix) / (float)m_rawdims.c.x;
2699      lockedbuf[3].v0 = (float)(m_texinfo.height + 2 * m_yborderpix) / (float)m_rawdims.c.y;
2700
2701      // reset the remaining vertex parameters
2702      for (i = 0; i < 4; i++)
2703      {
2704         lockedbuf[i].z = 0.0f;
2705         lockedbuf[i].rhw = 1.0f;
2706         lockedbuf[i].color = D3DCOLOR_ARGB(0xff,0xff,0xff,0xff);
2707      }
2708
2709      // unlock the vertex buffer
2710      result = (*d3dintf->vertexbuf.unlock)(m_renderer->get_vertex_buffer());
2711      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during vertex buffer unlock call\n", (int)result);
2712      m_renderer->set_locked_buffer(NULL);
2713
2714      // set the stream and draw the triangle strip
2715      result = (*d3dintf->device.set_stream_source)(m_renderer->get_device(), 0, m_renderer->get_vertex_buffer(), sizeof(vertex));
2716      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_stream_source call\n", (int)result);
2717      result = (*d3dintf->device.draw_primitive)(m_renderer->get_device(), D3DPT_TRIANGLESTRIP, 0, 2);
2718      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result);
2719
2720      // end the scene
2721      result = (*d3dintf->device.end_scene)(m_renderer->get_device());
2722      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device end_scene call\n", (int)result);
2723
2724      // reset the render target and release our reference to the backbuffer
2725      result = (*d3dintf->device.set_render_target)(m_renderer->get_device(), 0, backbuffer);
2726      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call 2\n", (int)result);
2727      (*d3dintf->surface.release)(backbuffer);
2728      m_renderer->reset_render_states();
2729   }
2730
2731   // release our reference to the target surface
2732   (*d3dintf->surface.release)(scale_surface);
2733}
2734
2735
2736//============================================================
2737//  cache_target::~cache_target
2738//============================================================
2739
2740cache_target::~cache_target()
2741{
2742   for (int index = 0; index < 11; index++)
2743   {
2744      if (bloom_texture[index] != NULL)
2745      {
2746         (*d3dintf->texture.release)(bloom_texture[index]);
2747         bloom_texture[index] = NULL;
2748      }
2749      if (bloom_target[index] != NULL)
2750      {
2751         (*d3dintf->surface.release)(bloom_target[index]);
2752         bloom_target[index] = NULL;
2753      }
2754   }
2755
2756   if (last_texture != NULL)
2757   {
2758      (*d3dintf->texture.release)(last_texture);
2759      last_texture = NULL;
2760   }
2761   if (last_target != NULL)
2762   {
2763      (*d3dintf->surface.release)(last_target);
2764      last_target = NULL;
2765   }
2766}
2767
2768
2769//============================================================
2770//  cache_target::init - initializes a target cache
2771//============================================================
2772
2773bool cache_target::init(renderer *d3d, base *d3dintf, int width, int height, int prescale_x, int prescale_y)
2774{
2775   int bloom_index = 0;
2776   int bloom_size = (width < height) ? width : height;
2777   int bloom_width = width;
2778   int bloom_height = height;
2779   for (; bloom_size >= 2 && bloom_index < 11; bloom_size >>= 1)
2780   {
2781      bloom_width >>= 1;
2782      bloom_height >>= 1;
2783
2784      HRESULT result = (*d3dintf->device.create_texture)(d3d->get_device(), bloom_width, bloom_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bloom_texture[bloom_index]);
2785      if (result != D3D_OK)
2786      {
2787         return false;
2788      }
2789      (*d3dintf->texture.get_surface_level)(bloom_texture[bloom_index], 0, &bloom_target[bloom_index]);
2790
2791      bloom_index++;
2792   }
2793
2794   HRESULT result = (*d3dintf->device.create_texture)(d3d->get_device(), width * prescale_x, height * prescale_y, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &last_texture);
2795   if (result != D3D_OK)
2796   {
2797      return false;
2798   }
2799   (*d3dintf->texture.get_surface_level)(last_texture, 0, &last_target);
2800
2801   target_width = width * prescale_x;
2802   target_height = height * prescale_y;
2803
2804   return true;
2805}
2806
2807
2808//============================================================
2809//  render_target::~render_target
2810//============================================================
2811
2812render_target::~render_target()
2813{
2814   for (int index = 0; index < 11; index++)
2815   {
2816      if (bloom_texture[index] != NULL)
2817      {
2818         (*d3dintf->texture.release)(bloom_texture[index]);
2819         bloom_texture[index] = NULL;
2820      }
2821      if (bloom_target[index] != NULL)
2822      {
2823         (*d3dintf->surface.release)(bloom_target[index]);
2824         bloom_target[index] = NULL;
2825      }
2826   }
2827
2828   for (int index = 0; index < 2; index++)
2829   {
2830      if (native_texture[index] != NULL)
2831      {
2832         (*d3dintf->texture.release)(native_texture[index]);
2833         native_texture[index] = NULL;
2834      }
2835      if (native_target[index] != NULL)
2836      {
2837         (*d3dintf->surface.release)(native_target[index]);
2838         native_target[index] = NULL;
2839      }
2840      if (prescale_texture[index] != NULL)
2841      {
2842         (*d3dintf->texture.release)(prescale_texture[index]);
2843         prescale_texture[index] = NULL;
2844      }
2845      if (prescale_target[index] != NULL)
2846      {
2847         (*d3dintf->surface.release)(prescale_target[index]);
2848         prescale_target[index] = NULL;
2849      }
2850   }
2851}
2852
2853
2854//============================================================
2855//  render_target::init - initializes a render target
2856//============================================================
2857
2858bool render_target::init(renderer *d3d, base *d3dintf, int width, int height, int prescale_x, int prescale_y)
2859{
2860   HRESULT result;
2861
2862   for (int index = 0; index < 2; index++)
2863   {
2864      result = (*d3dintf->device.create_texture)(d3d->get_device(), width, height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &native_texture[index]);
2865      if (result != D3D_OK)
2866      {
2867         return false;
2868      }
2869      (*d3dintf->texture.get_surface_level)(native_texture[index], 0, &native_target[index]);
2870
2871      result = (*d3dintf->device.create_texture)(d3d->get_device(), width * prescale_x, height * prescale_y, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &prescale_texture[index]);
2872      if (result != D3D_OK)
2873      {
2874         return false;
2875      }
2876      (*d3dintf->texture.get_surface_level)(prescale_texture[index], 0, &prescale_target[index]);
2877   }
2878
2879   int bloom_index = 0;
2880   float bloom_size = (d3d->get_width() < d3d->get_height()) ? d3d->get_width() : d3d->get_height();
2881   float bloom_width = d3d->get_width();
2882   float bloom_height = d3d->get_height();
2883   for (; bloom_size >= 2.0f && bloom_index < 11; bloom_size *= 0.5f)
2884   {
2885      bloom_width *= 0.5f;
2886      bloom_height *= 0.5f;
2887
2888      result = (*d3dintf->device.create_texture)(d3d->get_device(), (int)bloom_width, (int)bloom_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bloom_texture[bloom_index]);
2889      if (result != D3D_OK)
2890      {
2891         return false;
2892      }
2893      (*d3dintf->texture.get_surface_level)(bloom_texture[bloom_index], 0, &bloom_target[bloom_index]);
2894
2895      bloom_index++;
2896   }
2897
2898   this->width = width;
2899   this->height = height;
2900
2901   target_width = width * prescale_x;
2902   target_height = height * prescale_y;
2903
2904   return true;
2905}
2906
2907}
trunk/src/osd/modules/render/drawd3d.cpp
r0r250288
1// license:BSD-3-Clause
2// copyright-holders:Aaron Giles
3//============================================================
4//
5//  drawd3d.c - Win32 Direct3D implementation
6//
7//============================================================
8
9// Useful info:
10//  Windows XP/2003 shipped with DirectX 8.1
11//  Windows 2000 shipped with DirectX 7a
12//  Windows 98SE shipped with DirectX 6.1a
13//  Windows 98 shipped with DirectX 5
14//  Windows NT shipped with DirectX 3.0a
15//  Windows 95 shipped with DirectX 2
16
17// standard windows headers
18#define WIN32_LEAN_AND_MEAN
19#include <windows.h>
20#include <tchar.h>
21#include <mmsystem.h>
22#include <d3d9.h>
23#include <d3dx9.h>
24#include <math.h>
25#undef interface
26
27// MAME headers
28#include "emu.h"
29#include "render.h"
30#include "ui/ui.h"
31#include "rendutil.h"
32#include "options.h"
33#include "emuopts.h"
34#include "aviio.h"
35#include "png.h"
36
37// MAMEOS headers
38#include "modules/render/d3d/d3dintf.h"
39#include "winmain.h"
40#include "window.h"
41#include "config.h"
42#include "strconv.h"
43#include "modules/render/d3d/d3dcomm.h"
44#include "drawd3d.h"
45
46
47//============================================================
48//  DEBUGGING
49//============================================================
50
51extern void mtlog_add(const char *event);
52
53
54//============================================================
55//  CONSTANTS
56//============================================================
57
58#define ENABLE_BORDER_PIX   (1)
59
60enum
61{
62   TEXTURE_TYPE_PLAIN,
63   TEXTURE_TYPE_DYNAMIC,
64   TEXTURE_TYPE_SURFACE
65};
66
67
68//============================================================
69//  MACROS
70//============================================================
71
72#define FSWAP(var1, var2) do { float temp = var1; var1 = var2; var2 = temp; } while (0)
73
74
75//============================================================
76//  GLOBALS
77//============================================================
78
79static const line_aa_step line_aa_1step[] =
80{
81   {  0.00f,  0.00f,  1.00f  },
82   { 0 }
83};
84
85static const line_aa_step line_aa_4step[] =
86{
87   { -0.25f,  0.00f,  0.25f  },
88   {  0.25f,  0.00f,  0.25f  },
89   {  0.00f, -0.25f,  0.25f  },
90   {  0.00f,  0.25f,  0.25f  },
91   { 0 }
92};
93
94
95//============================================================
96//  INLINES
97//============================================================
98
99INLINE BOOL GetClientRectExceptMenu(HWND hWnd, PRECT pRect, BOOL fullscreen)
100{
101   static HMENU last_menu;
102   static RECT last_rect;
103   static RECT cached_rect;
104   HMENU menu = GetMenu(hWnd);
105   BOOL result = GetClientRect(hWnd, pRect);
106
107   if (!fullscreen || !menu)
108      return result;
109
110   // to avoid flicker use cache if we can use
111   if (last_menu != menu || memcmp(&last_rect, pRect, sizeof *pRect) != 0)
112   {
113      last_menu = menu;
114      last_rect = *pRect;
115
116      SetMenu(hWnd, NULL);
117      result = GetClientRect(hWnd, &cached_rect);
118      SetMenu(hWnd, menu);
119   }
120
121   *pRect = cached_rect;
122   return result;
123}
124
125
126INLINE UINT32 ycc_to_rgb(UINT8 y, UINT8 cb, UINT8 cr)
127{
128   /* original equations:
129
130       C = Y - 16
131       D = Cb - 128
132       E = Cr - 128
133
134       R = clip(( 298 * C           + 409 * E + 128) >> 8)
135       G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8)
136       B = clip(( 298 * C + 516 * D           + 128) >> 8)
137
138       R = clip(( 298 * (Y - 16)                    + 409 * (Cr - 128) + 128) >> 8)
139       G = clip(( 298 * (Y - 16) - 100 * (Cb - 128) - 208 * (Cr - 128) + 128) >> 8)
140       B = clip(( 298 * (Y - 16) + 516 * (Cb - 128)                    + 128) >> 8)
141
142       R = clip(( 298 * Y - 298 * 16                        + 409 * Cr - 409 * 128 + 128) >> 8)
143       G = clip(( 298 * Y - 298 * 16 - 100 * Cb + 100 * 128 - 208 * Cr + 208 * 128 + 128) >> 8)
144       B = clip(( 298 * Y - 298 * 16 + 516 * Cb - 516 * 128                        + 128) >> 8)
145
146       R = clip(( 298 * Y - 298 * 16                        + 409 * Cr - 409 * 128 + 128) >> 8)
147       G = clip(( 298 * Y - 298 * 16 - 100 * Cb + 100 * 128 - 208 * Cr + 208 * 128 + 128) >> 8)
148       B = clip(( 298 * Y - 298 * 16 + 516 * Cb - 516 * 128                        + 128) >> 8)
149   */
150   int r, g, b, common;
151
152   common = 298 * y - 298 * 16;
153   r = (common +                        409 * cr - 409 * 128 + 128) >> 8;
154   g = (common - 100 * cb + 100 * 128 - 208 * cr + 208 * 128 + 128) >> 8;
155   b = (common + 516 * cb - 516 * 128                        + 128) >> 8;
156
157   if (r < 0) r = 0;
158   else if (r > 255) r = 255;
159   if (g < 0) g = 0;
160   else if (g > 255) g = 255;
161   if (b < 0) b = 0;
162   else if (b > 255) b = 255;
163
164   return rgb_t(0xff, r, g, b);
165}
166
167
168//============================================================
169//  drawd3d_init
170//============================================================
171
172static d3d::base *               d3dintf; // FIX ME
173
174
175//============================================================
176//  PROTOTYPES
177//============================================================
178
179// core functions
180static void drawd3d_exit(void);
181
182
183//============================================================
184//  drawd3d_window_init
185//============================================================
186
187int d3d::renderer::create()
188{
189   if (!initialize())
190   {
191      destroy();
192      osd_printf_error("Unable to initialize Direct3D.\n");
193      return 1;
194   }
195
196   return 0;
197}
198
199
200//============================================================
201//  drawd3d_exit
202//============================================================
203
204static void drawd3d_exit(void)
205{
206   if (d3dintf != NULL)
207      (*d3dintf->d3d.release)(d3dintf);
208}
209
210void d3d::renderer::toggle_fsfx()
211{
212   set_restarting(true);
213}
214
215void d3d::renderer::record()
216{
217   get_shaders()->window_record();
218}
219
220void d3d::renderer::save()
221{
222   get_shaders()->window_save();
223}
224
225
226//============================================================
227//  drawd3d_window_destroy
228//============================================================
229
230void d3d::renderer::destroy()
231{
232   if (get_shaders() != NULL && get_shaders()->recording())
233      get_shaders()->window_record();
234
235}
236
237
238//============================================================
239//  drawd3d_window_get_primitives
240//============================================================
241
242render_primitive_list *d3d::renderer::get_primitives()
243{
244   RECT client;
245
246   GetClientRectExceptMenu(window().m_hwnd, &client, window().fullscreen());
247   if (rect_width(&client) > 0 && rect_height(&client) > 0)
248   {
249      window().target()->set_bounds(rect_width(&client), rect_height(&client), window().aspect());
250      window().target()->set_max_update_rate((get_refresh() == 0) ? get_origmode().RefreshRate : get_refresh());
251   }
252   return &window().target()->get_primitives();
253}
254
255
256//============================================================
257//  drawnone_create
258//============================================================
259
260static osd_renderer *drawd3d_create(osd_window *window)
261{
262   return global_alloc(d3d::renderer(window));
263}
264
265int drawd3d_init(running_machine &machine, osd_draw_callbacks *callbacks)
266{
267   d3dintf = NULL;
268
269   // Use Direct3D9
270   d3dintf = d3d::drawd3d9_init();
271
272   // if we failed, note the error
273   if (d3dintf == NULL)
274   {
275      osd_printf_error("Unable to initialize Direct3D.\n");
276      return 1;
277   }
278
279   // fill in the callbacks
280   memset(callbacks, 0, sizeof(*callbacks));
281   callbacks->exit = drawd3d_exit;
282   callbacks->create = drawd3d_create;
283   return 0;
284}
285
286
287//============================================================
288//  drawd3d_window_draw
289//============================================================
290
291int d3d::renderer::draw(const int update)
292{
293   int check = pre_window_draw_check();
294   if (check >= 0)
295      return check;
296
297   begin_frame();
298   process_primitives();
299   end_frame();
300
301   return 0;
302}
303
304namespace d3d
305{
306void renderer::set_texture(texture_info *texture)
307{
308   if (texture != m_last_texture)
309   {
310      m_last_texture = texture;
311      m_last_texture_flags = (texture == NULL ? 0 : texture->get_flags());
312      HRESULT result = (*d3dintf->device.set_texture)(m_device, 0, (texture == NULL) ? get_default_texture()->get_finaltex() : texture->get_finaltex());
313      m_shaders->set_texture(texture);
314      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture call\n", (int)result);
315   }
316}
317
318void renderer::set_filter(int filter)
319{
320   if (filter != m_last_filter)
321   {
322      m_last_filter = filter;
323      HRESULT result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MINFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT);
324      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
325      result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MAGFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT);
326      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
327      result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MINFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT);
328      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
329      result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MAGFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT);
330      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
331   }
332}
333
334void renderer::set_wrap(D3DTEXTUREADDRESS wrap)
335{
336   if (wrap != m_last_wrap)
337   {
338      m_last_wrap = wrap;
339      HRESULT result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSU, wrap);
340      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
341      result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSV, wrap);
342      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
343      result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSU, wrap);
344      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
345      result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSV, wrap);
346      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
347   }
348}
349
350void renderer::set_modmode(DWORD modmode)
351{
352   if (modmode != m_last_modmode)
353   {
354      m_last_modmode = modmode;
355      HRESULT result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, D3DTSS_COLOROP, modmode);
356      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
357      result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, D3DTSS_COLOROP, modmode);
358      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
359   }
360}
361
362void renderer::set_blendmode(int blendmode)
363{
364   int blendenable;
365   int blendop;
366   int blendsrc;
367   int blenddst;
368
369   // choose the parameters
370   switch (blendmode)
371   {
372      default:
373      case BLENDMODE_NONE:            blendenable = FALSE;    blendop = D3DBLENDOP_ADD;   blendsrc = D3DBLEND_SRCALPHA;   blenddst = D3DBLEND_INVSRCALPHA;    break;
374      case BLENDMODE_ALPHA:           blendenable = TRUE;     blendop = D3DBLENDOP_ADD;   blendsrc = D3DBLEND_SRCALPHA;   blenddst = D3DBLEND_INVSRCALPHA;    break;
375      case BLENDMODE_RGB_MULTIPLY:    blendenable = TRUE;     blendop = D3DBLENDOP_ADD;   blendsrc = D3DBLEND_DESTCOLOR;  blenddst = D3DBLEND_ZERO;           break;
376      case BLENDMODE_ADD:             blendenable = TRUE;     blendop = D3DBLENDOP_ADD;   blendsrc = D3DBLEND_SRCALPHA;   blenddst = D3DBLEND_ONE;            break;
377   }
378
379   // adjust the bits that changed
380   if (blendenable != m_last_blendenable)
381   {
382      m_last_blendenable = blendenable;
383      HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHABLENDENABLE, blendenable);
384      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result);
385   }
386
387   if (blendop != m_last_blendop)
388   {
389      m_last_blendop = blendop;
390      HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_BLENDOP, blendop);
391      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result);
392   }
393
394   if (blendsrc != m_last_blendsrc)
395   {
396      m_last_blendsrc = blendsrc;
397      HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_SRCBLEND, blendsrc);
398      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result);
399   }
400
401   if (blenddst != m_last_blenddst)
402   {
403      m_last_blenddst = blenddst;
404      HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_DESTBLEND, blenddst);
405      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result);
406   }
407}
408
409void renderer::reset_render_states()
410{
411   // this ensures subsequent calls to the above setters will force-update the data
412   m_last_texture = (texture_info *)~0;
413   m_last_filter = -1;
414   m_last_blendenable = -1;
415   m_last_blendop = -1;
416   m_last_blendsrc = -1;
417   m_last_blenddst = -1;
418   m_last_wrap = (D3DTEXTUREADDRESS)-1;
419}
420
421texture_manager::texture_manager(renderer *d3d)
422{
423   m_renderer = d3d;
424
425   m_texlist = NULL;
426   m_vector_texture = NULL;
427   m_default_texture = NULL;
428
429   // check for dynamic texture support
430   DWORD tempcaps;
431   HRESULT result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_CAPS2, &tempcaps);
432   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
433   m_dynamic_supported = ((tempcaps & D3DCAPS2_DYNAMICTEXTURES) != 0);
434   if (m_dynamic_supported) osd_printf_verbose("Direct3D: Using dynamic textures\n");
435
436   // check for stretchrect support
437   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_STRETCH_RECT_FILTER, &tempcaps);
438   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
439   m_stretch_supported = ((tempcaps & D3DPTFILTERCAPS_MAGFPOINT) != 0);
440   if (m_stretch_supported && video_config.prescale > 1) osd_printf_verbose("Direct3D: Using StretchRect for prescaling\n");
441
442   // get texture caps
443   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_TEXTURE_CAPS, &m_texture_caps);
444   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
445   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_MAX_TEXTURE_ASPECT, &m_texture_max_aspect);
446   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
447   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_MAX_TEXTURE_WIDTH, &m_texture_max_width);
448   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
449   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_MAX_TEXTURE_HEIGHT, &m_texture_max_height);
450   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
451
452   // pick a YUV texture format
453   m_yuv_format = D3DFMT_UYVY;
454   result = (*d3dintf->d3d.check_device_format)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, d3d->get_pixel_format(), 0, D3DRTYPE_TEXTURE, D3DFMT_UYVY);
455   if (result != D3D_OK)
456   {
457      m_yuv_format = D3DFMT_YUY2;
458      result = (*d3dintf->d3d.check_device_format)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, d3d->get_pixel_format(), 0, D3DRTYPE_TEXTURE, D3DFMT_YUY2);
459      if (result != D3D_OK)
460         m_yuv_format = D3DFMT_A8R8G8B8;
461   }
462   osd_printf_verbose("Direct3D: YUV format = %s\n", (m_yuv_format == D3DFMT_YUY2) ? "YUY2" : (m_yuv_format == D3DFMT_UYVY) ? "UYVY" : "RGB");
463
464   // set the max texture size
465   d3d->window().target()->set_max_texture_size(m_texture_max_width, m_texture_max_height);
466   osd_printf_verbose("Direct3D: Max texture size = %dx%d\n", (int)m_texture_max_width, (int)m_texture_max_height);
467}
468
469texture_manager::~texture_manager()
470{
471}
472
473void texture_manager::create_resources()
474{
475   // experimental: load a PNG to use for vector rendering; it is treated
476   // as a brightness map
477   emu_file file(m_renderer->window().machine().options().art_path(), OPEN_FLAG_READ);
478   render_load_png(m_vector_bitmap, file, NULL, "vector.png");
479   if (m_vector_bitmap.valid())
480   {
481      m_vector_bitmap.fill(rgb_t(0xff,0xff,0xff,0xff));
482      render_load_png(m_vector_bitmap, file, NULL, "vector.png", true);
483   }
484
485   m_default_bitmap.allocate(8, 8);
486   m_default_bitmap.fill(rgb_t(0xff,0xff,0xff,0xff));
487
488   if (m_default_bitmap.valid())
489   {
490      render_texinfo texture;
491
492      // fake in the basic data so it looks like it came from render.c
493      texture.base = m_default_bitmap.raw_pixptr(0);
494      texture.rowpixels = m_default_bitmap.rowpixels();
495      texture.width = m_default_bitmap.width();
496      texture.height = m_default_bitmap.height();
497      texture.palette = NULL;
498      texture.seqid = 0;
499
500      // now create it
501      m_default_texture = global_alloc(texture_info(this, &texture, m_renderer->window().prescale(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32)));
502   }
503
504   // experimental: if we have a vector bitmap, create a texture for it
505   if (m_vector_bitmap.valid())
506   {
507      render_texinfo texture;
508
509      // fake in the basic data so it looks like it came from render.c
510      texture.base = &m_vector_bitmap.pix32(0);
511      texture.rowpixels = m_vector_bitmap.rowpixels();
512      texture.width = m_vector_bitmap.width();
513      texture.height = m_vector_bitmap.height();
514      texture.palette = NULL;
515      texture.seqid = 0;
516
517      // now create it
518      m_vector_texture = global_alloc(texture_info(this, &texture, m_renderer->window().prescale(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32)));
519   }
520}
521
522void texture_manager::delete_resources()
523{
524   // is part of m_texlist and will be free'd there
525   //global_free(m_default_texture);
526   m_default_texture = NULL;
527
528   //global_free(m_vector_texture);
529   m_vector_texture = NULL;
530
531   // free all textures
532   while (m_texlist != NULL)
533   {
534      texture_info *tex = m_texlist;
535      m_texlist = tex->get_next();
536      global_free(tex);
537   }
538}
539
540UINT32 texture_manager::texture_compute_hash(const render_texinfo *texture, UINT32 flags)
541{
542   return (FPTR)texture->base ^ (flags & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK));
543}
544
545texture_info *texture_manager::find_texinfo(const render_texinfo *texinfo, UINT32 flags)
546{
547   UINT32 hash = texture_compute_hash(texinfo, flags);
548   texture_info *texture;
549
550   // find a match
551   for (texture = m_renderer->get_texture_manager()->get_texlist(); texture != NULL; texture = texture->get_next())
552   {
553      UINT32 test_screen = (UINT32)texture->get_texinfo().osddata >> 1;
554      UINT32 test_page = (UINT32)texture->get_texinfo().osddata & 1;
555      UINT32 prim_screen = (UINT32)texinfo->osddata >> 1;
556      UINT32 prim_page = (UINT32)texinfo->osddata & 1;
557      if (test_screen != prim_screen || test_page != prim_page)
558      {
559         continue;
560      }
561
562      if (texture->get_hash() == hash &&
563         texture->get_texinfo().base == texinfo->base &&
564         texture->get_texinfo().width == texinfo->width &&
565         texture->get_texinfo().height == texinfo->height &&
566         ((texture->get_flags() ^ flags) & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) == 0)
567      {
568         // Reject a texture if it belongs to an out-of-date render target, so as to cause the HLSL system to re-cache
569         if (m_renderer->get_shaders()->enabled() && texinfo->width != 0 && texinfo->height != 0 && (flags & PRIMFLAG_SCREENTEX_MASK) != 0)
570         {
571            if (m_renderer->get_shaders()->find_render_target(texture) != NULL)
572            {
573               return texture;
574            }
575         }
576         else
577         {
578            return texture;
579         }
580      }
581   }
582
583   // Nothing found, check if we need to unregister something with HLSL
584   if (m_renderer->get_shaders()->enabled())
585   {
586      if (texinfo->width == 0 || texinfo->height == 0)
587      {
588         return NULL;
589      }
590
591      UINT32 prim_screen = texinfo->osddata >> 1;
592      UINT32 prim_page = texinfo->osddata & 1;
593
594      for (texture = m_renderer->get_texture_manager()->get_texlist(); texture != NULL; texture = texture->get_next())
595      {
596         UINT32 test_screen = texture->get_texinfo().osddata >> 1;
597         UINT32 test_page = texture->get_texinfo().osddata & 1;
598         if (test_screen != prim_screen || test_page != prim_page)
599         {
600            continue;
601         }
602
603         // Clear out our old texture reference
604         if (texture->get_hash() == hash &&
605            texture->get_texinfo().base == texinfo->base &&
606            ((texture->get_flags() ^ flags) & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) == 0 &&
607            (texture->get_texinfo().width != texinfo->width ||
608               texture->get_texinfo().height != texinfo->height))
609         {
610            m_renderer->get_shaders()->remove_render_target(texture);
611         }
612      }
613   }
614
615   return NULL;
616}
617
618renderer::renderer(osd_window *window)
619   : osd_renderer(window, FLAG_NONE)
620{
621   m_device = NULL;
622   m_restarting = false;
623   m_shaders = NULL;
624   m_numverts = 0;
625   m_numpolys = 0;
626   m_vertexbuf = NULL;
627   m_lockedbuf = NULL;
628   m_vectorbatch = NULL;
629   m_last_texture = NULL;
630   m_hlsl_buf = NULL;
631   m_texture_manager = NULL;
632}
633
634int renderer::initialize()
635{
636   // configure the adapter for the mode we want
637   if (config_adapter_mode())
638      return false;
639
640   // create the device immediately for the full screen case (defer for window mode)
641   if (window().fullscreen() && device_create(window().m_focus_hwnd))
642      return false;
643
644   return true;
645}
646
647int renderer::pre_window_draw_check()
648{
649   // if we're in the middle of resizing, leave things alone
650   if (window().m_resize_state == RESIZE_STATE_RESIZING)
651      return 0;
652
653   // if we're restarting the renderer, leave things alone
654   if (m_restarting)
655   {
656      m_shaders->toggle();
657
658      // free all existing resources and re-create
659      device_delete_resources();
660      device_create_resources();
661
662      m_restarting = false;
663   }
664
665   // if we have a device, check the cooperative level
666   if (m_device != NULL)
667   {
668      if (device_test_cooperative())
669      {
670         return 1;
671      }
672   }
673
674   // in window mode, we need to track the window size
675   if (!window().fullscreen() || m_device == NULL)
676   {
677      // if the size changes, skip this update since the render target will be out of date
678      if (update_window_size())
679         return 0;
680
681      // if we have no device, after updating the size, return an error so GDI can try
682      if (m_device == NULL)
683         return 1;
684   }
685
686   return -1;
687}
688
689void texture_manager::update_textures()
690{
691   for (render_primitive *prim = m_renderer->window().m_primlist->first(); prim != NULL; prim = prim->next())
692   {
693      if (prim->texture.base != NULL)
694      {
695         texture_info *texture = find_texinfo(&prim->texture, prim->flags);
696         if (texture == NULL)
697         {
698            // if there isn't one, create a new texture
699            global_alloc(texture_info(this, &prim->texture, m_renderer->window().prescale(), prim->flags));
700         }
701         else
702         {
703            // if there is one, but with a different seqid, copy the data
704            if (texture->get_texinfo().seqid != prim->texture.seqid)
705            {
706               texture->set_data(&prim->texture, prim->flags);
707               texture->get_texinfo().seqid = prim->texture.seqid;
708            }
709         }
710      }
711      else if(m_renderer->get_shaders()->vector_enabled() && PRIMFLAG_GET_VECTORBUF(prim->flags))
712      {
713         if (!m_renderer->get_shaders()->get_vector_target())
714         {
715            m_renderer->get_shaders()->create_vector_target(prim);
716         }
717      }
718   }
719}
720
721void renderer::begin_frame()
722{
723   HRESULT result = (*d3dintf->device.clear)(m_device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0);
724   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result);
725
726   m_shaders->begin_frame();
727
728   window().m_primlist->acquire_lock();
729
730   // first update any textures
731   m_texture_manager->update_textures();
732
733   // begin the scene
734   mtlog_add("drawd3d_window_draw: begin_scene");
735   result = (*d3dintf->device.begin_scene)(m_device);
736   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device begin_scene call\n", (int)result);
737
738   m_lockedbuf = NULL;
739
740   if(m_shaders->enabled())
741   {
742      m_hlsl_buf = (void*)mesh_alloc(6);
743      m_shaders->init_fsfx_quad(m_hlsl_buf);
744   }
745
746   m_line_count = 0;
747
748   // loop over primitives
749   for (render_primitive *prim = window().m_primlist->first(); prim != NULL; prim = prim->next())
750      if (prim->type == render_primitive::LINE && PRIMFLAG_GET_VECTOR(prim->flags))
751         m_line_count++;
752}
753
754void renderer::process_primitives()
755{
756   // Rotating index for vector time offsets
757   for (render_primitive *prim = window().m_primlist->first(); prim != NULL; prim = prim->next())
758   {
759      switch (prim->type)
760      {
761         case render_primitive::LINE:
762            if (PRIMFLAG_GET_VECTOR(prim->flags))
763            {
764               if (m_line_count > 0)
765                  batch_vectors();
766               else
767                  continue;
768            }
769            else
770            {
771               draw_line(prim);
772            }
773            break;
774
775         case render_primitive::QUAD:
776            draw_quad(prim);
777            break;
778
779         default:
780            throw emu_fatalerror("Unexpected render_primitive type");
781      }
782   }
783}
784
785void renderer::end_frame()
786{
787   window().m_primlist->release_lock();
788
789   // flush any pending polygons
790   primitive_flush_pending();
791
792   m_shaders->end_frame();
793
794   // finish the scene
795   HRESULT result = (*d3dintf->device.end_scene)(m_device);
796   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device end_scene call\n", (int)result);
797
798   // present the current buffers
799   result = (*d3dintf->device.present)(m_device, NULL, NULL, NULL, NULL, 0);
800   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device present call\n", (int)result);
801}
802
803//============================================================
804//  device_create
805//============================================================
806
807int renderer::device_create(HWND device_hwnd)
808{
809   // if a device exists, free it
810   if (m_device != NULL)
811   {
812      device_delete();
813   }
814
815   // create shader options only once
816   if (m_shaders_options == NULL)
817   {
818      m_shaders_options = (hlsl_options*)global_alloc_clear(hlsl_options);
819   }
820
821   // verify the caps
822   int verify = device_verify_caps();
823   if (verify == 2)
824   {
825      osd_printf_error("Error: Device does not meet minimum requirements for Direct3D rendering\n");
826      return 1;
827   }
828   if (verify == 1)
829   {
830      osd_printf_warning("Warning: Device may not perform well for Direct3D rendering\n");
831   }
832
833   // verify texture formats
834   HRESULT result = (*d3dintf->d3d.check_device_format)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, 0, D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8);
835   if (result != D3D_OK)
836   {
837      osd_printf_error("Error: A8R8G8B8 format textures not supported\n");
838      return 1;
839   }
840
841   m_texture_manager = global_alloc(texture_manager(this));
842
843try_again:
844   // try for XRGB first
845   m_screen_format = D3DFMT_X8R8G8B8;
846   result = (*d3dintf->d3d.check_device_format)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, m_texture_manager->is_dynamic_supported() ? D3DUSAGE_DYNAMIC : 0, D3DRTYPE_TEXTURE, m_screen_format);
847   if (result != D3D_OK)
848   {
849      // if not, try for ARGB
850      m_screen_format = D3DFMT_A8R8G8B8;
851      result = (*d3dintf->d3d.check_device_format)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, m_texture_manager->is_dynamic_supported() ? D3DUSAGE_DYNAMIC : 0, D3DRTYPE_TEXTURE, m_screen_format);
852      if (result != D3D_OK && m_texture_manager->is_dynamic_supported())
853      {
854         m_texture_manager->set_dynamic_supported(FALSE);
855         goto try_again;
856      }
857      if (result != D3D_OK)
858      {
859         osd_printf_error("Error: unable to configure a screen texture format\n");
860         return 1;
861      }
862   }
863
864   // initialize the D3D presentation parameters
865   memset(&m_presentation, 0, sizeof(m_presentation));
866   m_presentation.BackBufferWidth               = m_width;
867   m_presentation.BackBufferHeight              = m_height;
868   m_presentation.BackBufferFormat              = m_pixformat;
869   m_presentation.BackBufferCount               = video_config.triplebuf ? 2 : 1;
870   m_presentation.MultiSampleType               = D3DMULTISAMPLE_NONE;
871   m_presentation.SwapEffect                    = D3DSWAPEFFECT_DISCARD;
872   m_presentation.hDeviceWindow                 = window().m_hwnd;
873   m_presentation.Windowed                      = !window().fullscreen() || window().win_has_menu();
874   m_presentation.EnableAutoDepthStencil        = FALSE;
875   m_presentation.AutoDepthStencilFormat        = D3DFMT_D16;
876   m_presentation.Flags                         = 0;
877   m_presentation.FullScreen_RefreshRateInHz    = m_refresh;
878   m_presentation.PresentationInterval          = ((video_config.triplebuf && window().fullscreen()) ||
879                                       video_config.waitvsync || video_config.syncrefresh) ?
880                                       D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
881
882   // create the D3D device
883   result = (*d3dintf->d3d.create_device)(d3dintf, m_adapter, D3DDEVTYPE_HAL, device_hwnd,
884               D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &m_presentation, &m_device);
885   if (result != D3D_OK)
886   {
887      // if we got a "DEVICELOST" error, it may be transitory; count it and only fail if
888      // we exceed a threshold
889      if (result == D3DERR_DEVICELOST)
890      {
891         m_create_error_count++;
892         if (m_create_error_count < 10)
893         {
894            return 0;
895         }
896      }
897
898      //  fatal error if we just can't do it
899      osd_printf_error("Unable to create the Direct3D device (%08X)\n", (UINT32)result);
900      return 1;
901   }
902   m_create_error_count = 0;
903   osd_printf_verbose("Direct3D: Device created at %dx%d\n", m_width, m_height);
904
905   // set the gamma if we need to
906   if (window().fullscreen())
907   {
908      // only set the gamma if it's not 1.0f
909      windows_options &options = downcast<windows_options &>(window().machine().options());
910      float brightness = options.full_screen_brightness();
911      float contrast = options.full_screen_contrast();
912      float gamma = options.full_screen_gamma();
913      if (brightness != 1.0f || contrast != 1.0f || gamma != 1.0f)
914      {
915         // warn if we can't do it
916         if (!m_gamma_supported)
917         {
918            osd_printf_warning("Direct3D: Warning - device does not support full screen gamma correction.\n");
919         }
920         else
921         {
922            // create a standard ramp and set it
923            D3DGAMMARAMP ramp;
924            for (int i = 0; i < 256; i++)
925            {
926               ramp.red[i] = ramp.green[i] = ramp.blue[i] = apply_brightness_contrast_gamma(i, brightness, contrast, gamma) << 8;
927            }
928            (*d3dintf->device.set_gamma_ramp)(m_device, 0, &ramp);
929         }
930      }
931   }
932
933   int ret = m_shaders->create_resources(false);
934   if (ret != 0)
935      return ret;
936
937   return device_create_resources();
938}
939
940
941//============================================================
942//  device_create_resources
943//============================================================
944
945int renderer::device_create_resources()
946{
947   // allocate a vertex buffer to use
948   HRESULT result = (*d3dintf->device.create_vertex_buffer)(m_device,
949            sizeof(vertex) * VERTEX_BUFFER_SIZE,
950            D3DUSAGE_DYNAMIC | D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_WRITEONLY,
951            VERTEX_BASE_FORMAT | ((m_shaders->enabled() && d3dintf->post_fx_available) ? D3DFVF_XYZW : D3DFVF_XYZRHW),
952            D3DPOOL_DEFAULT, &m_vertexbuf);
953   if (result != D3D_OK)
954   {
955      osd_printf_error("Error creating vertex buffer (%08X)\n", (UINT32)result);
956      return 1;
957   }
958
959   // set the vertex format
960   result = (*d3dintf->device.set_vertex_format)(m_device, (D3DFORMAT)(VERTEX_BASE_FORMAT | ((m_shaders->enabled() &&
961      d3dintf->post_fx_available) ? D3DFVF_XYZW : D3DFVF_XYZRHW)));
962   if (result != D3D_OK)
963   {
964      osd_printf_error("Error setting vertex format (%08X)\n", (UINT32)result);
965      return 1;
966   }
967
968   // set the fixed render state
969   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ZENABLE, D3DZB_FALSE);
970   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_FILLMODE, D3DFILL_SOLID);
971   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_SHADEMODE, D3DSHADE_FLAT);
972   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ZWRITEENABLE, FALSE);
973   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHATESTENABLE, TRUE);
974   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_LASTPIXEL, TRUE);
975   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_CULLMODE, D3DCULL_NONE);
976   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ZFUNC, D3DCMP_LESS);
977   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHAREF, 0);
978   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHAFUNC, D3DCMP_GREATER);
979   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_DITHERENABLE, FALSE);
980   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_FOGENABLE, FALSE);
981   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_SPECULARENABLE, FALSE);
982   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_STENCILENABLE, FALSE);
983   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_WRAP0, FALSE);
984   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_CLIPPING, TRUE);
985   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_LIGHTING, FALSE);
986   result = (*d3dintf->device.set_render_state)(m_device, D3DRS_COLORVERTEX, TRUE);
987
988   result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, D3DTSS_COLOROP, D3DTOP_MODULATE);
989   result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
990   result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, D3DTSS_COLOROP, D3DTOP_MODULATE);
991   result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
992
993   // reset the local states to force updates
994   reset_render_states();
995
996   // clear the buffer
997   result = (*d3dintf->device.clear)(m_device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0);
998   result = (*d3dintf->device.present)(m_device, NULL, NULL, NULL, NULL, 0);
999
1000   m_texture_manager->create_resources();
1001
1002   return 0;
1003}
1004
1005
1006//============================================================
1007//  device_delete
1008//============================================================
1009
1010renderer::~renderer()
1011{
1012   if (m_shaders_options != NULL)
1013   {
1014      global_free(m_shaders_options);
1015   }
1016   m_shaders_options = NULL;
1017
1018   device_delete();
1019}
1020
1021void renderer::device_delete()
1022{
1023   if (m_shaders != NULL)
1024   {
1025      // free our effects
1026      m_shaders->delete_resources(false);
1027
1028      // delete the HLSL interface
1029      global_free(m_shaders);
1030   }
1031
1032   // free our base resources
1033   device_delete_resources();
1034
1035   if (m_texture_manager != NULL)
1036   {
1037      global_free(m_texture_manager);
1038   }
1039   m_texture_manager = NULL;
1040
1041   // free the device itself
1042   if (m_device != NULL)
1043   {
1044      (*d3dintf->device.reset)(m_device, &m_presentation);
1045      (*d3dintf->device.release)(m_device);
1046   }
1047   m_device = NULL;
1048}
1049
1050
1051//============================================================
1052//  device_delete_resources
1053//============================================================
1054
1055void renderer::device_delete_resources()
1056{
1057   if (m_texture_manager != NULL)
1058      m_texture_manager->delete_resources();
1059   // free the vertex buffer
1060   if (m_vertexbuf != NULL)
1061      (*d3dintf->vertexbuf.release)(m_vertexbuf);
1062   m_vertexbuf = NULL;
1063}
1064
1065
1066//============================================================
1067//  device_verify_caps
1068//============================================================
1069
1070int renderer::device_verify_caps()
1071{
1072   int retval = 0;
1073
1074   m_shaders = (shaders*)global_alloc_clear(shaders);
1075   m_shaders->init(d3dintf, &window().machine(), this);
1076
1077   DWORD tempcaps;
1078   HRESULT result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_MAX_PS30_INSN_SLOTS, &tempcaps);
1079   if (result != D3D_OK) osd_printf_verbose("Direct3D Error %08X during get_caps_dword call\n", (int)result);
1080   if (tempcaps < 512)
1081   {
1082      osd_printf_verbose("Direct3D: Warning - Device does not support Pixel Shader 3.0, falling back to non-PS rendering\n");
1083      d3dintf->post_fx_available = false;
1084   }
1085
1086   // verify presentation capabilities
1087   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_PRESENTATION_INTERVALS, &tempcaps);
1088   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
1089   if (!(tempcaps & D3DPRESENT_INTERVAL_IMMEDIATE))
1090   {
1091      osd_printf_verbose("Direct3D: Error - Device does not support immediate presentations\n");
1092      retval = 2;
1093   }
1094   if (!(tempcaps & D3DPRESENT_INTERVAL_ONE))
1095   {
1096      osd_printf_verbose("Direct3D: Error - Device does not support per-refresh presentations\n");
1097      retval = 2;
1098   }
1099
1100   // verify device capabilities
1101   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_DEV_CAPS, &tempcaps);
1102   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
1103   if (!(tempcaps & D3DDEVCAPS_CANRENDERAFTERFLIP))
1104   {
1105      osd_printf_verbose("Direct3D: Warning - Device does not support queued rendering after a page flip\n");
1106      retval = 1;
1107   }
1108   if (!(tempcaps & D3DDEVCAPS_HWRASTERIZATION))
1109   {
1110      osd_printf_verbose("Direct3D: Warning - Device does not support hardware rasterization\n");
1111      retval = 1;
1112   }
1113
1114   // verify texture operation capabilities
1115   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_TEXTURE_OP_CAPS, &tempcaps);
1116   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
1117   if (!(tempcaps & D3DTEXOPCAPS_MODULATE))
1118   {
1119      osd_printf_verbose("Direct3D: Warning - Device does not support texture modulation\n");
1120      retval = 1;
1121   }
1122
1123   // set a simpler flag to indicate mod2x and mod4x texture modes
1124   m_mod2x_supported = ((tempcaps & D3DTEXOPCAPS_MODULATE2X) != 0);
1125   m_mod4x_supported = ((tempcaps & D3DTEXOPCAPS_MODULATE4X) != 0);
1126
1127   result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_CAPS2, &tempcaps);
1128   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
1129   m_gamma_supported = ((tempcaps & D3DCAPS2_FULLSCREENGAMMA) != 0);
1130
1131   return retval;
1132}
1133
1134
1135//============================================================
1136//  device_test_cooperative
1137//============================================================
1138
1139int renderer::device_test_cooperative()
1140{
1141   // check our current status; if we lost the device, punt to GDI
1142   HRESULT result = (*d3dintf->device.test_cooperative_level)(m_device);
1143   if (result == D3DERR_DEVICELOST)
1144      return 1;
1145
1146   // if we're able to reset ourselves, try it
1147   if (result == D3DERR_DEVICENOTRESET)
1148   {
1149      osd_printf_verbose("Direct3D: resetting device\n");
1150
1151      // free all existing resources and call reset on the device
1152      //device_delete();
1153      device_delete_resources();
1154      m_shaders->delete_resources(true);
1155      result = (*d3dintf->device.reset)(m_device, &m_presentation);
1156
1157      // if it didn't work, punt to GDI
1158      if (result != D3D_OK)
1159      {
1160         osd_printf_error("Unable to reset, result %08x\n", (UINT32)result);
1161         return 1;
1162      }
1163
1164      // try to create the resources again; if that didn't work, delete the whole thing
1165      if (device_create_resources())
1166      {
1167         osd_printf_verbose("Direct3D: failed to recreate resources for device; failing permanently\n");
1168         device_delete();
1169         return 1;
1170      }
1171
1172      if (m_shaders->create_resources(true))
1173      {
1174         osd_printf_verbose("Direct3D: failed to recreate HLSL resources for device; failing permanently\n");
1175         device_delete();
1176         return 1;
1177      }
1178   }
1179   return 0;
1180}
1181
1182
1183//============================================================
1184//  config_adapter_mode
1185//============================================================
1186
1187int renderer::config_adapter_mode()
1188{
1189   adapter_identifier identifier;
1190
1191   // choose the monitor number
1192   m_adapter = get_adapter_for_monitor();
1193
1194   // get the identifier
1195   HRESULT result = (*d3dintf->d3d.get_adapter_identifier)(d3dintf, m_adapter, 0, &identifier);
1196   if (result != D3D_OK)
1197   {
1198      osd_printf_error("Error getting identifier for adapter #%d\n", m_adapter);
1199      return 1;
1200   }
1201   osd_printf_verbose("Direct3D: Configuring adapter #%d = %s\n", m_adapter, identifier.Description);
1202
1203   // get the current display mode
1204   result = (*d3dintf->d3d.get_adapter_display_mode)(d3dintf, m_adapter, &m_origmode);
1205   if (result != D3D_OK)
1206   {
1207      osd_printf_error("Error getting mode for adapter #%d\n", m_adapter);
1208      return 1;
1209   }
1210
1211   // choose a resolution: window mode case
1212   if (!window().fullscreen() || !video_config.switchres || window().win_has_menu())
1213   {
1214      RECT client;
1215
1216      // bounds are from the window client rect
1217      GetClientRectExceptMenu(window().m_hwnd, &client, window().fullscreen());
1218      m_width = client.right - client.left;
1219      m_height = client.bottom - client.top;
1220
1221      // pix format is from the current mode
1222      m_pixformat = m_origmode.Format;
1223      m_refresh = 0;
1224
1225      // make sure it's a pixel format we can get behind
1226      if (m_pixformat != D3DFMT_X1R5G5B5 && m_pixformat != D3DFMT_R5G6B5 && m_pixformat != D3DFMT_X8R8G8B8)
1227      {
1228         osd_printf_error("Device %s currently in an unsupported mode\n", window().monitor()->devicename());
1229         return 1;
1230      }
1231   }
1232
1233   // choose a resolution: full screen mode case
1234   else
1235   {
1236      // default to the current mode exactly
1237      m_width = m_origmode.Width;
1238      m_height = m_origmode.Height;
1239      m_pixformat = m_origmode.Format;
1240      m_refresh = m_origmode.RefreshRate;
1241
1242      // if we're allowed to switch resolutions, override with something better
1243      if (video_config.switchres)
1244         pick_best_mode();
1245   }
1246
1247   // see if we can handle the device type
1248   result = (*d3dintf->d3d.check_device_type)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, m_pixformat, !window().fullscreen());
1249   if (result != D3D_OK)
1250   {
1251      osd_printf_error("Proposed video mode not supported on device %s\n", window().monitor()->devicename());
1252      return 1;
1253   }
1254   return 0;
1255}
1256
1257
1258//============================================================
1259//  get_adapter_for_monitor
1260//============================================================
1261
1262int renderer::get_adapter_for_monitor()
1263{
1264   int maxadapter = (*d3dintf->d3d.get_adapter_count)(d3dintf);
1265
1266   // iterate over adapters until we error or find a match
1267   for (int adapternum = 0; adapternum < maxadapter; adapternum++)
1268   {
1269      // get the monitor for this adapter
1270      HMONITOR curmonitor = (*d3dintf->d3d.get_adapter_monitor)(d3dintf, adapternum);
1271
1272      // if we match the proposed monitor, this is it
1273      if (curmonitor == *((HMONITOR *)window().monitor()->oshandle()))
1274      {
1275         return adapternum;
1276      }
1277   }
1278
1279   // default to the default
1280   return D3DADAPTER_DEFAULT;
1281}
1282
1283
1284//============================================================
1285//  pick_best_mode
1286//============================================================
1287
1288void renderer::pick_best_mode()
1289{
1290   double target_refresh = 60.0;
1291   INT32 minwidth, minheight;
1292   float best_score = 0.0f;
1293
1294   // determine the refresh rate of the primary screen
1295   const screen_device *primary_screen = window().machine().config().first_screen();
1296   if (primary_screen != NULL)
1297   {
1298      target_refresh = ATTOSECONDS_TO_HZ(primary_screen->refresh_attoseconds());
1299   }
1300
1301   // determine the minimum width/height for the selected target
1302   // note: technically we should not be calling this from an alternate window
1303   // thread; however, it is only done during init time, and the init code on
1304   // the main thread is waiting for us to finish, so it is safe to do so here
1305   window().target()->compute_minimum_size(minwidth, minheight);
1306
1307   // use those as the target for now
1308   INT32 target_width = minwidth;
1309   INT32 target_height = minheight;
1310
1311   // determine the maximum number of modes
1312   int maxmodes = (*d3dintf->d3d.get_adapter_mode_count)(d3dintf, m_adapter, D3DFMT_X8R8G8B8);
1313
1314   // enumerate all the video modes and find the best match
1315   osd_printf_verbose("Direct3D: Selecting video mode...\n");
1316   for (int modenum = 0; modenum < maxmodes; modenum++)
1317   {
1318      // check this mode
1319      D3DDISPLAYMODE mode;
1320      HRESULT result = (*d3dintf->d3d.enum_adapter_modes)(d3dintf, m_adapter, D3DFMT_X8R8G8B8, modenum, &mode);
1321      if (result != D3D_OK)
1322         break;
1323
1324      // skip non-32 bit modes
1325      if (mode.Format != D3DFMT_X8R8G8B8)
1326         continue;
1327
1328      // compute initial score based on difference between target and current
1329      float size_score = 1.0f / (1.0f + fabs((float)(mode.Width - target_width)) + fabs((float)(mode.Height - target_height)));
1330
1331      // if the mode is too small, give a big penalty
1332      if (mode.Width < minwidth || mode.Height < minheight)
1333         size_score *= 0.01f;
1334
1335      // if mode is smaller than we'd like, it only scores up to 0.1
1336      if (mode.Width < target_width || mode.Height < target_height)
1337         size_score *= 0.1f;
1338
1339      // if we're looking for a particular mode, that's a winner
1340      if (mode.Width == window().m_win_config.width && mode.Height == window().m_win_config.height)
1341         size_score = 2.0f;
1342
1343      // compute refresh score
1344      float refresh_score = 1.0f / (1.0f + fabs((double)mode.RefreshRate - target_refresh));
1345
1346      // if refresh is smaller than we'd like, it only scores up to 0.1
1347      if ((double)mode.RefreshRate < target_refresh)
1348         refresh_score *= 0.1f;
1349
1350      // if we're looking for a particular refresh, make sure it matches
1351      if (mode.RefreshRate == window().m_win_config.refresh)
1352         refresh_score = 2.0f;
1353
1354      // weight size and refresh equally
1355      float final_score = size_score + refresh_score;
1356
1357      // best so far?
1358      osd_printf_verbose("  %4dx%4d@%3dHz -> %f\n", mode.Width, mode.Height, mode.RefreshRate, final_score * 1000.0f);
1359      if (final_score > best_score)
1360      {
1361         best_score = final_score;
1362         m_width = mode.Width;
1363         m_height = mode.Height;
1364         m_pixformat = mode.Format;
1365         m_refresh = mode.RefreshRate;
1366      }
1367   }
1368   osd_printf_verbose("Direct3D: Mode selected = %4dx%4d@%3dHz\n", m_width, m_height, m_refresh);
1369}
1370
1371
1372//============================================================
1373//  update_window_size
1374//============================================================
1375
1376int renderer::update_window_size()
1377{
1378   // get the current window bounds
1379   RECT client;
1380   GetClientRectExceptMenu(window().m_hwnd, &client, window().fullscreen());
1381
1382   // if we have a device and matching width/height, nothing to do
1383   if (m_device != NULL && rect_width(&client) == m_width && rect_height(&client) == m_height)
1384   {
1385      // clear out any pending resizing if the area didn't change
1386      if (window().m_resize_state == RESIZE_STATE_PENDING)
1387         window().m_resize_state = RESIZE_STATE_NORMAL;
1388      return FALSE;
1389   }
1390
1391   // if we're in the middle of resizing, leave it alone as well
1392   if (window().m_resize_state == RESIZE_STATE_RESIZING)
1393      return FALSE;
1394
1395   // set the new bounds and create the device again
1396   m_width = rect_width(&client);
1397   m_height = rect_height(&client);
1398   if (device_create(window().m_focus_hwnd))
1399      return FALSE;
1400
1401   // reset the resize state to normal, and indicate we made a change
1402   window().m_resize_state = RESIZE_STATE_NORMAL;
1403   return TRUE;
1404}
1405
1406
1407//============================================================
1408//  batch_vectors
1409//============================================================
1410
1411void renderer::batch_vectors()
1412{
1413   windows_options &options = downcast<windows_options &>(window().machine().options());
1414
1415   int vector_size = (options.antialias() ? 24 : 6);
1416   m_vectorbatch = mesh_alloc(m_line_count * vector_size);
1417   m_batchindex = 0;
1418
1419   static int start_index = 0;
1420   int line_index = 0;
1421   float period = options.screen_vector_time_period();
1422   UINT32 cached_flags = 0;
1423   for (render_primitive *prim = window().m_primlist->first(); prim != NULL; prim = prim->next())
1424   {
1425      switch (prim->type)
1426      {
1427         case render_primitive::LINE:
1428            if (PRIMFLAG_GET_VECTOR(prim->flags))
1429            {
1430               if (period == 0.0f || m_line_count == 0)
1431               {
1432                  batch_vector(prim, 1.0f);
1433               }
1434               else
1435               {
1436                  batch_vector(prim, (float)(start_index + line_index) / ((float)m_line_count * period));
1437                  line_index++;
1438               }
1439               cached_flags = prim->flags;
1440            }
1441            break;
1442
1443         default:
1444            // Skip
1445            break;
1446      }
1447   }
1448
1449   // now add a polygon entry
1450   m_poly[m_numpolys].init(D3DPT_TRIANGLELIST, m_line_count * (options.antialias() ? 8 : 2), vector_size * m_line_count, cached_flags,
1451      m_texture_manager->get_vector_texture(), D3DTOP_MODULATE, 0.0f, 1.0f, 0.0f, 0.0f);
1452   m_numpolys++;
1453
1454   start_index += (int)((float)line_index * period);
1455   if (m_line_count > 0)
1456   {
1457      start_index %= m_line_count;
1458   }
1459
1460   m_line_count = 0;
1461}
1462
1463void renderer::batch_vector(const render_primitive *prim, float line_time)
1464{
1465   // compute the effective width based on the direction of the line
1466   float effwidth = prim->width;
1467   if (effwidth < 0.5f)
1468   {
1469      effwidth = 0.5f;
1470   }
1471
1472   // determine the bounds of a quad to draw this line
1473   render_bounds b0, b1;
1474   render_line_to_quad(&prim->bounds, effwidth, &b0, &b1);
1475
1476   // iterate over AA steps
1477   for (const line_aa_step *step = PRIMFLAG_GET_ANTIALIAS(prim->flags) ? line_aa_4step : line_aa_1step;
1478      step->weight != 0; step++)
1479   {
1480      // get a pointer to the vertex buffer
1481      if (m_vectorbatch == NULL)
1482         return;
1483
1484      m_vectorbatch[m_batchindex + 0].x = b0.x0 + step->xoffs;
1485      m_vectorbatch[m_batchindex + 0].y = b0.y0 + step->yoffs;
1486      m_vectorbatch[m_batchindex + 1].x = b0.x1 + step->xoffs;
1487      m_vectorbatch[m_batchindex + 1].y = b0.y1 + step->yoffs;
1488      m_vectorbatch[m_batchindex + 2].x = b1.x0 + step->xoffs;
1489      m_vectorbatch[m_batchindex + 2].y = b1.y0 + step->yoffs;
1490
1491      m_vectorbatch[m_batchindex + 3].x = b0.x1 + step->xoffs;
1492      m_vectorbatch[m_batchindex + 3].y = b0.y1 + step->yoffs;
1493      m_vectorbatch[m_batchindex + 4].x = b1.x0 + step->xoffs;
1494      m_vectorbatch[m_batchindex + 4].y = b1.y0 + step->yoffs;
1495      m_vectorbatch[m_batchindex + 5].x = b1.x1 + step->xoffs;
1496      m_vectorbatch[m_batchindex + 5].y = b1.y1 + step->yoffs;
1497
1498      float dx = b1.x1 - b0.x1;
1499      float dy = b1.y1 - b0.y1;
1500      float line_length = sqrtf(dx * dx + dy * dy);
1501
1502      // determine the color of the line
1503      INT32 r = (INT32)(prim->color.r * step->weight * 255.0f);
1504      INT32 g = (INT32)(prim->color.g * step->weight * 255.0f);
1505      INT32 b = (INT32)(prim->color.b * step->weight * 255.0f);
1506      INT32 a = (INT32)(prim->color.a * 255.0f);
1507      if (r > 255 || g > 255 || b > 255)
1508      {
1509         if (r > 2*255 || g > 2*255 || b > 2*255)
1510         {
1511            r >>= 2; g >>= 2; b >>= 2;
1512         }
1513         else
1514         {
1515            r >>= 1; g >>= 1; b >>= 1;
1516         }
1517      }
1518      if (r > 255) r = 255;
1519      if (g > 255) g = 255;
1520      if (b > 255) b = 255;
1521      if (a > 255) a = 255;
1522      DWORD color = D3DCOLOR_ARGB(a, r, g, b);
1523
1524      vec2f& start = (get_vector_texture() ? get_vector_texture()->get_uvstart() : get_default_texture()->get_uvstart());
1525      vec2f& stop = (get_vector_texture() ? get_vector_texture()->get_uvstop() : get_default_texture()->get_uvstop());
1526
1527      m_vectorbatch[m_batchindex + 0].u0 = start.c.x;
1528      m_vectorbatch[m_batchindex + 0].v0 = start.c.y;
1529      m_vectorbatch[m_batchindex + 1].u0 = start.c.x;
1530      m_vectorbatch[m_batchindex + 1].v0 = stop.c.y;
1531      m_vectorbatch[m_batchindex + 2].u0 = stop.c.x;
1532      m_vectorbatch[m_batchindex + 2].v0 = start.c.y;
1533
1534      m_vectorbatch[m_batchindex + 3].u0 = start.c.x;
1535      m_vectorbatch[m_batchindex + 3].v0 = stop.c.y;
1536      m_vectorbatch[m_batchindex + 4].u0 = stop.c.x;
1537      m_vectorbatch[m_batchindex + 4].v0 = start.c.y;
1538      m_vectorbatch[m_batchindex + 5].u0 = stop.c.x;
1539      m_vectorbatch[m_batchindex + 5].v0 = stop.c.y;
1540
1541      m_vectorbatch[m_batchindex + 0].u1 = line_length;
1542      m_vectorbatch[m_batchindex + 1].u1 = line_length;
1543      m_vectorbatch[m_batchindex + 2].u1 = line_length;
1544      m_vectorbatch[m_batchindex + 3].u1 = line_length;
1545      m_vectorbatch[m_batchindex + 4].u1 = line_length;
1546      m_vectorbatch[m_batchindex + 5].u1 = line_length;
1547
1548      // set the color, Z parameters to standard values
1549      for (int i = 0; i < 6; i++)
1550      {
1551         m_vectorbatch[m_batchindex + i].z = 0.0f;
1552         m_vectorbatch[m_batchindex + i].rhw = 1.0f;
1553         m_vectorbatch[m_batchindex + i].color = color;
1554      }
1555
1556      m_batchindex += 6;
1557   }
1558}
1559
1560
1561//============================================================
1562//  draw_line
1563//============================================================
1564
1565void renderer::draw_line(const render_primitive *prim)
1566{
1567   // compute the effective width based on the direction of the line
1568   float effwidth = prim->width;
1569   if (effwidth < 0.5f)
1570   {
1571      effwidth = 0.5f;
1572   }
1573
1574   // determine the bounds of a quad to draw this line
1575   render_bounds b0, b1;
1576   render_line_to_quad(&prim->bounds, effwidth, &b0, &b1);
1577
1578   // iterate over AA steps
1579   for (const line_aa_step *step = PRIMFLAG_GET_ANTIALIAS(prim->flags) ? line_aa_4step : line_aa_1step;
1580      step->weight != 0; step++)
1581   {
1582      // get a pointer to the vertex buffer
1583      vertex *vertex = mesh_alloc(4);
1584      if (vertex == NULL)
1585         return;
1586
1587      // rotate the unit vector by 135 degrees and add to point 0
1588      vertex[0].x = b0.x0 + step->xoffs;
1589      vertex[0].y = b0.y0 + step->yoffs;
1590
1591      // rotate the unit vector by -135 degrees and add to point 0
1592      vertex[1].x = b0.x1 + step->xoffs;
1593      vertex[1].y = b0.y1 + step->yoffs;
1594
1595      // rotate the unit vector by 45 degrees and add to point 1
1596      vertex[2].x = b1.x0 + step->xoffs;
1597      vertex[2].y = b1.y0 + step->yoffs;
1598
1599      // rotate the unit vector by -45 degrees and add to point 1
1600      vertex[3].x = b1.x1 + step->xoffs;
1601      vertex[3].y = b1.y1 + step->yoffs;
1602
1603      // determine the color of the line
1604      INT32 r = (INT32)(prim->color.r * step->weight * 255.0f);
1605      INT32 g = (INT32)(prim->color.g * step->weight * 255.0f);
1606      INT32 b = (INT32)(prim->color.b * step->weight * 255.0f);
1607      INT32 a = (INT32)(prim->color.a * 255.0f);
1608      if (r > 255) r = 255;
1609      if (g > 255) g = 255;
1610      if (b > 255) b = 255;
1611      if (a > 255) a = 255;
1612      DWORD color = D3DCOLOR_ARGB(a, r, g, b);
1613
1614      vec2f& start = (get_vector_texture() ? get_vector_texture()->get_uvstart() : get_default_texture()->get_uvstart());
1615      vec2f& stop = (get_vector_texture() ? get_vector_texture()->get_uvstop() : get_default_texture()->get_uvstop());
1616
1617      vertex[0].u0 = start.c.x;
1618      vertex[0].v0 = start.c.y;
1619
1620      vertex[2].u0 = stop.c.x;
1621      vertex[2].v0 = start.c.y;
1622
1623      vertex[1].u0 = start.c.x;
1624      vertex[1].v0 = stop.c.y;
1625
1626      vertex[3].u0 = stop.c.x;
1627      vertex[3].v0 = stop.c.y;
1628
1629      // set the color, Z parameters to standard values
1630      for (int i = 0; i < 4; i++)
1631      {
1632         vertex[i].z = 0.0f;
1633         vertex[i].rhw = 1.0f;
1634         vertex[i].color = color;
1635      }
1636
1637      // now add a polygon entry
1638      m_poly[m_numpolys].init(D3DPT_TRIANGLESTRIP, 2, 4, prim->flags, get_vector_texture(),
1639                        D3DTOP_MODULATE, 0.0f, 1.0f, 0.0f, 0.0f);
1640      m_numpolys++;
1641   }
1642}
1643
1644
1645//============================================================
1646//  draw_quad
1647//============================================================
1648
1649void renderer::draw_quad(const render_primitive *prim)
1650{
1651   texture_info *texture = m_texture_manager->find_texinfo(&prim->texture, prim->flags);
1652
1653   if (texture == NULL)
1654   {
1655      texture = get_default_texture();
1656   }
1657
1658   // get a pointer to the vertex buffer
1659   vertex *vertex = mesh_alloc(4);
1660   if (vertex == NULL)
1661      return;
1662
1663   // fill in the vertexes clockwise
1664   vertex[0].x = prim->bounds.x0;
1665   vertex[0].y = prim->bounds.y0;
1666   vertex[1].x = prim->bounds.x1;
1667   vertex[1].y = prim->bounds.y0;
1668   vertex[2].x = prim->bounds.x0;
1669   vertex[2].y = prim->bounds.y1;
1670   vertex[3].x = prim->bounds.x1;
1671   vertex[3].y = prim->bounds.y1;
1672   float width = prim->bounds.x1 - prim->bounds.x0;
1673   float height = prim->bounds.y1 - prim->bounds.y0;
1674
1675   // set the texture coordinates
1676   if(texture != NULL)
1677   {
1678      vec2f& start = texture->get_uvstart();
1679      vec2f& stop = texture->get_uvstop();
1680      vec2f delta = stop - start;
1681      vertex[0].u0 = start.c.x + delta.c.x * prim->texcoords.tl.u;
1682      vertex[0].v0 = start.c.y + delta.c.y * prim->texcoords.tl.v;
1683      vertex[1].u0 = start.c.x + delta.c.x * prim->texcoords.tr.u;
1684      vertex[1].v0 = start.c.y + delta.c.y * prim->texcoords.tr.v;
1685      vertex[2].u0 = start.c.x + delta.c.x * prim->texcoords.bl.u;
1686      vertex[2].v0 = start.c.y + delta.c.y * prim->texcoords.bl.v;
1687      vertex[3].u0 = start.c.x + delta.c.x * prim->texcoords.br.u;
1688      vertex[3].v0 = start.c.y + delta.c.y * prim->texcoords.br.v;
1689   }
1690
1691   // determine the color, allowing for over modulation
1692   INT32 r = (INT32)(prim->color.r * 255.0f);
1693   INT32 g = (INT32)(prim->color.g * 255.0f);
1694   INT32 b = (INT32)(prim->color.b * 255.0f);
1695   INT32 a = (INT32)(prim->color.a * 255.0f);
1696   DWORD modmode = D3DTOP_MODULATE;
1697   if (texture != NULL)
1698   {
1699      if (m_mod2x_supported && (r > 255 || g > 255 || b > 255))
1700      {
1701         if (m_mod4x_supported && (r > 2*255 || g > 2*255 || b > 2*255))
1702         {
1703            r >>= 2; g >>= 2; b >>= 2;
1704            modmode = D3DTOP_MODULATE4X;
1705         }
1706         else
1707         {
1708            r >>= 1; g >>= 1; b >>= 1;
1709            modmode = D3DTOP_MODULATE2X;
1710         }
1711      }
1712   }
1713   if (r > 255) r = 255;
1714   if (g > 255) g = 255;
1715   if (b > 255) b = 255;
1716   if (a > 255) a = 255;
1717   DWORD color = D3DCOLOR_ARGB(a, r, g, b);
1718
1719   // adjust half pixel X/Y offset, set the color, Z parameters to standard values
1720   for (int i = 0; i < 4; i++)
1721   {
1722      vertex[i].x -= 0.5f;
1723      vertex[i].y -= 0.5f;
1724      vertex[i].z = 0.0f;
1725      vertex[i].rhw = 1.0f;
1726      vertex[i].color = color;
1727   }
1728
1729   // now add a polygon entry
1730   m_poly[m_numpolys].init(D3DPT_TRIANGLESTRIP, 2, 4, prim->flags, texture, modmode, width, height);
1731   m_numpolys++;
1732}
1733
1734void poly_info::init(D3DPRIMITIVETYPE type, UINT32 count, UINT32 numverts,
1735                     UINT32 flags, texture_info *texture, UINT32 modmode,
1736                     float line_time, float line_length,
1737                     float prim_width, float prim_height)
1738{
1739   init(type, count, numverts, flags, texture, modmode, prim_width, prim_height);
1740   m_line_time = line_time;
1741   m_line_length = line_length;
1742}
1743
1744void poly_info::init(D3DPRIMITIVETYPE type, UINT32 count, UINT32 numverts,
1745                     UINT32 flags, texture_info *texture, UINT32 modmode,
1746                     float prim_width, float prim_height)
1747{
1748   m_type = type;
1749   m_count = count;
1750   m_numverts = numverts;
1751   m_flags = flags;
1752   m_texture = texture;
1753   m_modmode = modmode;
1754   m_prim_width = prim_width;
1755   m_prim_height = prim_height;
1756}
1757
1758
1759//============================================================
1760//  primitive_alloc
1761//============================================================
1762
1763vertex *renderer::mesh_alloc(int numverts)
1764{
1765   HRESULT result;
1766
1767   // if we're going to overflow, flush
1768   if (m_lockedbuf != NULL && m_numverts + numverts >= VERTEX_BUFFER_SIZE)
1769   {
1770      primitive_flush_pending();
1771
1772      if(m_shaders->enabled())
1773      {
1774         m_hlsl_buf = (void*)mesh_alloc(6);
1775         m_shaders->init_fsfx_quad(m_hlsl_buf);
1776      }
1777   }
1778
1779   // if we don't have a lock, grab it now
1780   if (m_lockedbuf == NULL)
1781   {
1782      result = (*d3dintf->vertexbuf.lock)(m_vertexbuf, 0, 0, (VOID **)&m_lockedbuf, D3DLOCK_DISCARD);
1783      if (result != D3D_OK)
1784         return NULL;
1785   }
1786
1787   // if we already have the lock and enough room, just return a pointer
1788   if (m_lockedbuf != NULL && m_numverts + numverts < VERTEX_BUFFER_SIZE)
1789   {
1790      int oldverts = m_numverts;
1791      m_numverts += numverts;
1792      return &m_lockedbuf[oldverts];
1793   }
1794   return NULL;
1795}
1796
1797
1798//============================================================
1799//  primitive_flush_pending
1800//============================================================
1801
1802void renderer::primitive_flush_pending()
1803{
1804   // ignore if we're not locked
1805   if (m_lockedbuf == NULL)
1806   {
1807      return;
1808   }
1809
1810   // unlock the buffer
1811   HRESULT result = (*d3dintf->vertexbuf.unlock)(m_vertexbuf);
1812   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during vertex buffer unlock call\n", (int)result);
1813   m_lockedbuf = NULL;
1814
1815   // set the stream
1816   result = (*d3dintf->device.set_stream_source)(m_device, 0, m_vertexbuf, sizeof(vertex));
1817   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_stream_source call\n", (int)result);
1818
1819   m_shaders->begin_draw();
1820
1821   int vertnum = 0;
1822   if (m_shaders->enabled())
1823   {
1824      vertnum = 6;
1825   }
1826
1827   // now do the polys
1828   for (int polynum = 0; polynum < m_numpolys; polynum++)
1829   {
1830      UINT32 flags = m_poly[polynum].get_flags();
1831      texture_info *texture = m_poly[polynum].get_texture();
1832      int newfilter;
1833
1834      // set the texture if different
1835      set_texture(texture);
1836
1837      // set filtering if different
1838      if (texture != NULL)
1839      {
1840         newfilter = FALSE;
1841         if (PRIMFLAG_GET_SCREENTEX(flags))
1842            newfilter = video_config.filter;
1843         set_filter(newfilter);
1844         set_wrap(PRIMFLAG_GET_TEXWRAP(flags) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP);
1845         set_modmode(m_poly[polynum].get_modmode());
1846
1847         m_shaders->init_effect_info(&m_poly[polynum]);
1848      }
1849
1850      // set the blendmode if different
1851      set_blendmode(PRIMFLAG_GET_BLENDMODE(flags));
1852
1853      if (vertnum + m_poly[polynum].get_vertcount() > m_numverts)
1854      {
1855         osd_printf_error("Error: vertnum (%d) plus poly vertex count (%d) > %d\n", vertnum, m_poly[polynum].get_vertcount(), m_numverts);
1856         fflush(stdout);
1857      }
1858
1859      assert(vertnum + m_poly[polynum].get_vertcount() <= m_numverts);
1860
1861      if(m_shaders->enabled() && d3dintf->post_fx_available)
1862      {
1863         m_shaders->render_quad(&m_poly[polynum], vertnum);
1864      }
1865      else
1866      {
1867         // add the primitives
1868         result = (*d3dintf->device.draw_primitive)(m_device, m_poly[polynum].get_type(), vertnum,
1869                                          m_poly[polynum].get_count());
1870         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result);
1871      }
1872
1873      vertnum += m_poly[polynum].get_vertcount();
1874   }
1875
1876   m_shaders->end_draw();
1877
1878   // reset the vertex count
1879   m_numverts = 0;
1880   m_numpolys = 0;
1881}
1882
1883
1884//============================================================
1885//  texture_info destructor
1886//============================================================
1887
1888texture_info::~texture_info()
1889{
1890   if (m_d3dfinaltex != NULL)
1891   {
1892      if (m_d3dtex == m_d3dfinaltex)
1893      {
1894         m_d3dtex = NULL;
1895      }
1896      (*d3dintf->texture.release)(m_d3dfinaltex);
1897      m_d3dfinaltex = NULL;
1898   }
1899   if (m_d3dtex != NULL)
1900   {
1901      (*d3dintf->texture.release)(m_d3dtex);
1902      m_d3dtex = NULL;
1903   }
1904   if (m_d3dsurface != NULL)
1905   {
1906      (*d3dintf->surface.release)(m_d3dsurface);
1907      m_d3dsurface = NULL;
1908   }
1909}
1910
1911
1912//============================================================
1913//  texture_info constructor
1914//============================================================
1915
1916texture_info::texture_info(texture_manager *manager, const render_texinfo* texsource, int prescale, UINT32 flags)
1917{
1918   HRESULT result;
1919
1920   // fill in the core data
1921   m_texture_manager = manager;
1922   m_renderer = m_texture_manager->get_d3d();
1923   m_hash = m_texture_manager->texture_compute_hash(texsource, flags);
1924   m_flags = flags;
1925   m_texinfo = *texsource;
1926   m_xprescale = prescale;
1927   m_yprescale = prescale;
1928
1929   m_d3dtex = NULL;
1930   m_d3dsurface = NULL;
1931   m_d3dfinaltex = NULL;
1932
1933   // compute the size
1934   compute_size(texsource->width, texsource->height);
1935
1936   // non-screen textures are easy
1937   if (!PRIMFLAG_GET_SCREENTEX(flags))
1938   {
1939      assert(PRIMFLAG_TEXFORMAT(flags) != TEXFORMAT_YUY16);
1940      result = (*d3dintf->device.create_texture)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_d3dtex);
1941      if (result != D3D_OK)
1942         goto error;
1943      m_d3dfinaltex = m_d3dtex;
1944      m_type = TEXTURE_TYPE_PLAIN;
1945   }
1946
1947   // screen textures are allocated differently
1948   else
1949   {
1950      D3DFORMAT format;
1951      DWORD usage = m_texture_manager->is_dynamic_supported() ? D3DUSAGE_DYNAMIC : 0;
1952      D3DPOOL pool = m_texture_manager->is_dynamic_supported() ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
1953      int maxdim = MAX(m_renderer->get_presentation()->BackBufferWidth, m_renderer->get_presentation()->BackBufferHeight);
1954
1955      // pick the format
1956      if (PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_YUY16)
1957      {
1958         format = m_texture_manager->get_yuv_format();
1959      }
1960      else if (PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_ARGB32 || PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_PALETTEA16)
1961      {
1962         format = D3DFMT_A8R8G8B8;
1963      }
1964      else
1965      {
1966         format = m_renderer->get_screen_format();
1967      }
1968
1969      // don't prescale above screen size
1970      while (m_xprescale > 1 && m_rawdims.c.x * m_xprescale >= 2 * maxdim)
1971      {
1972         m_xprescale--;
1973      }
1974      while (m_xprescale > 1 && m_rawdims.c.x * m_xprescale > manager->get_max_texture_width())
1975      {
1976         m_xprescale--;
1977      }
1978      while (m_yprescale > 1 && m_rawdims.c.y * m_yprescale >= 2 * maxdim)
1979      {
1980         m_yprescale--;
1981      }
1982      while (m_yprescale > 1 && m_rawdims.c.y * m_yprescale > manager->get_max_texture_height())
1983      {
1984         m_yprescale--;
1985      }
1986
1987      int prescale = m_renderer->window().prescale();
1988      if (m_xprescale != prescale || m_yprescale != prescale)
1989      {
1990         osd_printf_verbose("Direct3D: adjusting prescale from %dx%d to %dx%d\n", prescale, prescale, m_xprescale, m_yprescale);
1991      }
1992
1993      // loop until we allocate something or error
1994      for (int attempt = 0; attempt < 2; attempt++)
1995      {
1996         // second attempt is always 1:1
1997         if (attempt == 1)
1998         {
1999            m_xprescale = m_yprescale = 1;
2000         }
2001
2002         // screen textures with no prescaling are pretty easy
2003         if (m_xprescale == 1 && m_yprescale == 1)
2004         {
2005            result = (*d3dintf->device.create_texture)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, 1, usage, format, pool, &m_d3dtex);
2006            if (result == D3D_OK)
2007            {
2008               m_d3dfinaltex = m_d3dtex;
2009               m_type = m_texture_manager->is_dynamic_supported() ? TEXTURE_TYPE_DYNAMIC : TEXTURE_TYPE_PLAIN;
2010               if (m_renderer->get_shaders()->enabled() && !m_renderer->get_shaders()->register_texture(this))
2011               {
2012                  goto error;
2013               }
2014
2015               break;
2016            }
2017         }
2018
2019         // screen textures with prescaling require two allocations
2020         else
2021         {
2022            // use an offscreen plain surface for stretching if supported
2023            // (won't work for YUY textures)
2024            if (m_texture_manager->is_stretch_supported() && PRIMFLAG_GET_TEXFORMAT(flags) != TEXFORMAT_YUY16)
2025            {
2026               result = (*d3dintf->device.create_offscreen_plain_surface)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, format, D3DPOOL_DEFAULT, &m_d3dsurface);
2027               if (result != D3D_OK)
2028               {
2029                  continue;
2030               }
2031               m_type = TEXTURE_TYPE_SURFACE;
2032            }
2033
2034            // otherwise, we allocate a dynamic texture for the source
2035            else
2036            {
2037               result = (*d3dintf->device.create_texture)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, 1, usage, format, pool, &m_d3dtex);
2038               if (result != D3D_OK)
2039               {
2040                  continue;
2041               }
2042               m_type = m_texture_manager->is_dynamic_supported() ? TEXTURE_TYPE_DYNAMIC : TEXTURE_TYPE_PLAIN;
2043            }
2044
2045            // for the target surface, we allocate a render target texture
2046            int scwidth = m_rawdims.c.x * m_xprescale;
2047            int scheight = m_rawdims.c.y * m_yprescale;
2048
2049            // target surfaces typically cannot be YCbCr, so we always pick RGB in that case
2050            D3DFORMAT finalfmt = (format != m_texture_manager->get_yuv_format()) ? format : D3DFMT_A8R8G8B8;
2051            result = (*d3dintf->device.create_texture)(m_renderer->get_device(), scwidth, scheight, 1, D3DUSAGE_RENDERTARGET, finalfmt, D3DPOOL_DEFAULT, &m_d3dfinaltex);
2052            if (result == D3D_OK)
2053            {
2054               if (m_renderer->get_shaders()->enabled() && !m_renderer->get_shaders()->register_prescaled_texture(this))
2055               {
2056                  goto error;
2057               }
2058               break;
2059            }
2060            (*d3dintf->texture.release)(m_d3dtex);
2061            m_d3dtex = NULL;
2062         }
2063      }
2064   }
2065
2066   // copy the data to the texture
2067   set_data(texsource, flags);
2068
2069   //texsource->osdhandle = (void*)this;
2070   // add us to the texture list
2071   if(m_texture_manager->get_texlist() != NULL)
2072      m_texture_manager->get_texlist()->m_prev = this;
2073   m_prev = NULL;
2074   m_next = m_texture_manager->get_texlist();
2075   m_texture_manager->set_texlist(this);
2076   return;
2077
2078error:
2079   d3dintf->post_fx_available = false;
2080   osd_printf_error("Direct3D: Critical warning: A texture failed to allocate. Expect things to get bad quickly.\n");
2081   if (m_d3dsurface != NULL)
2082      (*d3dintf->surface.release)(m_d3dsurface);
2083   if (m_d3dtex != NULL)
2084      (*d3dintf->texture.release)(m_d3dtex);
2085}
2086
2087
2088//============================================================
2089//  texture_info::compute_size_subroutine
2090//============================================================
2091
2092void texture_info::compute_size_subroutine(int texwidth, int texheight, int* p_width, int* p_height)
2093{
2094   int finalheight = texheight;
2095   int finalwidth = texwidth;
2096
2097   // round width/height up to nearest power of 2 if we need to
2098   if (!(m_texture_manager->get_texture_caps() & D3DPTEXTURECAPS_NONPOW2CONDITIONAL))
2099   {
2100      // first the width
2101      if (finalwidth & (finalwidth - 1))
2102      {
2103         finalwidth |= finalwidth >> 1;
2104         finalwidth |= finalwidth >> 2;
2105         finalwidth |= finalwidth >> 4;
2106         finalwidth |= finalwidth >> 8;
2107         finalwidth++;
2108      }
2109
2110      // then the height
2111      if (finalheight & (finalheight - 1))
2112      {
2113         finalheight |= finalheight >> 1;
2114         finalheight |= finalheight >> 2;
2115         finalheight |= finalheight >> 4;
2116         finalheight |= finalheight >> 8;
2117         finalheight++;
2118      }
2119   }
2120
2121   // round up to square if we need to
2122   if (m_texture_manager->get_texture_caps() & D3DPTEXTURECAPS_SQUAREONLY)
2123   {
2124      if (finalwidth < finalheight)
2125         finalwidth = finalheight;
2126      else
2127         finalheight = finalwidth;
2128   }
2129
2130   // adjust the aspect ratio if we need to
2131   while (finalwidth < finalheight && finalheight / finalwidth > m_texture_manager->get_max_texture_aspect())
2132   {
2133      finalwidth *= 2;
2134   }
2135   while (finalheight < finalwidth && finalwidth / finalheight > m_texture_manager->get_max_texture_aspect())
2136   {
2137      finalheight *= 2;
2138   }
2139
2140   *p_width = finalwidth;
2141   *p_height = finalheight;
2142}
2143
2144
2145//============================================================
2146//  texture_info::compute_size
2147//============================================================
2148
2149void texture_info::compute_size(int texwidth, int texheight)
2150{
2151   int finalheight = texheight;
2152   int finalwidth = texwidth;
2153
2154   m_xborderpix = 0;
2155   m_yborderpix = 0;
2156
2157   // if we're not wrapping, add a 1-2 pixel border on all sides
2158   if (ENABLE_BORDER_PIX && !(m_flags & PRIMFLAG_TEXWRAP_MASK))
2159   {
2160      // note we need 2 pixels in X for YUY textures
2161      m_xborderpix = (PRIMFLAG_GET_TEXFORMAT(m_flags) == TEXFORMAT_YUY16) ? 2 : 1;
2162      m_yborderpix = 1;
2163   }
2164
2165   // compute final texture size
2166   finalwidth += 2 * m_xborderpix;
2167   finalheight += 2 * m_yborderpix;
2168
2169   compute_size_subroutine(finalwidth, finalheight, &finalwidth, &finalheight);
2170
2171   // if we added pixels for the border, and that just barely pushed us over, take it back
2172   if (finalwidth > m_texture_manager->get_max_texture_width() || finalheight > m_texture_manager->get_max_texture_height())
2173   {
2174      finalheight = texheight;
2175      finalwidth = texwidth;
2176
2177      m_xborderpix = 0;
2178      m_yborderpix = 0;
2179
2180      compute_size_subroutine(finalwidth, finalheight, &finalwidth, &finalheight);
2181   }
2182
2183   // if we're above the max width/height, do what?
2184   if (finalwidth > m_texture_manager->get_max_texture_width() || finalheight > m_texture_manager->get_max_texture_height())
2185   {
2186      static int printed = FALSE;
2187      if (!printed) osd_printf_warning("Texture too big! (wanted: %dx%d, max is %dx%d)\n", finalwidth, finalheight, (int)m_texture_manager->get_max_texture_width(), (int)m_texture_manager->get_max_texture_height());
2188      printed = TRUE;
2189   }
2190
2191   // compute the U/V scale factors
2192   m_start.c.x = (float)m_xborderpix / (float)finalwidth;
2193   m_start.c.y = (float)m_yborderpix / (float)finalheight;
2194   m_stop.c.x = (float)(texwidth + m_xborderpix) / (float)finalwidth;
2195   m_stop.c.y = (float)(texheight + m_yborderpix) / (float)finalheight;
2196
2197   // set the final values
2198   m_rawdims.c.x = finalwidth;
2199   m_rawdims.c.y = finalheight;
2200}
2201
2202
2203//============================================================
2204//  copyline_palette16
2205//============================================================
2206
2207INLINE void copyline_palette16(UINT32 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix)
2208{
2209   int x;
2210
2211   assert(xborderpix == 0 || xborderpix == 1);
2212   if (xborderpix)
2213      *dst++ = 0xff000000 | palette[*src];
2214   for (x = 0; x < width; x++)
2215      *dst++ = 0xff000000 | palette[*src++];
2216   if (xborderpix)
2217      *dst++ = 0xff000000 | palette[*--src];
2218}
2219
2220
2221//============================================================
2222//  copyline_palettea16
2223//============================================================
2224
2225INLINE void copyline_palettea16(UINT32 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix)
2226{
2227   int x;
2228
2229   assert(xborderpix == 0 || xborderpix == 1);
2230   if (xborderpix)
2231      *dst++ = palette[*src];
2232   for (x = 0; x < width; x++)
2233      *dst++ = palette[*src++];
2234   if (xborderpix)
2235      *dst++ = palette[*--src];
2236}
2237
2238
2239//============================================================
2240//  copyline_rgb32
2241//============================================================
2242
2243INLINE void copyline_rgb32(UINT32 *dst, const UINT32 *src, int width, const rgb_t *palette, int xborderpix)
2244{
2245   int x;
2246
2247   assert(xborderpix == 0 || xborderpix == 1);
2248
2249   // palette (really RGB map) case
2250   if (palette != NULL)
2251   {
2252      if (xborderpix)
2253      {
2254         rgb_t srcpix = *src;
2255         *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2256      }
2257      for (x = 0; x < width; x++)
2258      {
2259         rgb_t srcpix = *src++;
2260         *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2261      }
2262      if (xborderpix)
2263      {
2264         rgb_t srcpix = *--src;
2265         *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2266      }
2267   }
2268
2269   // direct case
2270   else
2271   {
2272      if (xborderpix)
2273         *dst++ = 0xff000000 | *src;
2274      for (x = 0; x < width; x++)
2275         *dst++ = 0xff000000 | *src++;
2276      if (xborderpix)
2277         *dst++ = 0xff000000 | *--src;
2278   }
2279}
2280
2281
2282//============================================================
2283//  copyline_argb32
2284//============================================================
2285
2286INLINE void copyline_argb32(UINT32 *dst, const UINT32 *src, int width, const rgb_t *palette, int xborderpix)
2287{
2288   int x;
2289
2290   assert(xborderpix == 0 || xborderpix == 1);
2291
2292   // palette (really RGB map) case
2293   if (palette != NULL)
2294   {
2295      if (xborderpix)
2296      {
2297         rgb_t srcpix = *src;
2298         *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2299      }
2300      for (x = 0; x < width; x++)
2301      {
2302         rgb_t srcpix = *src++;
2303         *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2304      }
2305      if (xborderpix)
2306      {
2307         rgb_t srcpix = *--src;
2308         *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2309      }
2310   }
2311
2312   // direct case
2313   else
2314   {
2315      if (xborderpix)
2316         *dst++ = *src;
2317      for (x = 0; x < width; x++)
2318         *dst++ = *src++;
2319      if (xborderpix)
2320         *dst++ = *--src;
2321   }
2322}
2323
2324
2325//============================================================
2326//  copyline_yuy16_to_yuy2
2327//============================================================
2328
2329INLINE void copyline_yuy16_to_yuy2(UINT16 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix)
2330{
2331   int x;
2332
2333   assert(xborderpix == 0 || xborderpix == 2);
2334   assert(width % 2 == 0);
2335
2336   // palette (really RGB map) case
2337   if (palette != NULL)
2338   {
2339      if (xborderpix)
2340      {
2341         UINT16 srcpix0 = *src++;
2342         UINT16 srcpix1 = *src--;
2343         *dst++ = palette[0x000 + (srcpix0 >> 8)] | (srcpix0 << 8);
2344         *dst++ = palette[0x000 + (srcpix0 >> 8)] | (srcpix1 << 8);
2345      }
2346      for (x = 0; x < width; x += 2)
2347      {
2348         UINT16 srcpix0 = *src++;
2349         UINT16 srcpix1 = *src++;
2350         *dst++ = palette[0x000 + (srcpix0 >> 8)] | (srcpix0 << 8);
2351         *dst++ = palette[0x000 + (srcpix1 >> 8)] | (srcpix1 << 8);
2352      }
2353      if (xborderpix)
2354      {
2355         UINT16 srcpix1 = *--src;
2356         UINT16 srcpix0 = *--src;
2357         *dst++ = palette[0x000 + (srcpix1 >> 8)] | (srcpix0 << 8);
2358         *dst++ = palette[0x000 + (srcpix1 >> 8)] | (srcpix1 << 8);
2359      }
2360   }
2361
2362   // direct case
2363   else
2364   {
2365      if (xborderpix)
2366      {
2367         UINT16 srcpix0 = *src++;
2368         UINT16 srcpix1 = *src--;
2369         *dst++ = (srcpix0 >> 8) | (srcpix0 << 8);
2370         *dst++ = (srcpix0 >> 8) | (srcpix1 << 8);
2371      }
2372      for (x = 0; x < width; x += 2)
2373      {
2374         UINT16 srcpix0 = *src++;
2375         UINT16 srcpix1 = *src++;
2376         *dst++ = (srcpix0 >> 8) | (srcpix0 << 8);
2377         *dst++ = (srcpix1 >> 8) | (srcpix1 << 8);
2378      }
2379      if (xborderpix)
2380      {
2381         UINT16 srcpix1 = *--src;
2382         UINT16 srcpix0 = *--src;
2383         *dst++ = (srcpix1 >> 8) | (srcpix0 << 8);
2384         *dst++ = (srcpix1 >> 8) | (srcpix1 << 8);
2385      }
2386   }
2387}
2388
2389
2390//============================================================
2391//  copyline_yuy16_to_uyvy
2392//============================================================
2393
2394INLINE void copyline_yuy16_to_uyvy(UINT16 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix)
2395{
2396   int x;
2397
2398   assert(xborderpix == 0 || xborderpix == 2);
2399   assert(width % 2 == 0);
2400
2401   // palette (really RGB map) case
2402   if (palette != NULL)
2403   {
2404      if (xborderpix)
2405      {
2406         UINT16 srcpix0 = *src++;
2407         UINT16 srcpix1 = *src--;
2408         *dst++ = palette[0x100 + (srcpix0 >> 8)] | (srcpix0 & 0xff);
2409         *dst++ = palette[0x100 + (srcpix0 >> 8)] | (srcpix1 & 0xff);
2410      }
2411      for (x = 0; x < width; x += 2)
2412      {
2413         UINT16 srcpix0 = *src++;
2414         UINT16 srcpix1 = *src++;
2415         *dst++ = palette[0x100 + (srcpix0 >> 8)] | (srcpix0 & 0xff);
2416         *dst++ = palette[0x100 + (srcpix1 >> 8)] | (srcpix1 & 0xff);
2417      }
2418      if (xborderpix)
2419      {
2420         UINT16 srcpix1 = *--src;
2421         UINT16 srcpix0 = *--src;
2422         *dst++ = palette[0x100 + (srcpix1 >> 8)] | (srcpix0 & 0xff);
2423         *dst++ = palette[0x100 + (srcpix1 >> 8)] | (srcpix1 & 0xff);
2424      }
2425   }
2426
2427   // direct case
2428   else
2429   {
2430      if (xborderpix)
2431      {
2432         UINT16 srcpix0 = src[0];
2433         UINT16 srcpix1 = src[1];
2434         *dst++ = srcpix0;
2435         *dst++ = (srcpix0 & 0xff00) | (srcpix1 & 0x00ff);
2436      }
2437      for (x = 0; x < width; x += 2)
2438      {
2439         *dst++ = *src++;
2440         *dst++ = *src++;
2441      }
2442      if (xborderpix)
2443      {
2444         UINT16 srcpix1 = *--src;
2445         UINT16 srcpix0 = *--src;
2446         *dst++ = (srcpix1 & 0xff00) | (srcpix0 & 0x00ff);
2447         *dst++ = srcpix1;
2448      }
2449   }
2450}
2451
2452
2453//============================================================
2454//  copyline_yuy16_to_argb
2455//============================================================
2456
2457INLINE void copyline_yuy16_to_argb(UINT32 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix)
2458{
2459   int x;
2460
2461   assert(xborderpix == 0 || xborderpix == 2);
2462   assert(width % 2 == 0);
2463
2464   // palette (really RGB map) case
2465   if (palette != NULL)
2466   {
2467      if (xborderpix)
2468      {
2469         UINT16 srcpix0 = src[0];
2470         UINT16 srcpix1 = src[1];
2471         UINT8 cb = srcpix0 & 0xff;
2472         UINT8 cr = srcpix1 & 0xff;
2473         *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr);
2474         *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr);
2475      }
2476      for (x = 0; x < width / 2; x++)
2477      {
2478         UINT16 srcpix0 = *src++;
2479         UINT16 srcpix1 = *src++;
2480         UINT8 cb = srcpix0 & 0xff;
2481         UINT8 cr = srcpix1 & 0xff;
2482         *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr);
2483         *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr);
2484      }
2485      if (xborderpix)
2486      {
2487         UINT16 srcpix1 = *--src;
2488         UINT16 srcpix0 = *--src;
2489         UINT8 cb = srcpix0 & 0xff;
2490         UINT8 cr = srcpix1 & 0xff;
2491         *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr);
2492         *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr);
2493      }
2494   }
2495
2496   // direct case
2497   else
2498   {
2499      if (xborderpix)
2500      {
2501         UINT16 srcpix0 = src[0];
2502         UINT16 srcpix1 = src[1];
2503         UINT8 cb = srcpix0 & 0xff;
2504         UINT8 cr = srcpix1 & 0xff;
2505         *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr);
2506         *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr);
2507      }
2508      for (x = 0; x < width; x += 2)
2509      {
2510         UINT16 srcpix0 = *src++;
2511         UINT16 srcpix1 = *src++;
2512         UINT8 cb = srcpix0 & 0xff;
2513         UINT8 cr = srcpix1 & 0xff;
2514         *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr);
2515         *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr);
2516      }
2517      if (xborderpix)
2518      {
2519         UINT16 srcpix1 = *--src;
2520         UINT16 srcpix0 = *--src;
2521         UINT8 cb = srcpix0 & 0xff;
2522         UINT8 cr = srcpix1 & 0xff;
2523         *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr);
2524         *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr);
2525      }
2526   }
2527}
2528
2529
2530//============================================================
2531//  texture_set_data
2532//============================================================
2533
2534void texture_info::set_data(const render_texinfo *texsource, UINT32 flags)
2535{
2536   D3DLOCKED_RECT rect;
2537   HRESULT result;
2538
2539   // lock the texture
2540   switch (m_type)
2541   {
2542      default:
2543      case TEXTURE_TYPE_PLAIN:    result = (*d3dintf->texture.lock_rect)(m_d3dtex, 0, &rect, NULL, 0);                 break;
2544      case TEXTURE_TYPE_DYNAMIC:  result = (*d3dintf->texture.lock_rect)(m_d3dtex, 0, &rect, NULL, D3DLOCK_DISCARD);   break;
2545      case TEXTURE_TYPE_SURFACE:  result = (*d3dintf->surface.lock_rect)(m_d3dsurface, &rect, NULL, D3DLOCK_DISCARD);  break;
2546   }
2547   if (result != D3D_OK)
2548   {
2549      return;
2550   }
2551
2552   // loop over Y
2553   int miny = 0 - m_yborderpix;
2554   int maxy = texsource->height + m_yborderpix;
2555   for (int dsty = miny; dsty < maxy; dsty++)
2556   {
2557      int srcy = (dsty < 0) ? 0 : (dsty >= texsource->height) ? texsource->height - 1 : dsty;
2558      void *dst = (BYTE *)rect.pBits + (dsty + m_yborderpix) * rect.Pitch;
2559
2560      // switch off of the format and
2561      switch (PRIMFLAG_GET_TEXFORMAT(flags))
2562      {
2563         case TEXFORMAT_PALETTE16:
2564            copyline_palette16((UINT32 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix);
2565            break;
2566
2567         case TEXFORMAT_PALETTEA16:
2568            copyline_palettea16((UINT32 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix);
2569            break;
2570
2571         case TEXFORMAT_RGB32:
2572            copyline_rgb32((UINT32 *)dst, (UINT32 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix);
2573            break;
2574
2575         case TEXFORMAT_ARGB32:
2576            copyline_argb32((UINT32 *)dst, (UINT32 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix);
2577            break;
2578
2579         case TEXFORMAT_YUY16:
2580            if (m_texture_manager->get_yuv_format() == D3DFMT_YUY2)
2581               copyline_yuy16_to_yuy2((UINT16 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix);
2582            else if (m_texture_manager->get_yuv_format() == D3DFMT_UYVY)
2583               copyline_yuy16_to_uyvy((UINT16 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix);
2584            else
2585               copyline_yuy16_to_argb((UINT32 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix);
2586            break;
2587
2588         default:
2589            osd_printf_error("Unknown texture blendmode=%d format=%d\n", PRIMFLAG_GET_BLENDMODE(flags), PRIMFLAG_GET_TEXFORMAT(flags));
2590            break;
2591      }
2592   }
2593
2594   // unlock
2595   switch (m_type)
2596   {
2597      default:
2598      case TEXTURE_TYPE_PLAIN:    result = (*d3dintf->texture.unlock_rect)(m_d3dtex, 0);   break;
2599      case TEXTURE_TYPE_DYNAMIC:  result = (*d3dintf->texture.unlock_rect)(m_d3dtex, 0);   break;
2600      case TEXTURE_TYPE_SURFACE:  result = (*d3dintf->surface.unlock_rect)(m_d3dsurface);  break;
2601   }
2602   if (result != D3D_OK)
2603   {
2604      osd_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result);
2605   }
2606
2607   // prescale
2608   prescale();
2609}
2610
2611
2612//============================================================
2613//  texture_info::prescale
2614//============================================================
2615
2616void texture_info::prescale()
2617{
2618   surface *scale_surface;
2619   HRESULT result;
2620   int i;
2621
2622   // if we don't need to, just skip it
2623   if (m_d3dtex == m_d3dfinaltex)
2624      return;
2625
2626   // for all cases, we need to get the surface of the render target
2627   result = (*d3dintf->texture.get_surface_level)(m_d3dfinaltex, 0, &scale_surface);
2628   if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during texture get_surface_level call\n", (int)result);
2629
2630   // if we have an offscreen plain surface, we can just StretchRect to it
2631   if (m_type == TEXTURE_TYPE_SURFACE)
2632   {
2633      assert(m_d3dsurface != NULL);
2634
2635      // set the source bounds
2636      RECT source;
2637      source.left = source.top = 0;
2638      source.right = m_texinfo.width + 2 * m_xborderpix;
2639      source.bottom = m_texinfo.height + 2 * m_yborderpix;
2640
2641      // set the target bounds
2642      RECT dest;
2643      dest = source;
2644      dest.right *= m_xprescale;
2645      dest.bottom *= m_yprescale;
2646
2647      // do the stretchrect
2648      result = (*d3dintf->device.stretch_rect)(m_renderer->get_device(), m_d3dsurface, &source, scale_surface, &dest, D3DTEXF_POINT);
2649      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device stretct_rect call\n", (int)result);
2650   }
2651
2652   // if we are using a texture render target, we need to do more preparations
2653   else
2654   {
2655      surface *backbuffer;
2656
2657      assert(m_d3dtex != NULL);
2658
2659      // first remember the original render target and set the new one
2660      result = (*d3dintf->device.get_render_target)(m_renderer->get_device(), 0, &backbuffer);
2661      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device get_render_target call\n", (int)result);
2662      result = (*d3dintf->device.set_render_target)(m_renderer->get_device(), 0, scale_surface);
2663      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call 1\n", (int)result);
2664      m_renderer->reset_render_states();
2665
2666      // start the scene
2667      result = (*d3dintf->device.begin_scene)(m_renderer->get_device());
2668      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device begin_scene call\n", (int)result);
2669
2670      // configure the rendering pipeline
2671      m_renderer->set_filter(FALSE);
2672      m_renderer->set_blendmode(BLENDMODE_NONE);
2673      result = (*d3dintf->device.set_texture)(m_renderer->get_device(), 0, m_d3dtex);
2674      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture call\n", (int)result);
2675
2676      // lock the vertex buffer
2677      result = (*d3dintf->vertexbuf.lock)(m_renderer->get_vertex_buffer(), 0, 0, m_renderer->get_locked_buffer_ptr(), D3DLOCK_DISCARD);
2678      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during vertex buffer lock call\n", (int)result);
2679
2680      // configure the X/Y coordinates on the target surface
2681      vertex *lockedbuf = m_renderer->get_locked_buffer();
2682      lockedbuf[0].x = -0.5f;
2683      lockedbuf[0].y = -0.5f;
2684      lockedbuf[1].x = (float)((m_texinfo.width + 2 * m_xborderpix) * m_xprescale) - 0.5f;
2685      lockedbuf[1].y = -0.5f;
2686      lockedbuf[2].x = -0.5f;
2687      lockedbuf[2].y = (float)((m_texinfo.height + 2 * m_yborderpix) * m_yprescale) - 0.5f;
2688      lockedbuf[3].x = (float)((m_texinfo.width + 2 * m_xborderpix) * m_xprescale) - 0.5f;
2689      lockedbuf[3].y = (float)((m_texinfo.height + 2 * m_yborderpix) * m_yprescale) - 0.5f;
2690
2691      // configure the U/V coordintes on the source texture
2692      lockedbuf[0].u0 = 0.0f;
2693      lockedbuf[0].v0 = 0.0f;
2694      lockedbuf[1].u0 = (float)(m_texinfo.width + 2 * m_xborderpix) / (float)m_rawdims.c.x;
2695      lockedbuf[1].v0 = 0.0f;
2696      lockedbuf[2].u0 = 0.0f;
2697      lockedbuf[2].v0 = (float)(m_texinfo.height + 2 * m_yborderpix) / (float)m_rawdims.c.y;
2698      lockedbuf[3].u0 = (float)(m_texinfo.width + 2 * m_xborderpix) / (float)m_rawdims.c.x;
2699      lockedbuf[3].v0 = (float)(m_texinfo.height + 2 * m_yborderpix) / (float)m_rawdims.c.y;
2700
2701      // reset the remaining vertex parameters
2702      for (i = 0; i < 4; i++)
2703      {
2704         lockedbuf[i].z = 0.0f;
2705         lockedbuf[i].rhw = 1.0f;
2706         lockedbuf[i].color = D3DCOLOR_ARGB(0xff,0xff,0xff,0xff);
2707      }
2708
2709      // unlock the vertex buffer
2710      result = (*d3dintf->vertexbuf.unlock)(m_renderer->get_vertex_buffer());
2711      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during vertex buffer unlock call\n", (int)result);
2712      m_renderer->set_locked_buffer(NULL);
2713
2714      // set the stream and draw the triangle strip
2715      result = (*d3dintf->device.set_stream_source)(m_renderer->get_device(), 0, m_renderer->get_vertex_buffer(), sizeof(vertex));
2716      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_stream_source call\n", (int)result);
2717      result = (*d3dintf->device.draw_primitive)(m_renderer->get_device(), D3DPT_TRIANGLESTRIP, 0, 2);
2718      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result);
2719
2720      // end the scene
2721      result = (*d3dintf->device.end_scene)(m_renderer->get_device());
2722      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device end_scene call\n", (int)result);
2723
2724      // reset the render target and release our reference to the backbuffer
2725      result = (*d3dintf->device.set_render_target)(m_renderer->get_device(), 0, backbuffer);
2726      if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call 2\n", (int)result);
2727      (*d3dintf->surface.release)(backbuffer);
2728      m_renderer->reset_render_states();
2729   }
2730
2731   // release our reference to the target surface
2732   (*d3dintf->surface.release)(scale_surface);
2733}
2734
2735
2736//============================================================
2737//  cache_target::~cache_target
2738//============================================================
2739
2740cache_target::~cache_target()
2741{
2742   for (int index = 0; index < 11; index++)
2743   {
2744      if (bloom_texture[index] != NULL)
2745      {
2746         (*d3dintf->texture.release)(bloom_texture[index]);
2747         bloom_texture[index] = NULL;
2748      }
2749      if (bloom_target[index] != NULL)
2750      {
2751         (*d3dintf->surface.release)(bloom_target[index]);
2752         bloom_target[index] = NULL;
2753      }
2754   }
2755
2756   if (last_texture != NULL)
2757   {
2758      (*d3dintf->texture.release)(last_texture);
2759      last_texture = NULL;
2760   }
2761   if (last_target != NULL)
2762   {
2763      (*d3dintf->surface.release)(last_target);
2764      last_target = NULL;
2765   }
2766}
2767
2768
2769//============================================================
2770//  cache_target::init - initializes a target cache
2771//============================================================
2772
2773bool cache_target::init(renderer *d3d, base *d3dintf, int width, int height, int prescale_x, int prescale_y)
2774{
2775   int bloom_index = 0;
2776   int bloom_size = (width < height) ? width : height;
2777   int bloom_width = width;
2778   int bloom_height = height;
2779   for (; bloom_size >= 2 && bloom_index < 11; bloom_size >>= 1)
2780   {
2781      bloom_width >>= 1;
2782      bloom_height >>= 1;
2783
2784      HRESULT result = (*d3dintf->device.create_texture)(d3d->get_device(), bloom_width, bloom_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bloom_texture[bloom_index]);
2785      if (result != D3D_OK)
2786      {
2787         return false;
2788      }
2789      (*d3dintf->texture.get_surface_level)(bloom_texture[bloom_index], 0, &bloom_target[bloom_index]);
2790
2791      bloom_index++;
2792   }
2793
2794   HRESULT result = (*d3dintf->device.create_texture)(d3d->get_device(), width * prescale_x, height * prescale_y, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &last_texture);
2795   if (result != D3D_OK)
2796   {
2797      return false;
2798   }
2799   (*d3dintf->texture.get_surface_level)(last_texture, 0, &last_target);
2800
2801   target_width = width * prescale_x;
2802   target_height = height * prescale_y;
2803
2804   return true;
2805}
2806
2807
2808//============================================================
2809//  render_target::~render_target
2810//============================================================
2811
2812render_target::~render_target()
2813{
2814   for (int index = 0; index < 11; index++)
2815   {
2816      if (bloom_texture[index] != NULL)
2817      {
2818         (*d3dintf->texture.release)(bloom_texture[index]);
2819         bloom_texture[index] = NULL;
2820      }
2821      if (bloom_target[index] != NULL)
2822      {
2823         (*d3dintf->surface.release)(bloom_target[index]);
2824         bloom_target[index] = NULL;
2825      }
2826   }
2827
2828   for (int index = 0; index < 2; index++)
2829   {
2830      if (native_texture[index] != NULL)
2831      {
2832         (*d3dintf->texture.release)(native_texture[index]);
2833         native_texture[index] = NULL;
2834      }
2835      if (native_target[index] != NULL)
2836      {
2837         (*d3dintf->surface.release)(native_target[index]);
2838         native_target[index] = NULL;
2839      }
2840      if (prescale_texture[index] != NULL)
2841      {
2842         (*d3dintf->texture.release)(prescale_texture[index]);
2843         prescale_texture[index] = NULL;
2844      }
2845      if (prescale_target[index] != NULL)
2846      {
2847         (*d3dintf->surface.release)(prescale_target[index]);
2848         prescale_target[index] = NULL;
2849      }
2850   }
2851}
2852
2853
2854//============================================================
2855//  render_target::init - initializes a render target
2856//============================================================
2857
2858bool render_target::init(renderer *d3d, base *d3dintf, int width, int height, int prescale_x, int prescale_y)
2859{
2860   HRESULT result;
2861
2862   for (int index = 0; index < 2; index++)
2863   {
2864      result = (*d3dintf->device.create_texture)(d3d->get_device(), width, height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &native_texture[index]);
2865      if (result != D3D_OK)
2866      {
2867         return false;
2868      }
2869      (*d3dintf->texture.get_surface_level)(native_texture[index], 0, &native_target[index]);
2870
2871      result = (*d3dintf->device.create_texture)(d3d->get_device(), width * prescale_x, height * prescale_y, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &prescale_texture[index]);
2872      if (result != D3D_OK)
2873      {
2874         return false;
2875      }
2876      (*d3dintf->texture.get_surface_level)(prescale_texture[index], 0, &prescale_target[index]);
2877   }
2878
2879   int bloom_index = 0;
2880   float bloom_size = (d3d->get_width() < d3d->get_height()) ? d3d->get_width() : d3d->get_height();
2881   float bloom_width = d3d->get_width();
2882   float bloom_height = d3d->get_height();
2883   for (; bloom_size >= 2.0f && bloom_index < 11; bloom_size *= 0.5f)
2884   {
2885      bloom_width *= 0.5f;
2886      bloom_height *= 0.5f;
2887
2888      result = (*d3dintf->device.create_texture)(d3d->get_device(), (int)bloom_width, (int)bloom_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bloom_texture[bloom_index]);
2889      if (result != D3D_OK)
2890      {
2891         return false;
2892      }
2893      (*d3dintf->texture.get_surface_level)(bloom_texture[bloom_index], 0, &bloom_target[bloom_index]);
2894
2895      bloom_index++;
2896   }
2897
2898   this->width = width;
2899   this->height = height;
2900
2901   target_width = width * prescale_x;
2902   target_height = height * prescale_y;
2903
2904   return true;
2905}
2906
2907}
trunk/src/osd/windows/winmain.c
r250287r250288
1// license:BSD-3-Clause
2// copyright-holders:Aaron Giles
3//============================================================
4//
5//  winmain.c - Win32 main program
6//
7//============================================================
8
9// standard windows headers
10#define WIN32_LEAN_AND_MEAN
11#include <windows.h>
12#include <commctrl.h>
13#include <mmsystem.h>
14#include <tchar.h>
15#include <io.h>
16
17// standard C headers
18#include <ctype.h>
19#include <stdarg.h>
20#include <psapi.h>
21#include <dbghelp.h>
22
23// MAME headers
24#include "emu.h"
25#include "clifront.h"
26#include "emuopts.h"
27
28// MAMEOS headers
29#include "winmain.h"
30#include "window.h"
31#include "video.h"
32#include "input.h"
33#include "output.h"
34#include "config.h"
35#include "osdepend.h"
36#include "strconv.h"
37#include "winutf8.h"
38#include "winutil.h"
39#include "debugger.h"
40#include "winfile.h"
41
42#define DEBUG_SLOW_LOCKS    0
43
44//**************************************************************************
45//  MACROS
46//**************************************************************************
47
48#ifdef UNICODE
49#define UNICODE_POSTFIX "W"
50#else
51#define UNICODE_POSTFIX "A"
52#endif
53
54
55
56//**************************************************************************
57//  TYPE DEFINITIONS
58//**************************************************************************
59
60template<typename _FunctionPtr>
61class dynamic_bind
62{
63public:
64   // constructor which looks up the function
65   dynamic_bind(const TCHAR *dll, const char *symbol)
66      : m_function(NULL)
67   {
68      HMODULE module = LoadLibrary(dll);
69      if (module != NULL)
70         m_function = reinterpret_cast<_FunctionPtr>(GetProcAddress(module, symbol));
71   }
72
73   // bool to test if the function is NULL or not
74   operator bool() const { return (m_function != NULL); }
75
76   // dereference to get the underlying pointer
77   _FunctionPtr operator *() const { return m_function; }
78
79private:
80   _FunctionPtr    m_function;
81};
82
83
84class stack_walker
85{
86public:
87   stack_walker();
88
89   FPTR ip() const { return m_stackframe.AddrPC.Offset; }
90   FPTR sp() const { return m_stackframe.AddrStack.Offset; }
91   FPTR frame() const { return m_stackframe.AddrFrame.Offset; }
92
93   bool reset();
94   void reset(CONTEXT &context, HANDLE thread);
95   bool unwind();
96
97private:
98   HANDLE          m_process;
99   HANDLE          m_thread;
100   STACKFRAME64    m_stackframe;
101   CONTEXT         m_context;
102   bool            m_first;
103
104   dynamic_bind<BOOL (WINAPI *)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64)>
105         m_stack_walk_64;
106   dynamic_bind<BOOL (WINAPI *)(HANDLE, LPCTSTR, BOOL)> m_sym_initialize;
107   dynamic_bind<PVOID (WINAPI *)(HANDLE, DWORD64)> m_sym_function_table_access_64;
108   dynamic_bind<DWORD64 (WINAPI *)(HANDLE, DWORD64)> m_sym_get_module_base_64;
109   dynamic_bind<VOID (WINAPI *)(PCONTEXT)> m_rtl_capture_context;
110
111   static bool     s_initialized;
112};
113
114
115class symbol_manager
116{
117public:
118   // construction/destruction
119   symbol_manager(const char *argv0);
120   ~symbol_manager();
121
122   // getters
123   FPTR last_base() const { return m_last_base; }
124
125   // core symbol lookup
126   const char *symbol_for_address(FPTR address);
127   const char *symbol_for_address(PVOID address) { return symbol_for_address(reinterpret_cast<FPTR>(address)); }
128
129   // force symbols to be cached
130   void cache_symbols() { scan_file_for_address(0, true); }
131
132   void reset_cache() { m_cache.reset(); }
133private:
134   // internal helpers
135   bool query_system_for_address(FPTR address);
136   void scan_file_for_address(FPTR address, bool create_cache);
137   bool parse_sym_line(const char *line, FPTR &address, std::string &symbol);
138   bool parse_map_line(const char *line, FPTR &address, std::string &symbol);
139   void scan_cache_for_address(FPTR address);
140   void format_symbol(const char *name, UINT32 displacement, const char *filename = NULL, int linenumber = 0);
141
142   static FPTR get_text_section_base();
143
144   struct cache_entry
145   {
146      cache_entry(FPTR address, const char *symbol) :
147         m_next(NULL), m_address(address), m_name(symbol) { }
148      cache_entry *next() const { return m_next; }
149
150      cache_entry *   m_next;
151      FPTR            m_address;
152      std::string     m_name;
153   };
154   simple_list<cache_entry> m_cache;
155
156   std::string     m_mapfile;
157   std::string     m_symfile;
158   std::string     m_buffer;
159   HANDLE          m_process;
160   FPTR            m_last_base;
161   FPTR            m_text_base;
162
163   dynamic_bind<BOOL (WINAPI *)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO)> m_sym_from_addr;
164   dynamic_bind<BOOL (WINAPI *)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64)> m_sym_get_line_from_addr_64;
165};
166
167
168class sampling_profiler
169{
170public:
171   sampling_profiler(UINT32 max_seconds, UINT8 stack_depth);
172   ~sampling_profiler();
173
174   void start();
175   void stop();
176
177//  void reset();
178   void print_results(symbol_manager &symbols);
179
180private:
181   static DWORD WINAPI thread_entry(LPVOID lpParameter);
182   void thread_run();
183
184   static int CLIB_DECL compare_address(const void *item1, const void *item2);
185   static int CLIB_DECL compare_frequency(const void *item1, const void *item2);
186
187   HANDLE          m_target_thread;
188
189   HANDLE          m_thread;
190   DWORD           m_thread_id;
191   volatile bool   m_thread_exit;
192
193   UINT8           m_stack_depth;
194   UINT8           m_entry_stride;
195   std::vector<FPTR>    m_buffer;
196   FPTR *          m_buffer_ptr;
197   FPTR *          m_buffer_end;
198};
199
200//============================================================
201//  winui_output_error
202//============================================================
203
204class winui_output_error : public osd_output
205{
206public:
207   virtual void output_callback(osd_output_channel channel, const char *msg, va_list args)
208   {
209      if (channel == OSD_OUTPUT_CHANNEL_ERROR)
210      {
211         char buffer[1024];
212
213         // if we are in fullscreen mode, go to windowed mode
214         if ((video_config.windowed == 0) && (win_window_list != NULL))
215            winwindow_toggle_full_screen();
216
217         vsnprintf(buffer, ARRAY_LENGTH(buffer), msg, args);
218         win_message_box_utf8(win_window_list ? win_window_list->m_hwnd : NULL, buffer, emulator_info::get_appname(), MB_OK);
219      }
220      else
221         chain_output(channel, msg, args);
222   }
223};
224
225
226
227
228//**************************************************************************
229//  GLOBAL VARIABLES
230//**************************************************************************
231
232// this line prevents globbing on the command line
233int _CRT_glob = 0;
234
235//**************************************************************************
236//  LOCAL VARIABLES
237//**************************************************************************
238
239static LPTOP_LEVEL_EXCEPTION_FILTER pass_thru_filter;
240
241static HANDLE watchdog_reset_event;
242static HANDLE watchdog_exit_event;
243static HANDLE watchdog_thread;
244
245static running_machine *g_current_machine;
246
247static int timeresult = !TIMERR_NOERROR;
248static TIMECAPS timecaps;
249
250static sampling_profiler *profiler = NULL;
251static symbol_manager *symbols = NULL;
252
253bool stack_walker::s_initialized = false;
254
255
256//**************************************************************************
257//  FUNCTION PROTOTYPES
258//**************************************************************************
259
260static BOOL WINAPI control_handler(DWORD type);
261static int is_double_click_start(int argc);
262static DWORD WINAPI watchdog_thread_entry(LPVOID lpParameter);
263static LONG WINAPI exception_filter(struct _EXCEPTION_POINTERS *info);
264
265
266
267//**************************************************************************
268//  OPTIONS
269//**************************************************************************
270
271// struct definitions
272const options_entry windows_options::s_option_entries[] =
273{
274   // performance options
275   { NULL,                                           NULL,       OPTION_HEADER,     "WINDOWS PERFORMANCE OPTIONS" },
276   { WINOPTION_PRIORITY "(-15-1)",                   "0",        OPTION_INTEGER,    "thread priority for the main game thread; range from -15 to 1" },
277   { WINOPTION_PROFILE,                              "0",        OPTION_INTEGER,    "enables profiling, specifying the stack depth to track" },
278
279   // video options
280   { NULL,                                           NULL,       OPTION_HEADER,     "WINDOWS VIDEO OPTIONS" },
281   { WINOPTION_MENU,                                 "0",        OPTION_BOOLEAN,    "enables menu bar if available by UI implementation" },
282
283   // DirectDraw-specific options
284   { NULL,                                           NULL,       OPTION_HEADER,     "DIRECTDRAW-SPECIFIC OPTIONS" },
285   { WINOPTION_HWSTRETCH ";hws",                     "1",        OPTION_BOOLEAN,    "enables hardware stretching" },
286
287   // post-processing options
288   { NULL,                                                     NULL,        OPTION_HEADER,     "DIRECT3D POST-PROCESSING OPTIONS" },
289   { WINOPTION_HLSL_ENABLE";hlsl",                             "0",         OPTION_BOOLEAN,    "enables HLSL post-processing (PS3.0 required)" },
290   { WINOPTION_HLSLPATH,                                       "hlsl",      OPTION_STRING,     "path to hlsl files" },
291   { WINOPTION_HLSL_PRESCALE_X,                                "0",         OPTION_INTEGER,    "HLSL pre-scale override factor for X (0 for auto)" },
292   { WINOPTION_HLSL_PRESCALE_Y,                                "0",         OPTION_INTEGER,    "HLSL pre-scale override factor for Y (0 for auto)" },
293   { WINOPTION_HLSL_WRITE,                                     NULL,        OPTION_STRING,     "enables HLSL AVI writing (huge disk bandwidth suggested)" },
294   { WINOPTION_HLSL_SNAP_WIDTH,                                "2048",      OPTION_STRING,     "HLSL upscaled-snapshot width" },
295   { WINOPTION_HLSL_SNAP_HEIGHT,                               "1536",      OPTION_STRING,     "HLSL upscaled-snapshot height" },
296   { WINOPTION_SHADOW_MASK_ALPHA";fs_shadwa(0.0-1.0)",         "0.0",       OPTION_FLOAT,      "shadow mask alpha-blend value (1.0 is fully blended, 0.0 is no mask)" },
297   { WINOPTION_SHADOW_MASK_TEXTURE";fs_shadwt(0.0-1.0)",       "aperture.png", OPTION_STRING,  "shadow mask texture name" },
298   { WINOPTION_SHADOW_MASK_COUNT_X";fs_shadww",                "6",         OPTION_INTEGER,    "shadow mask tile width, in screen dimensions" },
299   { WINOPTION_SHADOW_MASK_COUNT_Y";fs_shadwh",                "6",         OPTION_INTEGER,    "shadow mask tile height, in screen dimensions" },
300   { WINOPTION_SHADOW_MASK_USIZE";fs_shadwu(0.0-1.0)",         "0.1875",    OPTION_FLOAT,      "shadow mask texture width, in U/V dimensions" },
301   { WINOPTION_SHADOW_MASK_VSIZE";fs_shadwv(0.0-1.0)",         "0.1875",    OPTION_FLOAT,      "shadow mask texture height, in U/V dimensions" },
302   { WINOPTION_SHADOW_MASK_UOFFSET";fs_shadwou(-1.0-1.0)",     "0.0",       OPTION_FLOAT,      "shadow mask texture offset, in U direction" },
303   { WINOPTION_SHADOW_MASK_VOFFSET";fs_shadwov(-1.0-1.0)",     "0.0",       OPTION_FLOAT,      "shadow mask texture offset, in V direction" },
304   { WINOPTION_CURVATURE";fs_curv(0.0-1.0)",                   "0.0",       OPTION_FLOAT,      "screen curvature amount" },
305   { WINOPTION_ROUND_CORNER";fs_rndc(0.0-1.0)",                "0.0",       OPTION_FLOAT,      "screen round corner amount" },
306   { WINOPTION_SMOOTH_BORDER";fs_smob(0.0-1.0)",               "0.0",       OPTION_FLOAT,      "screen smooth border amount" },
307   { WINOPTION_REFLECTION";fs_ref(0.0-1.0)",                   "0.0",       OPTION_FLOAT,      "screen reflection amount" },
308   { WINOPTION_VIGNETTING";fs_vig(0.0-1.0)",                   "0.0",       OPTION_FLOAT,      "image vignetting amount" },
309   /* Beam-related values below this line*/
310   { WINOPTION_SCANLINE_AMOUNT";fs_scanam(0.0-4.0)",           "1.0",       OPTION_FLOAT,      "overall alpha scaling value for scanlines" },
311   { WINOPTION_SCANLINE_SCALE";fs_scansc(0.0-4.0)",            "1.0",       OPTION_FLOAT,      "overall height scaling value for scanlines" },
312   { WINOPTION_SCANLINE_HEIGHT";fs_scanh(0.0-4.0)",            "1.0",       OPTION_FLOAT,      "individual height scaling value for scanlines" },
313   { WINOPTION_SCANLINE_BRIGHT_SCALE";fs_scanbs(0.0-2.0)",     "1.0",       OPTION_FLOAT,      "overall brightness scaling value for scanlines (multiplicative)" },
314   { WINOPTION_SCANLINE_BRIGHT_OFFSET";fs_scanbo(0.0-1.0)",    "0.0",       OPTION_FLOAT,      "overall brightness offset value for scanlines (additive)" },
315   { WINOPTION_SCANLINE_OFFSET";fs_scanjt(0.0-4.0)",           "0.0",       OPTION_FLOAT,      "overall interlace jitter scaling value for scanlines" },
316   { WINOPTION_DEFOCUS";fs_focus",                             "0.0,0.0",   OPTION_STRING,     "overall defocus value in screen-relative coords" },
317   { WINOPTION_CONVERGE_X";fs_convx",                          "0.3,0.0,-0.3",OPTION_STRING,   "convergence in screen-relative X direction" },
318   { WINOPTION_CONVERGE_Y";fs_convy",                          "0.0,0.3,-0.3",OPTION_STRING,   "convergence in screen-relative Y direction" },
319   { WINOPTION_RADIAL_CONVERGE_X";fs_rconvx",                  "0.0,0.0,0.0",OPTION_STRING,    "radial convergence in screen-relative X direction" },
320   { WINOPTION_RADIAL_CONVERGE_Y";fs_rconvy",                  "0.0,0.0,0.0",OPTION_STRING,    "radial convergence in screen-relative Y direction" },
321   /* RGB colorspace convolution below this line */
322   { WINOPTION_RED_RATIO";fs_redratio",                        "1.0,0.0,0.0",OPTION_STRING,    "red output signal generated by input signal" },
323   { WINOPTION_GRN_RATIO";fs_grnratio",                        "0.0,1.0,0.0",OPTION_STRING,    "green output signal generated by input signal" },
324   { WINOPTION_BLU_RATIO";fs_bluratio",                        "0.0,0.0,1.0",OPTION_STRING,    "blue output signal generated by input signal" },
325   { WINOPTION_SATURATION";fs_sat(0.0-4.0)",                   "1.4",        OPTION_FLOAT,     "saturation scaling value" },
326   { WINOPTION_OFFSET";fs_offset",                             "0.0,0.0,0.0",OPTION_STRING,    "signal offset value (additive)" },
327   { WINOPTION_SCALE";fs_scale",                               "0.95,0.95,0.95",OPTION_STRING, "signal scaling value (multiplicative)" },
328   { WINOPTION_POWER";fs_power",                               "0.8,0.8,0.8",OPTION_STRING,    "signal power value (exponential)" },
329   { WINOPTION_FLOOR";fs_floor",                               "0.05,0.05,0.05",OPTION_STRING, "signal floor level" },
330   { WINOPTION_PHOSPHOR";fs_phosphor",                         "0.4,0.4,0.4",OPTION_STRING,    "phosphorescence decay rate (0.0 is instant, 1.0 is forever)" },
331   /* NTSC simulation below this line */
332   { NULL,                                                     NULL,        OPTION_HEADER,     "NTSC POST-PROCESSING OPTIONS" },
333   { WINOPTION_YIQ_ENABLE";yiq",                               "0",         OPTION_BOOLEAN,    "enables YIQ-space HLSL post-processing" },
334   { WINOPTION_YIQ_CCVALUE";yiqcc",                            "3.59754545",OPTION_FLOAT,      "Color Carrier frequency for NTSC signal processing" },
335   { WINOPTION_YIQ_AVALUE";yiqa",                              "0.5",       OPTION_FLOAT,      "A value for NTSC signal processing" },
336   { WINOPTION_YIQ_BVALUE";yiqb",                              "0.5",       OPTION_FLOAT,      "B value for NTSC signal processing" },
337   { WINOPTION_YIQ_OVALUE";yiqo",                              "1.570796325",OPTION_FLOAT,     "Outgoing Color Carrier phase offset for NTSC signal processing" },
338   { WINOPTION_YIQ_PVALUE";yiqp",                              "1.0",       OPTION_FLOAT,      "Incoming Pixel Clock scaling value for NTSC signal processing" },
339   { WINOPTION_YIQ_NVALUE";yiqn",                              "1.0",       OPTION_FLOAT,      "Y filter notch width for NTSC signal processing" },
340   { WINOPTION_YIQ_YVALUE";yiqy",                              "6.0",       OPTION_FLOAT,      "Y filter cutoff frequency for NTSC signal processing" },
341   { WINOPTION_YIQ_IVALUE";yiqi",                              "1.2",       OPTION_FLOAT,      "I filter cutoff frequency for NTSC signal processing" },
342   { WINOPTION_YIQ_QVALUE";yiqq",                              "0.6",       OPTION_FLOAT,      "Q filter cutoff frequency for NTSC signal processing" },
343   { WINOPTION_YIQ_SCAN_TIME";yiqsc",                          "52.6",      OPTION_FLOAT,      "Horizontal scanline duration for NTSC signal processing (in usec)" },
344   { WINOPTION_YIQ_PHASE_COUNT";yiqp",                         "2",         OPTION_INTEGER,    "Phase Count value for NTSC signal processing" },
345   { WINOPTION_YIQ_SCAN_TIME";yiqsc",                          "52.6",      OPTION_FLOAT,      "Horizontal scanline duration for NTSC signal processing (in usec)" },
346   { WINOPTION_YIQ_PHASE_COUNT";yiqp",                         "2",         OPTION_INTEGER,    "Phase Count value for NTSC signal processing" },
347   /* Vector simulation below this line */
348   { NULL,                                                     NULL,        OPTION_HEADER,     "VECTOR POST-PROCESSING OPTIONS" },
349   { WINOPTION_VECTOR_LENGTH_SCALE";veclength",                "0.8",       OPTION_FLOAT,      "How much length affects vector fade" },
350   { WINOPTION_VECTOR_LENGTH_RATIO";vecsize",                  "500.0",     OPTION_FLOAT,      "Vector fade length (4.0 - vectors fade the most at and above 4 pixels, etc.)" },
351   /* Bloom below this line */
352   { NULL,                                                     NULL,        OPTION_HEADER,     "BLOOM POST-PROCESSING OPTIONS" },
353   { WINOPTION_BLOOM_SCALE,                                    "0.25",      OPTION_FLOAT,      "Intensity factor for bloom" },
354   { WINOPTION_BLOOM_OVERDRIVE,                                "0.0,0.0,0.0",OPTION_STRING,    "Overdrive factor for bloom" },
355   { WINOPTION_BLOOM_LEVEL0_WEIGHT,                            "1.0",       OPTION_FLOAT,      "Bloom level 0  (full-size target) weight" },
356   { WINOPTION_BLOOM_LEVEL1_WEIGHT,                            "0.21",      OPTION_FLOAT,      "Bloom level 1  (half-size target) weight" },
357   { WINOPTION_BLOOM_LEVEL2_WEIGHT,                            "0.19",      OPTION_FLOAT,      "Bloom level 2  (quarter-size target) weight" },
358   { WINOPTION_BLOOM_LEVEL3_WEIGHT,                            "0.17",      OPTION_FLOAT,      "Bloom level 3  (.) weight" },
359   { WINOPTION_BLOOM_LEVEL4_WEIGHT,                            "0.15",      OPTION_FLOAT,      "Bloom level 4  (.) weight" },
360   { WINOPTION_BLOOM_LEVEL5_WEIGHT,                            "0.14",      OPTION_FLOAT,      "Bloom level 5  (.) weight" },
361   { WINOPTION_BLOOM_LEVEL6_WEIGHT,                            "0.13",      OPTION_FLOAT,      "Bloom level 6  (.) weight" },
362   { WINOPTION_BLOOM_LEVEL7_WEIGHT,                            "0.12",      OPTION_FLOAT,      "Bloom level 7  (.) weight" },
363   { WINOPTION_BLOOM_LEVEL8_WEIGHT,                            "0.11",      OPTION_FLOAT,      "Bloom level 8  (.) weight" },
364   { WINOPTION_BLOOM_LEVEL9_WEIGHT,                            "0.10",      OPTION_FLOAT,      "Bloom level 9  (.) weight" },
365   { WINOPTION_BLOOM_LEVEL10_WEIGHT,                           "0.09",      OPTION_FLOAT,      "Bloom level 10 (1x1 target) weight" },
366
367   // full screen options
368   { NULL,                                           NULL,       OPTION_HEADER,     "FULL SCREEN OPTIONS" },
369   { WINOPTION_TRIPLEBUFFER ";tb",                   "0",        OPTION_BOOLEAN,    "enables triple buffering" },
370   { WINOPTION_FULLSCREENBRIGHTNESS ";fsb(0.1-2.0)", "1.0",      OPTION_FLOAT,      "brightness value in full screen mode" },
371   { WINOPTION_FULLSCREENCONTRAST ";fsc(0.1-2.0)",   "1.0",      OPTION_FLOAT,      "contrast value in full screen mode" },
372   { WINOPTION_FULLSCREENGAMMA ";fsg(0.1-3.0)",      "1.0",      OPTION_FLOAT,      "gamma value in full screen mode" },
373
374   // input options
375   { NULL,                                           NULL,       OPTION_HEADER,     "INPUT DEVICE OPTIONS" },
376   { WINOPTION_GLOBAL_INPUTS ";global_inputs",       "0",        OPTION_BOOLEAN,    "enables global inputs" },
377   { WINOPTION_DUAL_LIGHTGUN ";dual",                "0",        OPTION_BOOLEAN,    "enables dual lightgun input" },
378
379   { NULL }
380};
381
382//**************************************************************************
383//  MAIN ENTRY POINT
384//**************************************************************************
385
386
387//============================================================
388//  utf8_main
389//============================================================
390
391int main(int argc, char *argv[])
392{
393   // use small output buffers on non-TTYs (i.e. pipes)
394   if (!isatty(fileno(stdout)))
395      setvbuf(stdout, (char *) NULL, _IOFBF, 64);
396   if (!isatty(fileno(stderr)))
397      setvbuf(stderr, (char *) NULL, _IOFBF, 64);
398
399   // initialize common controls
400   InitCommonControls();
401
402   // set a handler to catch ctrl-c
403   SetConsoleCtrlHandler(control_handler, TRUE);
404
405   // allocate symbols
406   symbol_manager local_symbols(argv[0]);
407   symbols = &local_symbols;
408
409   // set up exception handling
410   pass_thru_filter = SetUnhandledExceptionFilter(exception_filter);
411   SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
412
413   // enable stack crawls for asserts
414   extern void (*s_debugger_stack_crawler)();
415   s_debugger_stack_crawler = winmain_dump_stack;
416
417
418   // parse config and cmdline options
419   DWORD result = 0;
420   {
421      windows_options options;
422      windows_osd_interface osd(options);
423      // if we're a GUI app, out errors to message boxes
424      // Initialize this after the osd interface so that we are first in the
425      // output order
426      winui_output_error winerror;
427      if (win_is_gui_application() || is_double_click_start(argc))
428      {
429         // if we are a GUI app, output errors to message boxes
430         osd_output::push(&winerror);
431         // make sure any console window that opened on our behalf is nuked
432         FreeConsole();
433      }
434      osd.register_options();
435      cli_frontend frontend(options, osd);
436      result = frontend.execute(argc, argv);
437      osd_output::pop(&winerror);
438   }
439   // free symbols
440   symbols = NULL;
441   return result;
442}
443
444
445//============================================================
446//  windows_options
447//============================================================
448
449windows_options::windows_options()
450: osd_options()
451{
452   add_entries(s_option_entries);
453}
454
455
456//============================================================
457//  control_handler
458//============================================================
459
460static BOOL WINAPI control_handler(DWORD type)
461{
462   // indicate to the user that we detected something
463   switch (type)
464   {
465      case CTRL_C_EVENT:          fprintf(stderr, "Caught Ctrl+C");                   break;
466      case CTRL_BREAK_EVENT:      fprintf(stderr, "Caught Ctrl+break");               break;
467      case CTRL_CLOSE_EVENT:      fprintf(stderr, "Caught console close");            break;
468      case CTRL_LOGOFF_EVENT:     fprintf(stderr, "Caught logoff");                   break;
469      case CTRL_SHUTDOWN_EVENT:   fprintf(stderr, "Caught shutdown");                 break;
470      default:                    fprintf(stderr, "Caught unexpected console event"); break;
471   }
472
473   // if we don't have a machine yet, or if we are handling ctrl+c/ctrl+break,
474   // just terminate hard, without throwing or handling any atexit stuff
475   if (g_current_machine == NULL || type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT)
476   {
477      fprintf(stderr, ", exiting\n");
478      TerminateProcess(GetCurrentProcess(), MAMERR_FATALERROR);
479   }
480
481   // all other situations attempt to do a clean exit
482   else
483   {
484      fprintf(stderr, ", exit requested\n");
485      g_current_machine->schedule_exit();
486   }
487
488   // in all cases we handled it
489   return TRUE;
490}
491
492
493
494
495//============================================================
496//  output_oslog
497//============================================================
498
499static void output_oslog(const running_machine &machine, const char *buffer)
500{
501   if (IsDebuggerPresent())
502      win_output_debug_string_utf8(buffer);
503}
504
505
506//============================================================
507//  constructor
508//============================================================
509
510windows_osd_interface::windows_osd_interface(windows_options &options)
511: osd_common_t(options), m_options(options)
512{
513}
514
515
516//============================================================
517//  destructor
518//============================================================
519
520windows_osd_interface::~windows_osd_interface()
521{
522}
523
524
525//============================================================
526//  video_register
527//============================================================
528
529void windows_osd_interface::video_register()
530{
531   video_options_add("gdi", NULL);
532   video_options_add("ddraw", NULL);
533   video_options_add("d3d", NULL);
534   video_options_add("bgfx", NULL);
535   //video_options_add("auto", NULL); // making d3d video default one
536}
537
538//============================================================
539//  init
540//============================================================
541
542void windows_osd_interface::init(running_machine &machine)
543{
544   // call our parent
545   osd_common_t::init(machine);
546
547   const char *stemp;
548   windows_options &options = downcast<windows_options &>(machine.options());
549
550   // determine if we are benchmarking, and adjust options appropriately
551   int bench = options.bench();
552   std::string error_string;
553   if (bench > 0)
554   {
555      options.set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM, error_string);
556      options.set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM, error_string);
557      options.set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM, error_string);
558      options.set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM, error_string);
559      assert(error_string.empty());
560   }
561
562   // determine if we are profiling, and adjust options appropriately
563   int profile = options.profile();
564   if (profile > 0)
565   {
566      options.set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM, error_string);
567      options.set_value(OSDOPTION_MULTITHREADING, false, OPTION_PRIORITY_MAXIMUM, error_string);
568      options.set_value(OSDOPTION_NUMPROCESSORS, 1, OPTION_PRIORITY_MAXIMUM, error_string);
569      assert(error_string.empty());
570   }
571
572   // thread priority
573   if (!(machine.debug_flags & DEBUG_FLAG_OSD_ENABLED))
574      SetThreadPriority(GetCurrentThread(), options.priority());
575
576   // get number of processors
577   stemp = options.numprocessors();
578
579   osd_num_processors = 0;
580
581   if (strcmp(stemp, "auto") != 0)
582   {
583      osd_num_processors = atoi(stemp);
584      if (osd_num_processors < 1)
585      {
586         osd_printf_warning("Warning: numprocessors < 1 doesn't make much sense. Assuming auto ...\n");
587         osd_num_processors = 0;
588      }
589   }
590
591   // initialize the subsystems
592   osd_common_t::init_subsystems();
593
594   // notify listeners of screen configuration
595   std::string tempstring;
596   for (win_window_info *info = win_window_list; info != NULL; info = info->m_next)
597   {
598      strprintf(tempstring, "Orientation(%s)", info->m_monitor->devicename());
599      output_set_value(tempstring.c_str(), info->m_targetorient);
600   }
601
602   // hook up the debugger log
603   if (options.oslog())
604      machine.add_logerror_callback(output_oslog);
605
606   // crank up the multimedia timer resolution to its max
607   // this gives the system much finer timeslices
608   timeresult = timeGetDevCaps(&timecaps, sizeof(timecaps));
609   if (timeresult == TIMERR_NOERROR)
610      timeBeginPeriod(timecaps.wPeriodMin);
611
612   // if a watchdog thread is requested, create one
613   int watchdog = options.watchdog();
614   if (watchdog != 0)
615   {
616      watchdog_reset_event = CreateEvent(NULL, FALSE, FALSE, NULL);
617      assert_always(watchdog_reset_event != NULL, "Failed to create watchdog reset event");
618      watchdog_exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
619      assert_always(watchdog_exit_event != NULL, "Failed to create watchdog exit event");
620      watchdog_thread = CreateThread(NULL, 0, watchdog_thread_entry, (LPVOID)(FPTR)watchdog, 0, NULL);
621      assert_always(watchdog_thread != NULL, "Failed to create watchdog thread");
622   }
623
624   // create and start the profiler
625   if (profile > 0)
626   {
627      profiler = global_alloc(sampling_profiler(1000, profile - 1));
628      profiler->start();
629   }
630
631   // initialize sockets
632   win_init_sockets();
633
634   // note the existence of a machine
635   g_current_machine = &machine;
636}
637
638
639//============================================================
640//  osd_exit
641//============================================================
642
643void windows_osd_interface::osd_exit()
644{
645   // no longer have a machine
646   g_current_machine = NULL;
647
648   // cleanup sockets
649   win_cleanup_sockets();
650
651   osd_common_t::osd_exit();
652
653   // take down the watchdog thread if it exists
654   if (watchdog_thread != NULL)
655   {
656      SetEvent(watchdog_exit_event);
657      WaitForSingleObject(watchdog_thread, INFINITE);
658      CloseHandle(watchdog_reset_event);
659      CloseHandle(watchdog_exit_event);
660      CloseHandle(watchdog_thread);
661      watchdog_reset_event = NULL;
662      watchdog_exit_event = NULL;
663      watchdog_thread = NULL;
664   }
665
666   // stop the profiler
667   if (profiler != NULL)
668   {
669      profiler->stop();
670      profiler->print_results(*symbols);
671      global_free(profiler);
672   }
673
674   // restore the timer resolution
675   if (timeresult == TIMERR_NOERROR)
676      timeEndPeriod(timecaps.wPeriodMin);
677
678   // one last pass at events
679   winwindow_process_events(machine(), 0, 0);
680}
681
682//============================================================
683//  winmain_dump_stack
684//============================================================
685
686void winmain_dump_stack()
687{
688   // set up the stack walker
689   stack_walker walker;
690   if (!walker.reset())
691      return;
692
693   // walk the stack
694   while (walker.unwind())
695      fprintf(stderr, "  %p: %p%s\n", (void *)walker.frame(), (void *)walker.ip(), (symbols == NULL) ? "" : symbols->symbol_for_address(walker.ip()));
696}
697
698
699//============================================================
700//  check_for_double_click_start
701//============================================================
702
703static int is_double_click_start(int argc)
704{
705   STARTUPINFO startup_info = { sizeof(STARTUPINFO) };
706
707   // determine our startup information
708   GetStartupInfo(&startup_info);
709
710   // try to determine if MAME was simply double-clicked
711   return (argc <= 1 && startup_info.dwFlags && !(startup_info.dwFlags & STARTF_USESTDHANDLES));
712}
713
714
715//============================================================
716//  watchdog_thread_entry
717//============================================================
718
719static DWORD WINAPI watchdog_thread_entry(LPVOID lpParameter)
720{
721   DWORD timeout = (int)(FPTR)lpParameter * 1000;
722
723   while (TRUE)
724   {
725      HANDLE handle_list[2];
726      DWORD wait_result;
727
728      // wait for either a reset or an exit, or a timeout
729      handle_list[0] = watchdog_reset_event;
730      handle_list[1] = watchdog_exit_event;
731      wait_result = WaitForMultipleObjects(2, handle_list, FALSE, timeout);
732
733      // on a reset, just loop around and re-wait
734      if (wait_result == WAIT_OBJECT_0 + 0)
735         continue;
736
737      // on an exit, break out
738      if (wait_result == WAIT_OBJECT_0 + 1)
739         break;
740
741      // on a timeout, kill the process
742      if (wait_result == WAIT_TIMEOUT)
743      {
744         fprintf(stderr, "Terminating due to watchdog timeout\n");
745         fflush(stderr);
746         TerminateProcess(GetCurrentProcess(), -1);
747      }
748   }
749   return EXCEPTION_CONTINUE_SEARCH;
750}
751
752
753//============================================================
754//  winmain_watchdog_ping
755//============================================================
756
757void winmain_watchdog_ping(void)
758{
759   // if we have a watchdog, reset it
760   if (watchdog_reset_event != NULL)
761      SetEvent(watchdog_reset_event);
762}
763
764
765//============================================================
766//  exception_filter
767//============================================================
768
769static LONG WINAPI exception_filter(struct _EXCEPTION_POINTERS *info)
770{
771   static const struct
772   {
773      DWORD code;
774      const char *string;
775   } exception_table[] =
776   {
777      { EXCEPTION_ACCESS_VIOLATION,       "ACCESS VIOLATION" },
778      { EXCEPTION_DATATYPE_MISALIGNMENT,  "DATATYPE MISALIGNMENT" },
779      { EXCEPTION_BREAKPOINT,             "BREAKPOINT" },
780      { EXCEPTION_SINGLE_STEP,            "SINGLE STEP" },
781      { EXCEPTION_ARRAY_BOUNDS_EXCEEDED,  "ARRAY BOUNDS EXCEEDED" },
782      { EXCEPTION_FLT_DENORMAL_OPERAND,   "FLOAT DENORMAL OPERAND" },
783      { EXCEPTION_FLT_DIVIDE_BY_ZERO,     "FLOAT DIVIDE BY ZERO" },
784      { EXCEPTION_FLT_INEXACT_RESULT,     "FLOAT INEXACT RESULT" },
785      { EXCEPTION_FLT_INVALID_OPERATION,  "FLOAT INVALID OPERATION" },
786      { EXCEPTION_FLT_OVERFLOW,           "FLOAT OVERFLOW" },
787      { EXCEPTION_FLT_STACK_CHECK,        "FLOAT STACK CHECK" },
788      { EXCEPTION_FLT_UNDERFLOW,          "FLOAT UNDERFLOW" },
789      { EXCEPTION_INT_DIVIDE_BY_ZERO,     "INTEGER DIVIDE BY ZERO" },
790      { EXCEPTION_INT_OVERFLOW,           "INTEGER OVERFLOW" },
791      { EXCEPTION_PRIV_INSTRUCTION,       "PRIVILEGED INSTRUCTION" },
792      { EXCEPTION_IN_PAGE_ERROR,          "IN PAGE ERROR" },
793      { EXCEPTION_ILLEGAL_INSTRUCTION,    "ILLEGAL INSTRUCTION" },
794      { EXCEPTION_NONCONTINUABLE_EXCEPTION,"NONCONTINUABLE EXCEPTION" },
795      { EXCEPTION_STACK_OVERFLOW,         "STACK OVERFLOW" },
796      { EXCEPTION_INVALID_DISPOSITION,    "INVALID DISPOSITION" },
797      { EXCEPTION_GUARD_PAGE,             "GUARD PAGE VIOLATION" },
798      { EXCEPTION_INVALID_HANDLE,         "INVALID HANDLE" },
799      { 0,                                "UNKNOWN EXCEPTION" }
800   };
801   static int already_hit = 0;
802   int i;
803
804   // if we're hitting this recursively, just exit
805   if (already_hit)
806      return EXCEPTION_CONTINUE_SEARCH;
807   already_hit = 1;
808
809   // flush any debugging traces that were live
810   debugger_flush_all_traces_on_abnormal_exit();
811
812   // find our man
813   for (i = 0; exception_table[i].code != 0; i++)
814      if (info->ExceptionRecord->ExceptionCode == exception_table[i].code)
815         break;
816
817   // print the exception type and address
818   fprintf(stderr, "\n-----------------------------------------------------\n");
819   fprintf(stderr, "Exception at EIP=%p%s: %s\n", info->ExceptionRecord->ExceptionAddress,
820         symbols->symbol_for_address((FPTR)info->ExceptionRecord->ExceptionAddress), exception_table[i].string);
821
822   // for access violations, print more info
823   if (info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
824      fprintf(stderr, "While attempting to %s memory at %p\n",
825            info->ExceptionRecord->ExceptionInformation[0] ? "write" : "read",
826            (void *)info->ExceptionRecord->ExceptionInformation[1]);
827
828   // print the state of the CPU
829   fprintf(stderr, "-----------------------------------------------------\n");
830#ifdef PTR64
831   fprintf(stderr, "RAX=%p RBX=%p RCX=%p RDX=%p\n",
832         (void *)info->ContextRecord->Rax,
833         (void *)info->ContextRecord->Rbx,
834         (void *)info->ContextRecord->Rcx,
835         (void *)info->ContextRecord->Rdx);
836   fprintf(stderr, "RSI=%p RDI=%p RBP=%p RSP=%p\n",
837         (void *)info->ContextRecord->Rsi,
838         (void *)info->ContextRecord->Rdi,
839         (void *)info->ContextRecord->Rbp,
840         (void *)info->ContextRecord->Rsp);
841   fprintf(stderr, " R8=%p  R9=%p R10=%p R11=%p\n",
842         (void *)info->ContextRecord->R8,
843         (void *)info->ContextRecord->R9,
844         (void *)info->ContextRecord->R10,
845         (void *)info->ContextRecord->R11);
846   fprintf(stderr, "R12=%p R13=%p R14=%p R15=%p\n",
847         (void *)info->ContextRecord->R12,
848         (void *)info->ContextRecord->R13,
849         (void *)info->ContextRecord->R14,
850         (void *)info->ContextRecord->R15);
851#else
852   fprintf(stderr, "EAX=%p EBX=%p ECX=%p EDX=%p\n",
853         (void *)info->ContextRecord->Eax,
854         (void *)info->ContextRecord->Ebx,
855         (void *)info->ContextRecord->Ecx,
856         (void *)info->ContextRecord->Edx);
857   fprintf(stderr, "ESI=%p EDI=%p EBP=%p ESP=%p\n",
858         (void *)info->ContextRecord->Esi,
859         (void *)info->ContextRecord->Edi,
860         (void *)info->ContextRecord->Ebp,
861         (void *)info->ContextRecord->Esp);
862#endif
863
864   stack_walker walker;
865   walker.reset(*info->ContextRecord, GetCurrentThread());
866
867   // reprint the actual exception address
868   fprintf(stderr, "-----------------------------------------------------\n");
869   fprintf(stderr, "Stack crawl:\n");
870
871   // walk the stack
872   while (walker.unwind())
873      fprintf(stderr, "  %p: %p%s\n", (void *)walker.frame(), (void *)walker.ip(), (symbols == NULL) ? "" : symbols->symbol_for_address(walker.ip()));
874
875   // flush stderr, so the data is actually written when output is being redirected
876   fflush(stderr);
877
878   // exit
879   return EXCEPTION_CONTINUE_SEARCH;
880}
881
882
883//**************************************************************************
884//  STACK WALKER
885//**************************************************************************
886
887//-------------------------------------------------
888//  stack_walker - constructor
889//-------------------------------------------------
890
891stack_walker::stack_walker()
892   : m_process(GetCurrentProcess()),
893      m_thread(GetCurrentThread()),
894      m_first(true),
895      m_stack_walk_64(TEXT("dbghelp.dll"), "StackWalk64"),
896      m_sym_initialize(TEXT("dbghelp.dll"), "SymInitialize"),
897      m_sym_function_table_access_64(TEXT("dbghelp.dll"), "SymFunctionTableAccess64"),
898      m_sym_get_module_base_64(TEXT("dbghelp.dll"), "SymGetModuleBase64"),
899      m_rtl_capture_context(TEXT("kernel32.dll"), "RtlCaptureContext")
900{
901   // zap the structs
902   memset(&m_stackframe, 0, sizeof(m_stackframe));
903   memset(&m_context, 0, sizeof(m_context));
904
905   // initialize the symbols
906   if (!s_initialized && m_sym_initialize && m_stack_walk_64 && m_sym_function_table_access_64 && m_sym_get_module_base_64)
907   {
908      (*m_sym_initialize)(m_process, NULL, TRUE);
909      s_initialized = true;
910   }
911}
912
913
914//-------------------------------------------------
915//  reset - set up a new context
916//-------------------------------------------------
917
918bool stack_walker::reset()
919{
920   // set up the initial state
921   if (!m_rtl_capture_context)
922      return false;
923   (*m_rtl_capture_context)(&m_context);
924   m_thread = GetCurrentThread();
925   m_first = true;
926
927   // initialize the stackframe
928   memset(&m_stackframe, 0, sizeof(m_stackframe));
929   m_stackframe.AddrPC.Mode = AddrModeFlat;
930   m_stackframe.AddrFrame.Mode = AddrModeFlat;
931   m_stackframe.AddrStack.Mode = AddrModeFlat;
932
933   // pull architecture-specific fields from the context
934#ifdef PTR64
935   m_stackframe.AddrPC.Offset = m_context.Rip;
936   m_stackframe.AddrFrame.Offset = m_context.Rsp;
937   m_stackframe.AddrStack.Offset = m_context.Rsp;
938#else
939   m_stackframe.AddrPC.Offset = m_context.Eip;
940   m_stackframe.AddrFrame.Offset = m_context.Ebp;
941   m_stackframe.AddrStack.Offset = m_context.Esp;
942#endif
943   return true;
944}
945
946void stack_walker::reset(CONTEXT &initial, HANDLE thread)
947{
948   // set up the initial state
949   m_context = initial;
950   m_thread = thread;
951   m_first = true;
952
953   // initialize the stackframe
954   memset(&m_stackframe, 0, sizeof(m_stackframe));
955   m_stackframe.AddrPC.Mode = AddrModeFlat;
956   m_stackframe.AddrFrame.Mode = AddrModeFlat;
957   m_stackframe.AddrStack.Mode = AddrModeFlat;
958
959   // pull architecture-specific fields from the context
960#ifdef PTR64
961   m_stackframe.AddrPC.Offset = m_context.Rip;
962   m_stackframe.AddrFrame.Offset = m_context.Rsp;
963   m_stackframe.AddrStack.Offset = m_context.Rsp;
964#else
965   m_stackframe.AddrPC.Offset = m_context.Eip;
966   m_stackframe.AddrFrame.Offset = m_context.Ebp;
967   m_stackframe.AddrStack.Offset = m_context.Esp;
968#endif
969}
970
971
972//-------------------------------------------------
973//  unwind - unwind a single level
974//-------------------------------------------------
975
976bool stack_walker::unwind()
977{
978   // if we were able to initialize, then we have everything we need
979   if (s_initialized)
980   {
981#ifdef PTR64
982      return (*m_stack_walk_64)(IMAGE_FILE_MACHINE_AMD64, m_process, m_thread, &m_stackframe, &m_context, NULL, *m_sym_function_table_access_64, *m_sym_get_module_base_64, NULL);
983#else
984      return (*m_stack_walk_64)(IMAGE_FILE_MACHINE_I386, m_process, m_thread, &m_stackframe, &m_context, NULL, *m_sym_function_table_access_64, *m_sym_get_module_base_64, NULL);
985#endif
986   }
987
988   // otherwise, fake the first unwind, which will just return info from the context
989   else
990   {
991      bool result = m_first;
992      m_first = false;
993      return result;
994   }
995}
996
997
998
999//**************************************************************************
1000//  SYMBOL MANAGER
1001//**************************************************************************
1002
1003//-------------------------------------------------
1004//  symbol_manager - constructor
1005//-------------------------------------------------
1006
1007symbol_manager::symbol_manager(const char *argv0)
1008   : m_mapfile(argv0),
1009      m_symfile(argv0),
1010      m_process(GetCurrentProcess()),
1011      m_last_base(0),
1012      m_text_base(0),
1013      m_sym_from_addr(TEXT("dbghelp.dll"), "SymFromAddr"),
1014      m_sym_get_line_from_addr_64(TEXT("dbghelp.dll"), "SymGetLineFromAddr64")
1015{
1016#ifdef __GNUC__
1017   // compute the name of the mapfile
1018   int extoffs = m_mapfile.find_last_of('.');
1019   if (extoffs != -1)
1020      m_mapfile.substr(0, extoffs);
1021   m_mapfile.append(".map");
1022
1023   // and the name of the symfile
1024   extoffs = m_symfile.find_last_of('.');
1025   if (extoffs != -1)
1026      m_symfile = m_symfile.substr(0, extoffs);
1027   m_symfile.append(".sym");
1028
1029   // figure out the base of the .text section
1030   m_text_base = get_text_section_base();
1031#endif
1032
1033   // expand the buffer to be decently large up front
1034   strprintf(m_buffer,"%500s", "");
1035}
1036
1037
1038//-------------------------------------------------
1039//  ~symbol_manager - destructor
1040//-------------------------------------------------
1041
1042symbol_manager::~symbol_manager()
1043{
1044}
1045
1046
1047//-------------------------------------------------
1048//  symbol_for_address - return a symbol by looking
1049//  it up either in the cache or by scanning the
1050//  file
1051//-------------------------------------------------
1052
1053const char *symbol_manager::symbol_for_address(FPTR address)
1054{
1055   // default the buffer
1056   m_buffer.assign(" (not found)");
1057   m_last_base = 0;
1058
1059   // first try to do it using system APIs
1060   if (!query_system_for_address(address))
1061   {
1062      // if that fails, scan the cache if we have one
1063      if (m_cache.first() != NULL)
1064         scan_cache_for_address(address);
1065
1066      // or else try to open a sym/map file and find it there
1067      else
1068         scan_file_for_address(address, false);
1069   }
1070   return m_buffer.c_str();
1071}
1072
1073
1074//-------------------------------------------------
1075//  query_system_for_address - ask the system to
1076//  look up our address
1077//-------------------------------------------------
1078
1079bool symbol_manager::query_system_for_address(FPTR address)
1080{
1081   // need at least the sym_from_addr API
1082   if (!m_sym_from_addr)
1083      return false;
1084
1085   BYTE info_buffer[sizeof(SYMBOL_INFO) + 256] = { 0 };
1086   SYMBOL_INFO &info = *reinterpret_cast<SYMBOL_INFO *>(&info_buffer[0]);
1087   DWORD64 displacement;
1088
1089   // even through the struct says TCHAR, we actually get back an ANSI string here
1090   info.SizeOfStruct = sizeof(info);
1091   info.MaxNameLen = sizeof(info_buffer) - sizeof(info);
1092   if ((*m_sym_from_addr)(m_process, address, &displacement, &info))
1093   {
1094      // try to get source info as well; again we are returned an ANSI string
1095      IMAGEHLP_LINE64 lineinfo = { sizeof(lineinfo) };
1096      DWORD linedisp;
1097      if (m_sym_get_line_from_addr_64 && (*m_sym_get_line_from_addr_64)(m_process, address, &linedisp, &lineinfo))
1098         format_symbol(info.Name, displacement, lineinfo.FileName, lineinfo.LineNumber);
1099      else
1100         format_symbol(info.Name, displacement);
1101
1102      // set the last base
1103      m_last_base = address - displacement;
1104      return true;
1105   }
1106   return false;
1107}
1108
1109
1110//-------------------------------------------------
1111//  scan_file_for_address - walk either the map
1112//  or symbol files and find the best match for
1113//  the given address, optionally creating a cache
1114//  along the way
1115//-------------------------------------------------
1116
1117void symbol_manager::scan_file_for_address(FPTR address, bool create_cache)
1118{
1119   bool is_symfile = false;
1120   FILE *srcfile = NULL;
1121
1122#ifdef __GNUC__
1123   // see if we have a symbol file (gcc only)
1124   srcfile = fopen(m_symfile.c_str(), "r");
1125   is_symfile = (srcfile != NULL);
1126#endif
1127
1128   // if not, see if we have a map file
1129   if (srcfile == NULL)
1130      srcfile = fopen(m_mapfile.c_str(), "r");
1131
1132   // if not, fail
1133   if (srcfile == NULL)
1134      return;
1135
1136   // reset the best info
1137   std::string best_symbol;
1138   FPTR best_addr = 0;
1139
1140   // parse the file, looking for valid entries
1141   std::string symbol;
1142   char line[1024];
1143   while (fgets(line, sizeof(line) - 1, srcfile))
1144   {
1145      // parse the line looking for an interesting symbol
1146      FPTR addr = 0;
1147      bool valid = is_symfile ? parse_sym_line(line, addr, symbol) : parse_map_line(line, addr, symbol);
1148
1149      // if we got one, see if this is the best
1150      if (valid)
1151      {
1152         // if this is the best one so far, remember it
1153         if (addr <= address && addr > best_addr)
1154         {
1155            best_addr = addr;
1156            best_symbol = symbol;
1157         }
1158
1159         // also create a cache entry if we can
1160         if (create_cache)
1161            m_cache.append(*global_alloc(cache_entry(addr, symbol.c_str())));
1162      }
1163   }
1164
1165   // close the file
1166   fclose(srcfile);
1167
1168   // format the symbol and remember the last base
1169   format_symbol(best_symbol.c_str(), address - best_addr);
1170   m_last_base = best_addr;
1171}
1172
1173
1174//-------------------------------------------------
1175//  scan_cache_for_address - walk the cache to
1176//  find the best match for the given address
1177//-------------------------------------------------
1178
1179void symbol_manager::scan_cache_for_address(FPTR address)
1180{
1181   // reset the best info
1182   std::string best_symbol;
1183   FPTR best_addr = 0;
1184
1185   // walk the cache, looking for valid entries
1186   for (cache_entry *entry = m_cache.first(); entry != NULL; entry = entry->next())
1187
1188      // if this is the best one so far, remember it
1189      if (entry->m_address <= address && entry->m_address > best_addr)
1190      {
1191         best_addr = entry->m_address;
1192         best_symbol = entry->m_name;
1193      }
1194
1195   // format the symbol and remember the last base
1196   format_symbol(best_symbol.c_str(), address - best_addr);
1197   m_last_base = best_addr;
1198}
1199
1200
1201//-------------------------------------------------
1202//  parse_sym_line - parse a line from a sym file
1203//  which is just the output of objdump
1204//-------------------------------------------------
1205
1206bool symbol_manager::parse_sym_line(const char *line, FPTR &address, std::string &symbol)
1207{
1208#ifdef __GNUC__
1209/*
1210    32-bit gcc symbol line:
1211[271778](sec  1)(fl 0x00)(ty  20)(scl   3) (nx 0) 0x007df675 line_to_symbol(char const*, unsigned int&, bool)
1212
1213    64-bit gcc symbol line:
1214[271775](sec  1)(fl 0x00)(ty  20)(scl   3) (nx 0) 0x00000000008dd1e9 line_to_symbol(char const*, unsigned long long&, bool)
1215*/
1216
1217   // first look for a (ty) entry
1218   const char *type = strstr(line, "(ty  20)");
1219   if (type == NULL)
1220      return false;
1221
1222   // scan forward in the line to find the address
1223   bool in_parens = false;
1224   for (const char *chptr = type; *chptr != 0; chptr++)
1225   {
1226      // track open/close parentheses
1227      if (*chptr == '(')
1228         in_parens = true;
1229      else if (*chptr == ')')
1230         in_parens = false;
1231
1232      // otherwise, look for an 0x address
1233      else if (!in_parens && *chptr == '0' && chptr[1] == 'x')
1234      {
1235         // make sure we can get an address
1236         void *temp;
1237         if (sscanf(chptr, "0x%p", &temp) != 1)
1238            return false;
1239         address = m_text_base + reinterpret_cast<FPTR>(temp);
1240
1241         // skip forward until we're past the space
1242         while (*chptr != 0 && !isspace(*chptr))
1243            chptr++;
1244
1245         // extract the symbol name
1246         strtrimspace(symbol.assign(chptr));
1247         return (symbol.length() > 0);
1248      }
1249   }
1250#endif
1251   return false;
1252}
1253
1254
1255//-------------------------------------------------
1256//  parse_map_line - parse a line from a linker-
1257//  generated map file
1258//-------------------------------------------------
1259
1260bool symbol_manager::parse_map_line(const char *line, FPTR &address, std::string &symbol)
1261{
1262#ifdef __GNUC__
1263/*
1264    32-bit gcc map line:
1265                0x0089cb00                nbmj9195_palette_r(_address_space const*, unsigned int)
1266
1267    64-bit gcc map line:
1268                0x0000000000961afc                nbmj9195_palette_r(_address_space const*, unsigned int)
1269*/
1270
1271   // find a matching start
1272   if (strncmp(line, "                0x", 18) == 0)
1273   {
1274      // make sure we can get an address
1275      void *temp;
1276      if (sscanf(&line[16], "0x%p", &temp) != 1)
1277         return false;
1278      address = reinterpret_cast<FPTR>(temp);
1279
1280      // skip forward until we're past the space
1281      const char *chptr = &line[16];
1282      while (*chptr != 0 && !isspace(*chptr))
1283         chptr++;
1284
1285      // extract the symbol name
1286      strtrimspace(symbol.assign(chptr));
1287      return (symbol.length() > 0);
1288   }
1289#endif
1290   return false;
1291}
1292
1293
1294//-------------------------------------------------
1295//  format_symbol - common symbol formatting
1296//-------------------------------------------------
1297
1298void symbol_manager::format_symbol(const char *name, UINT32 displacement, const char *filename, int linenumber)
1299{
1300   // start with the address and offset
1301   strprintf(m_buffer, " (%s", name);
1302   if (displacement != 0)
1303      strcatprintf(m_buffer, "+0x%04x", (UINT32)displacement);
1304
1305   // append file/line if present
1306   if (filename != NULL)
1307      strcatprintf(m_buffer, ", %s:%d", filename, linenumber);
1308
1309   // close up the string
1310   m_buffer.append(")");
1311}
1312
1313
1314//-------------------------------------------------
1315//  get_text_section_base - figure out the base
1316//  of the .text section
1317//-------------------------------------------------
1318
1319FPTR symbol_manager::get_text_section_base()
1320{
1321   dynamic_bind<PIMAGE_SECTION_HEADER (WINAPI *)(PIMAGE_NT_HEADERS, PVOID, ULONG)> image_rva_to_section(TEXT("dbghelp.dll"), "ImageRvaToSection");
1322   dynamic_bind<PIMAGE_NT_HEADERS (WINAPI *)(PVOID)> image_nt_header(TEXT("dbghelp.dll"), "ImageNtHeader");
1323
1324   // start with the image base
1325   PVOID base = reinterpret_cast<PVOID>(GetModuleHandleUni());
1326   assert(base != NULL);
1327
1328   // make sure we have the functions we need
1329   if (image_nt_header && image_rva_to_section)
1330   {
1331      // get the NT header
1332      PIMAGE_NT_HEADERS headers = (*image_nt_header)(base);
1333      assert(headers != NULL);
1334
1335      // look ourself up (assuming we are in the .text section)
1336      PIMAGE_SECTION_HEADER section = (*image_rva_to_section)(headers, base, reinterpret_cast<FPTR>(get_text_section_base) - reinterpret_cast<FPTR>(base));
1337      if (section != NULL)
1338         return reinterpret_cast<FPTR>(base) + section->VirtualAddress;
1339   }
1340
1341   // fallback to returning the image base (wrong)
1342   return reinterpret_cast<FPTR>(base);
1343}
1344
1345
1346
1347//**************************************************************************
1348//  SAMPLING PROFILER
1349//**************************************************************************
1350
1351//-------------------------------------------------
1352//  sampling_profiler - constructor
1353//-------------------------------------------------
1354
1355sampling_profiler::sampling_profiler(UINT32 max_seconds, UINT8 stack_depth = 0)
1356   : m_thread(NULL),
1357      m_thread_id(0),
1358      m_thread_exit(false),
1359      m_stack_depth(stack_depth),
1360      m_entry_stride(stack_depth + 2),
1361      m_buffer(max_seconds * 1000 * m_entry_stride),
1362      m_buffer_ptr(&m_buffer[0]),
1363      m_buffer_end(&m_buffer[0] + max_seconds * 1000 * m_entry_stride)
1364{
1365}
1366
1367
1368//-------------------------------------------------
1369//  sampling_profiler - destructor
1370//-------------------------------------------------
1371
1372sampling_profiler::~sampling_profiler()
1373{
1374}
1375
1376
1377//-------------------------------------------------
1378//  start - begin gathering profiling information
1379//-------------------------------------------------
1380
1381void sampling_profiler::start()
1382{
1383   // do the dance to get a handle to ourself
1384   BOOL result = DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &m_target_thread,
1385         THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, FALSE, 0);
1386   assert_always(result, "Failed to get thread handle for main thread");
1387
1388   // reset the exit flag
1389   m_thread_exit = false;
1390
1391   // start the thread
1392   m_thread = CreateThread(NULL, 0, thread_entry, (LPVOID)this, 0, &m_thread_id);
1393   assert_always(m_thread != NULL, "Failed to create profiler thread\n");
1394
1395   // max out the priority
1396   SetThreadPriority(m_thread, THREAD_PRIORITY_TIME_CRITICAL);
1397}
1398
1399
1400//-------------------------------------------------
1401//  stop - stop gathering profiling information
1402//-------------------------------------------------
1403
1404void sampling_profiler::stop()
1405{
1406   // set the flag and wait a couple of seconds (max)
1407   m_thread_exit = true;
1408   WaitForSingleObject(m_thread, 2000);
1409
1410   // regardless, close the handle
1411   CloseHandle(m_thread);
1412}
1413
1414
1415//-------------------------------------------------
1416//  compare_address - compare two entries by their
1417//  bucket address
1418//-------------------------------------------------
1419
1420int CLIB_DECL sampling_profiler::compare_address(const void *item1, const void *item2)
1421{
1422   const FPTR *entry1 = reinterpret_cast<const FPTR *>(item1);
1423   const FPTR *entry2 = reinterpret_cast<const FPTR *>(item2);
1424   int mincount = MIN(entry1[0], entry2[0]);
1425
1426   // sort in order of: bucket, caller, caller's caller, etc.
1427   for (int index = 1; index <= mincount; index++)
1428      if (entry1[index] != entry2[index])
1429         return entry1[index] - entry2[index];
1430
1431   // if we match to the end, sort by the depth of the stack
1432   return entry1[0] - entry2[0];
1433}
1434
1435
1436//-------------------------------------------------
1437//  compare_frequency - compare two entries by
1438//  their frequency of occurrence
1439//-------------------------------------------------
1440
1441int CLIB_DECL sampling_profiler::compare_frequency(const void *item1, const void *item2)
1442{
1443   const FPTR *entry1 = reinterpret_cast<const FPTR *>(item1);
1444   const FPTR *entry2 = reinterpret_cast<const FPTR *>(item2);
1445
1446   // sort by frequency, then by address
1447   if (entry1[0] != entry2[0])
1448      return entry2[0] - entry1[0];
1449   return entry1[1] - entry2[1];
1450}
1451
1452
1453//-------------------------------------------------
1454//  print_results - output the results
1455//-------------------------------------------------
1456
1457void sampling_profiler::print_results(symbol_manager &symbols)
1458{
1459   // cache the symbols
1460   symbols.cache_symbols();
1461
1462   // step 1: find the base of each entry
1463   for (FPTR *current = &m_buffer[0]; current < m_buffer_ptr; current += m_entry_stride)
1464   {
1465      assert(current[0] >= 1 && current[0] < m_entry_stride);
1466
1467      // convert the sampled PC to its function base as a bucket
1468      symbols.symbol_for_address(current[1]);
1469      current[1] = symbols.last_base();
1470   }
1471
1472   // step 2: sort the results
1473   qsort(&m_buffer[0], (m_buffer_ptr - &m_buffer[0]) / m_entry_stride, m_entry_stride * sizeof(FPTR), compare_address);
1474
1475   // step 3: count and collapse unique entries
1476   UINT32 total_count = 0;
1477   for (FPTR *current = &m_buffer[0]; current < m_buffer_ptr; )
1478   {
1479      int count = 1;
1480      FPTR *scan;
1481      for (scan = current + m_entry_stride; scan < m_buffer_ptr; scan += m_entry_stride)
1482      {
1483         if (compare_address(current, scan) != 0)
1484            break;
1485         scan[0] = 0;
1486         count++;
1487      }
1488      current[0] = count;
1489      total_count += count;
1490      current = scan;
1491   }
1492
1493   // step 4: sort the results again, this time by frequency
1494   qsort(&m_buffer[0], (m_buffer_ptr - &m_buffer[0]) / m_entry_stride, m_entry_stride * sizeof(FPTR), compare_frequency);
1495
1496   // step 5: print the results
1497   UINT32 num_printed = 0;
1498   for (FPTR *current = &m_buffer[0]; current < m_buffer_ptr && num_printed < 30; current += m_entry_stride)
1499   {
1500      // once we hit 0 frequency, we're done
1501      if (current[0] == 0)
1502         break;
1503
1504      // output the result
1505      printf("%4.1f%% - %6d : %p%s\n", (double)current[0] * 100.0 / (double)total_count, (UINT32)current[0], reinterpret_cast<void *>(current[1]), symbols.symbol_for_address(current[1]));
1506      for (int index = 2; index < m_entry_stride; index++)
1507      {
1508         if (current[index] == 0)
1509            break;
1510         printf("                 %p%s\n", reinterpret_cast<void *>(current[index]), symbols.symbol_for_address(current[index]));
1511      }
1512      printf("\n");
1513      num_printed++;
1514   }
1515   symbols.reset_cache();
1516}
1517
1518
1519//-------------------------------------------------
1520//  thread_entry - thread entry stub
1521//-------------------------------------------------
1522
1523DWORD WINAPI sampling_profiler::thread_entry(LPVOID lpParameter)
1524{
1525   reinterpret_cast<sampling_profiler *>(lpParameter)->thread_run();
1526   return 0;
1527}
1528
1529
1530//-------------------------------------------------
1531//  thread_run - sampling thread
1532//-------------------------------------------------
1533
1534void sampling_profiler::thread_run()
1535{
1536   CONTEXT context;
1537   memset(&context, 0, sizeof(context));
1538
1539   // loop until done
1540   stack_walker walker;
1541   while (!m_thread_exit && m_buffer_ptr < m_buffer_end)
1542   {
1543      // pause the main thread and get its context
1544      SuspendThread(m_target_thread);
1545      context.ContextFlags = CONTEXT_FULL;
1546      GetThreadContext(m_target_thread, &context);
1547
1548      // first entry is a count
1549      FPTR *count = m_buffer_ptr++;
1550      *count = 0;
1551
1552      // iterate over the frames until we run out or hit an error
1553      walker.reset(context, m_target_thread);
1554      int frame;
1555      for (frame = 0; frame <= m_stack_depth && walker.unwind(); frame++)
1556      {
1557         *m_buffer_ptr++ = walker.ip();
1558         *count += 1;
1559      }
1560
1561      // fill in any missing parts with NULLs
1562      for (; frame <= m_stack_depth; frame++)
1563         *m_buffer_ptr++ = 0;
1564
1565      // resume the thread
1566      ResumeThread(m_target_thread);
1567
1568      // sleep for 1ms
1569      Sleep(1);
1570   }
1571}
trunk/src/osd/windows/winmain.cpp
r0r250288
1// license:BSD-3-Clause
2// copyright-holders:Aaron Giles
3//============================================================
4//
5//  winmain.c - Win32 main program
6//
7//============================================================
8
9// standard windows headers
10#define WIN32_LEAN_AND_MEAN
11#include <windows.h>
12#include <commctrl.h>
13#include <mmsystem.h>
14#include <tchar.h>
15#include <io.h>
16
17// standard C headers
18#include <ctype.h>
19#include <stdarg.h>
20#include <psapi.h>
21#include <dbghelp.h>
22
23// MAME headers
24#include "emu.h"
25#include "clifront.h"
26#include "emuopts.h"
27
28// MAMEOS headers
29#include "winmain.h"
30#include "window.h"
31#include "video.h"
32#include "input.h"
33#include "output.h"
34#include "config.h"
35#include "osdepend.h"
36#include "strconv.h"
37#include "winutf8.h"
38#include "winutil.h"
39#include "debugger.h"
40#include "winfile.h"
41
42#define DEBUG_SLOW_LOCKS    0
43
44//**************************************************************************
45//  MACROS
46//**************************************************************************
47
48#ifdef UNICODE
49#define UNICODE_POSTFIX "W"
50#else
51#define UNICODE_POSTFIX "A"
52#endif
53
54
55
56//**************************************************************************
57//  TYPE DEFINITIONS
58//**************************************************************************
59
60template<typename _FunctionPtr>
61class dynamic_bind
62{
63public:
64   // constructor which looks up the function
65   dynamic_bind(const TCHAR *dll, const char *symbol)
66      : m_function(NULL)
67   {
68      HMODULE module = LoadLibrary(dll);
69      if (module != NULL)
70         m_function = reinterpret_cast<_FunctionPtr>(GetProcAddress(module, symbol));
71   }
72
73   // bool to test if the function is NULL or not
74   operator bool() const { return (m_function != NULL); }
75
76   // dereference to get the underlying pointer
77   _FunctionPtr operator *() const { return m_function; }
78
79private:
80   _FunctionPtr    m_function;
81};
82
83
84class stack_walker
85{
86public:
87   stack_walker();
88
89   FPTR ip() const { return m_stackframe.AddrPC.Offset; }
90   FPTR sp() const { return m_stackframe.AddrStack.Offset; }
91   FPTR frame() const { return m_stackframe.AddrFrame.Offset; }
92
93   bool reset();
94   void reset(CONTEXT &context, HANDLE thread);
95   bool unwind();
96
97private:
98   HANDLE          m_process;
99   HANDLE          m_thread;
100   STACKFRAME64    m_stackframe;
101   CONTEXT         m_context;
102   bool            m_first;
103
104   dynamic_bind<BOOL (WINAPI *)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64)>
105         m_stack_walk_64;
106   dynamic_bind<BOOL (WINAPI *)(HANDLE, LPCTSTR, BOOL)> m_sym_initialize;
107   dynamic_bind<PVOID (WINAPI *)(HANDLE, DWORD64)> m_sym_function_table_access_64;
108   dynamic_bind<DWORD64 (WINAPI *)(HANDLE, DWORD64)> m_sym_get_module_base_64;
109   dynamic_bind<VOID (WINAPI *)(PCONTEXT)> m_rtl_capture_context;
110
111   static bool     s_initialized;
112};
113
114
115class symbol_manager
116{
117public:
118   // construction/destruction
119   symbol_manager(const char *argv0);
120   ~symbol_manager();
121
122   // getters
123   FPTR last_base() const { return m_last_base; }
124
125   // core symbol lookup
126   const char *symbol_for_address(FPTR address);
127   const char *symbol_for_address(PVOID address) { return symbol_for_address(reinterpret_cast<FPTR>(address)); }
128
129   // force symbols to be cached
130   void cache_symbols() { scan_file_for_address(0, true); }
131
132   void reset_cache() { m_cache.reset(); }
133private:
134   // internal helpers
135   bool query_system_for_address(FPTR address);
136   void scan_file_for_address(FPTR address, bool create_cache);
137   bool parse_sym_line(const char *line, FPTR &address, std::string &symbol);
138   bool parse_map_line(const char *line, FPTR &address, std::string &symbol);
139   void scan_cache_for_address(FPTR address);
140   void format_symbol(const char *name, UINT32 displacement, const char *filename = NULL, int linenumber = 0);
141
142   static FPTR get_text_section_base();
143
144   struct cache_entry
145   {
146      cache_entry(FPTR address, const char *symbol) :
147         m_next(NULL), m_address(address), m_name(symbol) { }
148      cache_entry *next() const { return m_next; }
149
150      cache_entry *   m_next;
151      FPTR            m_address;
152      std::string     m_name;
153   };
154   simple_list<cache_entry> m_cache;
155
156   std::string     m_mapfile;
157   std::string     m_symfile;
158   std::string     m_buffer;
159   HANDLE          m_process;
160   FPTR            m_last_base;
161   FPTR            m_text_base;
162
163   dynamic_bind<BOOL (WINAPI *)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO)> m_sym_from_addr;
164   dynamic_bind<BOOL (WINAPI *)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64)> m_sym_get_line_from_addr_64;
165};
166
167
168class sampling_profiler
169{
170public:
171   sampling_profiler(UINT32 max_seconds, UINT8 stack_depth);
172   ~sampling_profiler();
173
174   void start();
175   void stop();
176
177//  void reset();
178   void print_results(symbol_manager &symbols);
179
180private:
181   static DWORD WINAPI thread_entry(LPVOID lpParameter);
182   void thread_run();
183
184   static int CLIB_DECL compare_address(const void *item1, const void *item2);
185   static int CLIB_DECL compare_frequency(const void *item1, const void *item2);
186
187   HANDLE          m_target_thread;
188
189   HANDLE          m_thread;
190   DWORD           m_thread_id;
191   volatile bool   m_thread_exit;
192
193   UINT8           m_stack_depth;
194   UINT8           m_entry_stride;
195   std::vector<FPTR>    m_buffer;
196   FPTR *          m_buffer_ptr;
197   FPTR *          m_buffer_end;
198};
199
200//============================================================
201//  winui_output_error
202//============================================================
203
204class winui_output_error : public osd_output
205{
206public:
207   virtual void output_callback(osd_output_channel channel, const char *msg, va_list args)
208   {
209      if (channel == OSD_OUTPUT_CHANNEL_ERROR)
210      {
211         char buffer[1024];
212
213         // if we are in fullscreen mode, go to windowed mode
214         if ((video_config.windowed == 0) && (win_window_list != NULL))
215            winwindow_toggle_full_screen();
216
217         vsnprintf(buffer, ARRAY_LENGTH(buffer), msg, args);
218         win_message_box_utf8(win_window_list ? win_window_list->m_hwnd : NULL, buffer, emulator_info::get_appname(), MB_OK);
219      }
220      else
221         chain_output(channel, msg, args);
222   }
223};
224
225
226
227
228//**************************************************************************
229//  GLOBAL VARIABLES
230//**************************************************************************
231
232// this line prevents globbing on the command line
233int _CRT_glob = 0;
234
235//**************************************************************************
236//  LOCAL VARIABLES
237//**************************************************************************
238
239static LPTOP_LEVEL_EXCEPTION_FILTER pass_thru_filter;
240
241static HANDLE watchdog_reset_event;
242static HANDLE watchdog_exit_event;
243static HANDLE watchdog_thread;
244
245static running_machine *g_current_machine;
246
247static int timeresult = !TIMERR_NOERROR;
248static TIMECAPS timecaps;
249
250static sampling_profiler *profiler = NULL;
251static symbol_manager *symbols = NULL;
252
253bool stack_walker::s_initialized = false;
254
255
256//**************************************************************************
257//  FUNCTION PROTOTYPES
258//**************************************************************************
259
260static BOOL WINAPI control_handler(DWORD type);
261static int is_double_click_start(int argc);
262static DWORD WINAPI watchdog_thread_entry(LPVOID lpParameter);
263static LONG WINAPI exception_filter(struct _EXCEPTION_POINTERS *info);
264
265
266
267//**************************************************************************
268//  OPTIONS
269//**************************************************************************
270
271// struct definitions
272const options_entry windows_options::s_option_entries[] =
273{
274   // performance options
275   { NULL,                                           NULL,       OPTION_HEADER,     "WINDOWS PERFORMANCE OPTIONS" },
276   { WINOPTION_PRIORITY "(-15-1)",                   "0",        OPTION_INTEGER,    "thread priority for the main game thread; range from -15 to 1" },
277   { WINOPTION_PROFILE,                              "0",        OPTION_INTEGER,    "enables profiling, specifying the stack depth to track" },
278
279   // video options
280   { NULL,                                           NULL,       OPTION_HEADER,     "WINDOWS VIDEO OPTIONS" },
281   { WINOPTION_MENU,                                 "0",        OPTION_BOOLEAN,    "enables menu bar if available by UI implementation" },
282
283   // DirectDraw-specific options
284   { NULL,                                           NULL,       OPTION_HEADER,     "DIRECTDRAW-SPECIFIC OPTIONS" },
285   { WINOPTION_HWSTRETCH ";hws",                     "1",        OPTION_BOOLEAN,    "enables hardware stretching" },
286
287   // post-processing options
288   { NULL,                                                     NULL,        OPTION_HEADER,     "DIRECT3D POST-PROCESSING OPTIONS" },
289   { WINOPTION_HLSL_ENABLE";hlsl",                             "0",         OPTION_BOOLEAN,    "enables HLSL post-processing (PS3.0 required)" },
290   { WINOPTION_HLSLPATH,                                       "hlsl",      OPTION_STRING,     "path to hlsl files" },
291   { WINOPTION_HLSL_PRESCALE_X,                                "0",         OPTION_INTEGER,    "HLSL pre-scale override factor for X (0 for auto)" },
292   { WINOPTION_HLSL_PRESCALE_Y,                                "0",         OPTION_INTEGER,    "HLSL pre-scale override factor for Y (0 for auto)" },
293   { WINOPTION_HLSL_WRITE,                                     NULL,        OPTION_STRING,     "enables HLSL AVI writing (huge disk bandwidth suggested)" },
294   { WINOPTION_HLSL_SNAP_WIDTH,                                "2048",      OPTION_STRING,     "HLSL upscaled-snapshot width" },
295   { WINOPTION_HLSL_SNAP_HEIGHT,                               "1536",      OPTION_STRING,     "HLSL upscaled-snapshot height" },
296   { WINOPTION_SHADOW_MASK_ALPHA";fs_shadwa(0.0-1.0)",         "0.0",       OPTION_FLOAT,      "shadow mask alpha-blend value (1.0 is fully blended, 0.0 is no mask)" },
297   { WINOPTION_SHADOW_MASK_TEXTURE";fs_shadwt(0.0-1.0)",       "aperture.png", OPTION_STRING,  "shadow mask texture name" },
298   { WINOPTION_SHADOW_MASK_COUNT_X";fs_shadww",                "6",         OPTION_INTEGER,    "shadow mask tile width, in screen dimensions" },
299   { WINOPTION_SHADOW_MASK_COUNT_Y";fs_shadwh",                "6",         OPTION_INTEGER,    "shadow mask tile height, in screen dimensions" },
300   { WINOPTION_SHADOW_MASK_USIZE";fs_shadwu(0.0-1.0)",         "0.1875",    OPTION_FLOAT,      "shadow mask texture width, in U/V dimensions" },
301   { WINOPTION_SHADOW_MASK_VSIZE";fs_shadwv(0.0-1.0)",         "0.1875",    OPTION_FLOAT,      "shadow mask texture height, in U/V dimensions" },
302   { WINOPTION_SHADOW_MASK_UOFFSET";fs_shadwou(-1.0-1.0)",     "0.0",       OPTION_FLOAT,      "shadow mask texture offset, in U direction" },
303   { WINOPTION_SHADOW_MASK_VOFFSET";fs_shadwov(-1.0-1.0)",     "0.0",       OPTION_FLOAT,      "shadow mask texture offset, in V direction" },
304   { WINOPTION_CURVATURE";fs_curv(0.0-1.0)",                   "0.0",       OPTION_FLOAT,      "screen curvature amount" },
305   { WINOPTION_ROUND_CORNER";fs_rndc(0.0-1.0)",                "0.0",       OPTION_FLOAT,      "screen round corner amount" },
306   { WINOPTION_SMOOTH_BORDER";fs_smob(0.0-1.0)",               "0.0",       OPTION_FLOAT,      "screen smooth border amount" },
307   { WINOPTION_REFLECTION";fs_ref(0.0-1.0)",                   "0.0",       OPTION_FLOAT,      "screen reflection amount" },
308   { WINOPTION_VIGNETTING";fs_vig(0.0-1.0)",                   "0.0",       OPTION_FLOAT,      "image vignetting amount" },
309   /* Beam-related values below this line*/
310   { WINOPTION_SCANLINE_AMOUNT";fs_scanam(0.0-4.0)",           "1.0",       OPTION_FLOAT,      "overall alpha scaling value for scanlines" },
311   { WINOPTION_SCANLINE_SCALE";fs_scansc(0.0-4.0)",            "1.0",       OPTION_FLOAT,      "overall height scaling value for scanlines" },
312   { WINOPTION_SCANLINE_HEIGHT";fs_scanh(0.0-4.0)",            "1.0",       OPTION_FLOAT,      "individual height scaling value for scanlines" },
313   { WINOPTION_SCANLINE_BRIGHT_SCALE";fs_scanbs(0.0-2.0)",     "1.0",       OPTION_FLOAT,      "overall brightness scaling value for scanlines (multiplicative)" },
314   { WINOPTION_SCANLINE_BRIGHT_OFFSET";fs_scanbo(0.0-1.0)",    "0.0",       OPTION_FLOAT,      "overall brightness offset value for scanlines (additive)" },
315   { WINOPTION_SCANLINE_OFFSET";fs_scanjt(0.0-4.0)",           "0.0",       OPTION_FLOAT,      "overall interlace jitter scaling value for scanlines" },
316   { WINOPTION_DEFOCUS";fs_focus",                             "0.0,0.0",   OPTION_STRING,     "overall defocus value in screen-relative coords" },
317   { WINOPTION_CONVERGE_X";fs_convx",                          "0.3,0.0,-0.3",OPTION_STRING,   "convergence in screen-relative X direction" },
318   { WINOPTION_CONVERGE_Y";fs_convy",                          "0.0,0.3,-0.3",OPTION_STRING,   "convergence in screen-relative Y direction" },
319   { WINOPTION_RADIAL_CONVERGE_X";fs_rconvx",                  "0.0,0.0,0.0",OPTION_STRING,    "radial convergence in screen-relative X direction" },
320   { WINOPTION_RADIAL_CONVERGE_Y";fs_rconvy",                  "0.0,0.0,0.0",OPTION_STRING,    "radial convergence in screen-relative Y direction" },
321   /* RGB colorspace convolution below this line */
322   { WINOPTION_RED_RATIO";fs_redratio",                        "1.0,0.0,0.0",OPTION_STRING,    "red output signal generated by input signal" },
323   { WINOPTION_GRN_RATIO";fs_grnratio",                        "0.0,1.0,0.0",OPTION_STRING,    "green output signal generated by input signal" },
324   { WINOPTION_BLU_RATIO";fs_bluratio",                        "0.0,0.0,1.0",OPTION_STRING,    "blue output signal generated by input signal" },
325   { WINOPTION_SATURATION";fs_sat(0.0-4.0)",                   "1.4",        OPTION_FLOAT,     "saturation scaling value" },
326   { WINOPTION_OFFSET";fs_offset",                             "0.0,0.0,0.0",OPTION_STRING,    "signal offset value (additive)" },
327   { WINOPTION_SCALE";fs_scale",                               "0.95,0.95,0.95",OPTION_STRING, "signal scaling value (multiplicative)" },
328   { WINOPTION_POWER";fs_power",                               "0.8,0.8,0.8",OPTION_STRING,    "signal power value (exponential)" },
329   { WINOPTION_FLOOR";fs_floor",                               "0.05,0.05,0.05",OPTION_STRING, "signal floor level" },
330   { WINOPTION_PHOSPHOR";fs_phosphor",                         "0.4,0.4,0.4",OPTION_STRING,    "phosphorescence decay rate (0.0 is instant, 1.0 is forever)" },
331   /* NTSC simulation below this line */
332   { NULL,                                                     NULL,        OPTION_HEADER,     "NTSC POST-PROCESSING OPTIONS" },
333   { WINOPTION_YIQ_ENABLE";yiq",                               "0",         OPTION_BOOLEAN,    "enables YIQ-space HLSL post-processing" },
334   { WINOPTION_YIQ_CCVALUE";yiqcc",                            "3.59754545",OPTION_FLOAT,      "Color Carrier frequency for NTSC signal processing" },
335   { WINOPTION_YIQ_AVALUE";yiqa",                              "0.5",       OPTION_FLOAT,      "A value for NTSC signal processing" },
336   { WINOPTION_YIQ_BVALUE";yiqb",                              "0.5",       OPTION_FLOAT,      "B value for NTSC signal processing" },
337   { WINOPTION_YIQ_OVALUE";yiqo",                              "1.570796325",OPTION_FLOAT,     "Outgoing Color Carrier phase offset for NTSC signal processing" },
338   { WINOPTION_YIQ_PVALUE";yiqp",                              "1.0",       OPTION_FLOAT,      "Incoming Pixel Clock scaling value for NTSC signal processing" },
339   { WINOPTION_YIQ_NVALUE";yiqn",                              "1.0",       OPTION_FLOAT,      "Y filter notch width for NTSC signal processing" },
340   { WINOPTION_YIQ_YVALUE";yiqy",                              "6.0",       OPTION_FLOAT,      "Y filter cutoff frequency for NTSC signal processing" },
341   { WINOPTION_YIQ_IVALUE";yiqi",                              "1.2",       OPTION_FLOAT,      "I filter cutoff frequency for NTSC signal processing" },
342   { WINOPTION_YIQ_QVALUE";yiqq",                              "0.6",       OPTION_FLOAT,      "Q filter cutoff frequency for NTSC signal processing" },
343   { WINOPTION_YIQ_SCAN_TIME";yiqsc",                          "52.6",      OPTION_FLOAT,      "Horizontal scanline duration for NTSC signal processing (in usec)" },
344   { WINOPTION_YIQ_PHASE_COUNT";yiqp",                         "2",         OPTION_INTEGER,    "Phase Count value for NTSC signal processing" },
345   { WINOPTION_YIQ_SCAN_TIME";yiqsc",                          "52.6",      OPTION_FLOAT,      "Horizontal scanline duration for NTSC signal processing (in usec)" },
346   { WINOPTION_YIQ_PHASE_COUNT";yiqp",                         "2",         OPTION_INTEGER,    "Phase Count value for NTSC signal processing" },
347   /* Vector simulation below this line */
348   { NULL,                                                     NULL,        OPTION_HEADER,     "VECTOR POST-PROCESSING OPTIONS" },
349   { WINOPTION_VECTOR_LENGTH_SCALE";veclength",                "0.8",       OPTION_FLOAT,      "How much length affects vector fade" },
350   { WINOPTION_VECTOR_LENGTH_RATIO";vecsize",                  "500.0",     OPTION_FLOAT,      "Vector fade length (4.0 - vectors fade the most at and above 4 pixels, etc.)" },
351   /* Bloom below this line */
352   { NULL,                                                     NULL,        OPTION_HEADER,     "BLOOM POST-PROCESSING OPTIONS" },
353   { WINOPTION_BLOOM_SCALE,                                    "0.25",      OPTION_FLOAT,      "Intensity factor for bloom" },
354   { WINOPTION_BLOOM_OVERDRIVE,                                "0.0,0.0,0.0",OPTION_STRING,    "Overdrive factor for bloom" },
355   { WINOPTION_BLOOM_LEVEL0_WEIGHT,                            "1.0",       OPTION_FLOAT,      "Bloom level 0  (full-size target) weight" },
356   { WINOPTION_BLOOM_LEVEL1_WEIGHT,                            "0.21",      OPTION_FLOAT,      "Bloom level 1  (half-size target) weight" },
357   { WINOPTION_BLOOM_LEVEL2_WEIGHT,                            "0.19",      OPTION_FLOAT,      "Bloom level 2  (quarter-size target) weight" },
358   { WINOPTION_BLOOM_LEVEL3_WEIGHT,                            "0.17",      OPTION_FLOAT,      "Bloom level 3  (.) weight" },
359   { WINOPTION_BLOOM_LEVEL4_WEIGHT,                            "0.15",      OPTION_FLOAT,      "Bloom level 4  (.) weight" },
360   { WINOPTION_BLOOM_LEVEL5_WEIGHT,                            "0.14",      OPTION_FLOAT,      "Bloom level 5  (.) weight" },
361   { WINOPTION_BLOOM_LEVEL6_WEIGHT,                            "0.13",      OPTION_FLOAT,      "Bloom level 6  (.) weight" },
362   { WINOPTION_BLOOM_LEVEL7_WEIGHT,                            "0.12",      OPTION_FLOAT,      "Bloom level 7  (.) weight" },
363   { WINOPTION_BLOOM_LEVEL8_WEIGHT,                            "0.11",      OPTION_FLOAT,      "Bloom level 8  (.) weight" },
364   { WINOPTION_BLOOM_LEVEL9_WEIGHT,                            "0.10",      OPTION_FLOAT,      "Bloom level 9  (.) weight" },
365   { WINOPTION_BLOOM_LEVEL10_WEIGHT,                           "0.09",      OPTION_FLOAT,      "Bloom level 10 (1x1 target) weight" },
366
367   // full screen options
368   { NULL,                                           NULL,       OPTION_HEADER,     "FULL SCREEN OPTIONS" },
369   { WINOPTION_TRIPLEBUFFER ";tb",                   "0",        OPTION_BOOLEAN,    "enables triple buffering" },
370   { WINOPTION_FULLSCREENBRIGHTNESS ";fsb(0.1-2.0)", "1.0",      OPTION_FLOAT,      "brightness value in full screen mode" },
371   { WINOPTION_FULLSCREENCONTRAST ";fsc(0.1-2.0)",   "1.0",      OPTION_FLOAT,      "contrast value in full screen mode" },
372   { WINOPTION_FULLSCREENGAMMA ";fsg(0.1-3.0)",      "1.0",      OPTION_FLOAT,      "gamma value in full screen mode" },
373
374   // input options
375   { NULL,                                           NULL,       OPTION_HEADER,     "INPUT DEVICE OPTIONS" },
376   { WINOPTION_GLOBAL_INPUTS ";global_inputs",       "0",        OPTION_BOOLEAN,    "enables global inputs" },
377   { WINOPTION_DUAL_LIGHTGUN ";dual",                "0",        OPTION_BOOLEAN,    "enables dual lightgun input" },
378
379   { NULL }
380};
381
382//**************************************************************************
383//  MAIN ENTRY POINT
384//**************************************************************************
385
386
387//============================================================
388//  utf8_main
389//============================================================
390
391int main(int argc, char *argv[])
392{
393   // use small output buffers on non-TTYs (i.e. pipes)
394   if (!isatty(fileno(stdout)))
395      setvbuf(stdout, (char *) NULL, _IOFBF, 64);
396   if (!isatty(fileno(stderr)))
397      setvbuf(stderr, (char *) NULL, _IOFBF, 64);
398
399   // initialize common controls
400   InitCommonControls();
401
402   // set a handler to catch ctrl-c
403   SetConsoleCtrlHandler(control_handler, TRUE);
404
405   // allocate symbols
406   symbol_manager local_symbols(argv[0]);
407   symbols = &local_symbols;
408
409   // set up exception handling
410   pass_thru_filter = SetUnhandledExceptionFilter(exception_filter);
411   SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
412
413   // enable stack crawls for asserts
414   extern void (*s_debugger_stack_crawler)();
415   s_debugger_stack_crawler = winmain_dump_stack;
416
417
418   // parse config and cmdline options
419   DWORD result = 0;
420   {
421      windows_options options;
422      windows_osd_interface osd(options);
423      // if we're a GUI app, out errors to message boxes
424      // Initialize this after the osd interface so that we are first in the
425      // output order
426      winui_output_error winerror;
427      if (win_is_gui_application() || is_double_click_start(argc))
428      {
429         // if we are a GUI app, output errors to message boxes
430         osd_output::push(&winerror);
431         // make sure any console window that opened on our behalf is nuked
432         FreeConsole();
433      }
434      osd.register_options();
435      cli_frontend frontend(options, osd);
436      result = frontend.execute(argc, argv);
437      osd_output::pop(&winerror);
438   }
439   // free symbols
440   symbols = NULL;
441   return result;
442}
443
444
445//============================================================
446//  windows_options
447//============================================================
448
449windows_options::windows_options()
450: osd_options()
451{
452   add_entries(s_option_entries);
453}
454
455
456//============================================================
457//  control_handler
458//============================================================
459
460static BOOL WINAPI control_handler(DWORD type)
461{
462   // indicate to the user that we detected something
463   switch (type)
464   {
465      case CTRL_C_EVENT:          fprintf(stderr, "Caught Ctrl+C");                   break;
466      case CTRL_BREAK_EVENT:      fprintf(stderr, "Caught Ctrl+break");               break;
467      case CTRL_CLOSE_EVENT:      fprintf(stderr, "Caught console close");            break;
468      case CTRL_LOGOFF_EVENT:     fprintf(stderr, "Caught logoff");                   break;
469      case CTRL_SHUTDOWN_EVENT:   fprintf(stderr, "Caught shutdown");                 break;
470      default:                    fprintf(stderr, "Caught unexpected console event"); break;
471   }
472
473   // if we don't have a machine yet, or if we are handling ctrl+c/ctrl+break,
474   // just terminate hard, without throwing or handling any atexit stuff
475   if (g_current_machine == NULL || type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT)
476   {
477      fprintf(stderr, ", exiting\n");
478      TerminateProcess(GetCurrentProcess(), MAMERR_FATALERROR);
479   }
480
481   // all other situations attempt to do a clean exit
482   else
483   {
484      fprintf(stderr, ", exit requested\n");
485      g_current_machine->schedule_exit();
486   }
487
488   // in all cases we handled it
489   return TRUE;
490}
491
492
493
494
495//============================================================
496//  output_oslog
497//============================================================
498
499static void output_oslog(const running_machine &machine, const char *buffer)
500{
501   if (IsDebuggerPresent())
502      win_output_debug_string_utf8(buffer);
503}
504
505
506//============================================================
507//  constructor
508//============================================================
509
510windows_osd_interface::windows_osd_interface(windows_options &options)
511: osd_common_t(options), m_options(options)
512{
513}
514
515
516//============================================================
517//  destructor
518//============================================================
519
520windows_osd_interface::~windows_osd_interface()
521{
522}
523
524
525//============================================================
526//  video_register
527//============================================================
528
529void windows_osd_interface::video_register()
530{
531   video_options_add("gdi", NULL);
532   video_options_add("ddraw", NULL);
533   video_options_add("d3d", NULL);
534   video_options_add("bgfx", NULL);
535   //video_options_add("auto", NULL); // making d3d video default one
536}
537
538//============================================================
539//  init
540//============================================================
541
542void windows_osd_interface::init(running_machine &machine)
543{
544   // call our parent
545   osd_common_t::init(machine);
546
547   const char *stemp;
548   windows_options &options = downcast<windows_options &>(machine.options());
549
550   // determine if we are benchmarking, and adjust options appropriately
551   int bench = options.bench();
552   std::string error_string;
553   if (bench > 0)
554   {
555      options.set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM, error_string);
556      options.set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM, error_string);
557      options.set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM, error_string);
558      options.set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM, error_string);
559      assert(error_string.empty());
560   }
561
562   // determine if we are profiling, and adjust options appropriately
563   int profile = options.profile();
564   if (profile > 0)
565   {
566      options.set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM, error_string);
567      options.set_value(OSDOPTION_MULTITHREADING, false, OPTION_PRIORITY_MAXIMUM, error_string);
568      options.set_value(OSDOPTION_NUMPROCESSORS, 1, OPTION_PRIORITY_MAXIMUM, error_string);
569      assert(error_string.empty());
570   }
571
572   // thread priority
573   if (!(machine.debug_flags & DEBUG_FLAG_OSD_ENABLED))
574      SetThreadPriority(GetCurrentThread(), options.priority());
575
576   // get number of processors
577   stemp = options.numprocessors();
578
579   osd_num_processors = 0;
580
581   if (strcmp(stemp, "auto") != 0)
582   {
583      osd_num_processors = atoi(stemp);
584      if (osd_num_processors < 1)
585      {
586         osd_printf_warning("Warning: numprocessors < 1 doesn't make much sense. Assuming auto ...\n");
587         osd_num_processors = 0;
588      }
589   }
590
591   // initialize the subsystems
592   osd_common_t::init_subsystems();
593
594   // notify listeners of screen configuration
595   std::string tempstring;
596   for (win_window_info *info = win_window_list; info != NULL; info = info->m_next)
597   {
598      strprintf(tempstring, "Orientation(%s)", info->m_monitor->devicename());
599      output_set_value(tempstring.c_str(), info->m_targetorient);
600   }
601
602   // hook up the debugger log
603   if (options.oslog())
604      machine.add_logerror_callback(output_oslog);
605
606   // crank up the multimedia timer resolution to its max
607   // this gives the system much finer timeslices
608   timeresult = timeGetDevCaps(&timecaps, sizeof(timecaps));
609   if (timeresult == TIMERR_NOERROR)
610      timeBeginPeriod(timecaps.wPeriodMin);
611
612   // if a watchdog thread is requested, create one
613   int watchdog = options.watchdog();
614   if (watchdog != 0)
615   {
616      watchdog_reset_event = CreateEvent(NULL, FALSE, FALSE, NULL);
617      assert_always(watchdog_reset_event != NULL, "Failed to create watchdog reset event");
618      watchdog_exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
619      assert_always(watchdog_exit_event != NULL, "Failed to create watchdog exit event");
620      watchdog_thread = CreateThread(NULL, 0, watchdog_thread_entry, (LPVOID)(FPTR)watchdog, 0, NULL);
621      assert_always(watchdog_thread != NULL, "Failed to create watchdog thread");
622   }
623
624   // create and start the profiler
625   if (profile > 0)
626   {
627      profiler = global_alloc(sampling_profiler(1000, profile - 1));
628      profiler->start();
629   }
630
631   // initialize sockets
632   win_init_sockets();
633
634   // note the existence of a machine
635   g_current_machine = &machine;
636}
637
638
639//============================================================
640//  osd_exit
641//============================================================
642
643void windows_osd_interface::osd_exit()
644{
645   // no longer have a machine
646   g_current_machine = NULL;
647
648   // cleanup sockets
649   win_cleanup_sockets();
650
651   osd_common_t::osd_exit();
652
653   // take down the watchdog thread if it exists
654   if (watchdog_thread != NULL)
655   {
656      SetEvent(watchdog_exit_event);
657      WaitForSingleObject(watchdog_thread, INFINITE);
658      CloseHandle(watchdog_reset_event);
659      CloseHandle(watchdog_exit_event);
660      CloseHandle(watchdog_thread);
661      watchdog_reset_event = NULL;
662      watchdog_exit_event = NULL;
663      watchdog_thread = NULL;
664   }
665
666   // stop the profiler
667   if (profiler != NULL)
668   {
669      profiler->stop();
670      profiler->print_results(*symbols);
671      global_free(profiler);
672   }
673
674   // restore the timer resolution
675   if (timeresult == TIMERR_NOERROR)
676      timeEndPeriod(timecaps.wPeriodMin);
677
678   // one last pass at events
679   winwindow_process_events(machine(), 0, 0);
680}
681
682//============================================================
683//  winmain_dump_stack
684//============================================================
685
686void winmain_dump_stack()
687{
688   // set up the stack walker
689   stack_walker walker;
690   if (!walker.reset())
691      return;
692
693   // walk the stack
694   while (walker.unwind())
695      fprintf(stderr, "  %p: %p%s\n", (void *)walker.frame(), (void *)walker.ip(), (symbols == NULL) ? "" : symbols->symbol_for_address(walker.ip()));
696}
697
698
699//============================================================
700//  check_for_double_click_start
701//============================================================
702
703static int is_double_click_start(int argc)
704{
705   STARTUPINFO startup_info = { sizeof(STARTUPINFO) };
706
707   // determine our startup information
708   GetStartupInfo(&startup_info);
709
710   // try to determine if MAME was simply double-clicked
711   return (argc <= 1 && startup_info.dwFlags && !(startup_info.dwFlags & STARTF_USESTDHANDLES));
712}
713
714
715//============================================================
716//  watchdog_thread_entry
717//============================================================
718
719static DWORD WINAPI watchdog_thread_entry(LPVOID lpParameter)
720{
721   DWORD timeout = (int)(FPTR)lpParameter * 1000;
722
723   while (TRUE)
724   {
725      HANDLE handle_list[2];
726      DWORD wait_result;
727
728      // wait for either a reset or an exit, or a timeout
729      handle_list[0] = watchdog_reset_event;
730      handle_list[1] = watchdog_exit_event;
731      wait_result = WaitForMultipleObjects(2, handle_list, FALSE, timeout);
732
733      // on a reset, just loop around and re-wait
734      if (wait_result == WAIT_OBJECT_0 + 0)
735         continue;
736
737      // on an exit, break out
738      if (wait_result == WAIT_OBJECT_0 + 1)
739         break;
740
741      // on a timeout, kill the process
742      if (wait_result == WAIT_TIMEOUT)
743      {
744         fprintf(stderr, "Terminating due to watchdog timeout\n");
745         fflush(stderr);
746         TerminateProcess(GetCurrentProcess(), -1);
747      }
748   }
749   return EXCEPTION_CONTINUE_SEARCH;
750}
751
752
753//============================================================
754//  winmain_watchdog_ping
755//============================================================
756
757void winmain_watchdog_ping(void)
758{
759   // if we have a watchdog, reset it
760   if (watchdog_reset_event != NULL)
761      SetEvent(watchdog_reset_event);
762}
763
764
765//============================================================
766//  exception_filter
767//============================================================
768
769static LONG WINAPI exception_filter(struct _EXCEPTION_POINTERS *info)
770{
771   static const struct
772   {
773      DWORD code;
774      const char *string;
775   } exception_table[] =
776   {
777      { EXCEPTION_ACCESS_VIOLATION,       "ACCESS VIOLATION" },
778      { EXCEPTION_DATATYPE_MISALIGNMENT,  "DATATYPE MISALIGNMENT" },
779      { EXCEPTION_BREAKPOINT,             "BREAKPOINT" },
780      { EXCEPTION_SINGLE_STEP,            "SINGLE STEP" },
781      { EXCEPTION_ARRAY_BOUNDS_EXCEEDED,  "ARRAY BOUNDS EXCEEDED" },
782      { EXCEPTION_FLT_DENORMAL_OPERAND,   "FLOAT DENORMAL OPERAND" },
783      { EXCEPTION_FLT_DIVIDE_BY_ZERO,     "FLOAT DIVIDE BY ZERO" },
784      { EXCEPTION_FLT_INEXACT_RESULT,     "FLOAT INEXACT RESULT" },
785      { EXCEPTION_FLT_INVALID_OPERATION,  "FLOAT INVALID OPERATION" },
786      { EXCEPTION_FLT_OVERFLOW,           "FLOAT OVERFLOW" },
787      { EXCEPTION_FLT_STACK_CHECK,        "FLOAT STACK CHECK" },
788      { EXCEPTION_FLT_UNDERFLOW,          "FLOAT UNDERFLOW" },
789      { EXCEPTION_INT_DIVIDE_BY_ZERO,     "INTEGER DIVIDE BY ZERO" },
790      { EXCEPTION_INT_OVERFLOW,           "INTEGER OVERFLOW" },
791      { EXCEPTION_PRIV_INSTRUCTION,       "PRIVILEGED INSTRUCTION" },
792      { EXCEPTION_IN_PAGE_ERROR,          "IN PAGE ERROR" },
793      { EXCEPTION_ILLEGAL_INSTRUCTION,    "ILLEGAL INSTRUCTION" },
794      { EXCEPTION_NONCONTINUABLE_EXCEPTION,"NONCONTINUABLE EXCEPTION" },
795      { EXCEPTION_STACK_OVERFLOW,         "STACK OVERFLOW" },
796      { EXCEPTION_INVALID_DISPOSITION,    "INVALID DISPOSITION" },
797      { EXCEPTION_GUARD_PAGE,             "GUARD PAGE VIOLATION" },
798      { EXCEPTION_INVALID_HANDLE,         "INVALID HANDLE" },
799      { 0,                                "UNKNOWN EXCEPTION" }
800   };
801   static int already_hit = 0;
802   int i;
803
804   // if we're hitting this recursively, just exit
805   if (already_hit)
806      return EXCEPTION_CONTINUE_SEARCH;
807   already_hit = 1;
808
809   // flush any debugging traces that were live
810   debugger_flush_all_traces_on_abnormal_exit();
811
812   // find our man
813   for (i = 0; exception_table[i].code != 0; i++)
814      if (info->ExceptionRecord->ExceptionCode == exception_table[i].code)
815         break;
816
817   // print the exception type and address
818   fprintf(stderr, "\n-----------------------------------------------------\n");
819   fprintf(stderr, "Exception at EIP=%p%s: %s\n", info->ExceptionRecord->ExceptionAddress,
820         symbols->symbol_for_address((FPTR)info->ExceptionRecord->ExceptionAddress), exception_table[i].string);
821
822   // for access violations, print more info
823   if (info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
824      fprintf(stderr, "While attempting to %s memory at %p\n",
825            info->ExceptionRecord->ExceptionInformation[0] ? "write" : "read",
826            (void *)info->ExceptionRecord->ExceptionInformation[1]);
827
828   // print the state of the CPU
829   fprintf(stderr, "-----------------------------------------------------\n");
830#ifdef PTR64
831   fprintf(stderr, "RAX=%p RBX=%p RCX=%p RDX=%p\n",
832         (void *)info->ContextRecord->Rax,
833         (void *)info->ContextRecord->Rbx,
834         (void *)info->ContextRecord->Rcx,
835         (void *)info->ContextRecord->Rdx);
836   fprintf(stderr, "RSI=%p RDI=%p RBP=%p RSP=%p\n",
837         (void *)info->ContextRecord->Rsi,
838         (void *)info->ContextRecord->Rdi,
839         (void *)info->ContextRecord->Rbp,
840         (void *)info->ContextRecord->Rsp);
841   fprintf(stderr, " R8=%p  R9=%p R10=%p R11=%p\n",
842         (void *)info->ContextRecord->R8,
843         (void *)info->ContextRecord->R9,
844         (void *)info->ContextRecord->R10,
845         (void *)info->ContextRecord->R11);
846   fprintf(stderr, "R12=%p R13=%p R14=%p R15=%p\n",
847         (void *)info->ContextRecord->R12,
848         (void *)info->ContextRecord->R13,
849         (void *)info->ContextRecord->R14,
850         (void *)info->ContextRecord->R15);
851#else
852   fprintf(stderr, "EAX=%p EBX=%p ECX=%p EDX=%p\n",
853         (void *)info->ContextRecord->Eax,
854         (void *)info->ContextRecord->Ebx,
855         (void *)info->ContextRecord->Ecx,
856         (void *)info->ContextRecord->Edx);
857   fprintf(stderr, "ESI=%p EDI=%p EBP=%p ESP=%p\n",
858         (void *)info->ContextRecord->Esi,
859         (void *)info->ContextRecord->Edi,
860         (void *)info->ContextRecord->Ebp,
861         (void *)info->ContextRecord->Esp);
862#endif
863
864   stack_walker walker;
865   walker.reset(*info->ContextRecord, GetCurrentThread());
866
867   // reprint the actual exception address
868   fprintf(stderr, "-----------------------------------------------------\n");
869   fprintf(stderr, "Stack crawl:\n");
870
871   // walk the stack
872   while (walker.unwind())
873      fprintf(stderr, "  %p: %p%s\n", (void *)walker.frame(), (void *)walker.ip(), (symbols == NULL) ? "" : symbols->symbol_for_address(walker.ip()));
874
875   // flush stderr, so the data is actually written when output is being redirected
876   fflush(stderr);
877
878   // exit
879   return EXCEPTION_CONTINUE_SEARCH;
880}
881
882
883//**************************************************************************
884//  STACK WALKER
885//**************************************************************************
886
887//-------------------------------------------------
888//  stack_walker - constructor
889//-------------------------------------------------
890
891stack_walker::stack_walker()
892   : m_process(GetCurrentProcess()),
893      m_thread(GetCurrentThread()),
894      m_first(true),
895      m_stack_walk_64(TEXT("dbghelp.dll"), "StackWalk64"),
896      m_sym_initialize(TEXT("dbghelp.dll"), "SymInitialize"),
897      m_sym_function_table_access_64(TEXT("dbghelp.dll"), "SymFunctionTableAccess64"),
898      m_sym_get_module_base_64(TEXT("dbghelp.dll"), "SymGetModuleBase64"),
899      m_rtl_capture_context(TEXT("kernel32.dll"), "RtlCaptureContext")
900{
901   // zap the structs
902   memset(&m_stackframe, 0, sizeof(m_stackframe));
903   memset(&m_context, 0, sizeof(m_context));
904
905   // initialize the symbols
906   if (!s_initialized && m_sym_initialize && m_stack_walk_64 && m_sym_function_table_access_64 && m_sym_get_module_base_64)
907   {
908      (*m_sym_initialize)(m_process, NULL, TRUE);
909      s_initialized = true;
910   }
911}
912
913
914//-------------------------------------------------
915//  reset - set up a new context
916//-------------------------------------------------
917
918bool stack_walker::reset()
919{
920   // set up the initial state
921   if (!m_rtl_capture_context)
922      return false;
923   (*m_rtl_capture_context)(&m_context);
924   m_thread = GetCurrentThread();
925   m_first = true;
926
927   // initialize the stackframe
928   memset(&m_stackframe, 0, sizeof(m_stackframe));
929   m_stackframe.AddrPC.Mode = AddrModeFlat;
930   m_stackframe.AddrFrame.Mode = AddrModeFlat;
931   m_stackframe.AddrStack.Mode = AddrModeFlat;
932
933   // pull architecture-specific fields from the context
934#ifdef PTR64
935   m_stackframe.AddrPC.Offset = m_context.Rip;
936   m_stackframe.AddrFrame.Offset = m_context.Rsp;
937   m_stackframe.AddrStack.Offset = m_context.Rsp;
938#else
939   m_stackframe.AddrPC.Offset = m_context.Eip;
940   m_stackframe.AddrFrame.Offset = m_context.Ebp;
941   m_stackframe.AddrStack.Offset = m_context.Esp;
942#endif
943   return true;
944}
945
946void stack_walker::reset(CONTEXT &initial, HANDLE thread)
947{
948   // set up the initial state
949   m_context = initial;
950   m_thread = thread;
951   m_first = true;
952
953   // initialize the stackframe
954   memset(&m_stackframe, 0, sizeof(m_stackframe));
955   m_stackframe.AddrPC.Mode = AddrModeFlat;
956   m_stackframe.AddrFrame.Mode = AddrModeFlat;
957   m_stackframe.AddrStack.Mode = AddrModeFlat;
958
959   // pull architecture-specific fields from the context
960#ifdef PTR64
961   m_stackframe.AddrPC.Offset = m_context.Rip;
962   m_stackframe.AddrFrame.Offset = m_context.Rsp;
963   m_stackframe.AddrStack.Offset = m_context.Rsp;
964#else
965   m_stackframe.AddrPC.Offset = m_context.Eip;
966   m_stackframe.AddrFrame.Offset = m_context.Ebp;
967   m_stackframe.AddrStack.Offset = m_context.Esp;
968#endif
969}
970
971
972//-------------------------------------------------
973//  unwind - unwind a single level
974//-------------------------------------------------
975
976bool stack_walker::unwind()
977{
978   // if we were able to initialize, then we have everything we need
979   if (s_initialized)
980   {
981#ifdef PTR64
982      return (*m_stack_walk_64)(IMAGE_FILE_MACHINE_AMD64, m_process, m_thread, &m_stackframe, &m_context, NULL, *m_sym_function_table_access_64, *m_sym_get_module_base_64, NULL);
983#else
984      return (*m_stack_walk_64)(IMAGE_FILE_MACHINE_I386, m_process, m_thread, &m_stackframe, &m_context, NULL, *m_sym_function_table_access_64, *m_sym_get_module_base_64, NULL);
985#endif
986   }
987
988   // otherwise, fake the first unwind, which will just return info from the context
989   else
990   {
991      bool result = m_first;
992      m_first = false;
993      return result;
994   }
995}
996
997
998
999//**************************************************************************
1000//  SYMBOL MANAGER
1001//**************************************************************************
1002
1003//-------------------------------------------------
1004//  symbol_manager - constructor
1005//-------------------------------------------------
1006
1007symbol_manager::symbol_manager(const char *argv0)
1008   : m_mapfile(argv0),
1009      m_symfile(argv0),
1010      m_process(GetCurrentProcess()),
1011      m_last_base(0),
1012      m_text_base(0),
1013      m_sym_from_addr(TEXT("dbghelp.dll"), "SymFromAddr"),
1014      m_sym_get_line_from_addr_64(TEXT("dbghelp.dll"), "SymGetLineFromAddr64")
1015{
1016#ifdef __GNUC__
1017   // compute the name of the mapfile
1018   int extoffs = m_mapfile.find_last_of('.');
1019   if (extoffs != -1)
1020      m_mapfile.substr(0, extoffs);
1021   m_mapfile.append(".map");
1022
1023   // and the name of the symfile
1024   extoffs = m_symfile.find_last_of('.');
1025   if (extoffs != -1)
1026      m_symfile = m_symfile.substr(0, extoffs);
1027   m_symfile.append(".sym");
1028
1029   // figure out the base of the .text section
1030   m_text_base = get_text_section_base();
1031#endif
1032
1033   // expand the buffer to be decently large up front
1034   strprintf(m_buffer,"%500s", "");
1035}
1036
1037
1038//-------------------------------------------------
1039//  ~symbol_manager - destructor
1040//-------------------------------------------------
1041
1042symbol_manager::~symbol_manager()
1043{
1044}
1045
1046
1047//-------------------------------------------------
1048//  symbol_for_address - return a symbol by looking
1049//  it up either in the cache or by scanning the
1050//  file
1051//-------------------------------------------------
1052
1053const char *symbol_manager::symbol_for_address(FPTR address)
1054{
1055   // default the buffer
1056   m_buffer.assign(" (not found)");
1057   m_last_base = 0;
1058
1059   // first try to do it using system APIs
1060   if (!query_system_for_address(address))
1061   {
1062      // if that fails, scan the cache if we have one
1063      if (m_cache.first() != NULL)
1064         scan_cache_for_address(address);
1065
1066      // or else try to open a sym/map file and find it there
1067      else
1068         scan_file_for_address(address, false);
1069   }
1070   return m_buffer.c_str();
1071}
1072
1073
1074//-------------------------------------------------
1075//  query_system_for_address - ask the system to
1076//  look up our address
1077//-------------------------------------------------
1078
1079bool symbol_manager::query_system_for_address(FPTR address)
1080{
1081   // need at least the sym_from_addr API
1082   if (!m_sym_from_addr)
1083      return false;
1084
1085   BYTE info_buffer[sizeof(SYMBOL_INFO) + 256] = { 0 };
1086   SYMBOL_INFO &info = *reinterpret_cast<SYMBOL_INFO *>(&info_buffer[0]);
1087   DWORD64 displacement;
1088
1089   // even through the struct says TCHAR, we actually get back an ANSI string here
1090   info.SizeOfStruct = sizeof(info);
1091   info.MaxNameLen = sizeof(info_buffer) - sizeof(info);
1092   if ((*m_sym_from_addr)(m_process, address, &displacement, &info))
1093   {
1094      // try to get source info as well; again we are returned an ANSI string
1095      IMAGEHLP_LINE64 lineinfo = { sizeof(lineinfo) };
1096      DWORD linedisp;
1097      if (m_sym_get_line_from_addr_64 && (*m_sym_get_line_from_addr_64)(m_process, address, &linedisp, &lineinfo))
1098         format_symbol(info.Name, displacement, lineinfo.FileName, lineinfo.LineNumber);
1099      else
1100         format_symbol(info.Name, displacement);
1101
1102      // set the last base
1103      m_last_base = address - displacement;
1104      return true;
1105   }
1106   return false;
1107}
1108
1109
1110//-------------------------------------------------
1111//  scan_file_for_address - walk either the map
1112//  or symbol files and find the best match for
1113//  the given address, optionally creating a cache
1114//  along the way
1115//-------------------------------------------------
1116
1117void symbol_manager::scan_file_for_address(FPTR address, bool create_cache)
1118{
1119   bool is_symfile = false;
1120   FILE *srcfile = NULL;
1121
1122#ifdef __GNUC__
1123   // see if we have a symbol file (gcc only)
1124   srcfile = fopen(m_symfile.c_str(), "r");
1125   is_symfile = (srcfile != NULL);
1126#endif
1127
1128   // if not, see if we have a map file
1129   if (srcfile == NULL)
1130      srcfile = fopen(m_mapfile.c_str(), "r");
1131
1132   // if not, fail
1133   if (srcfile == NULL)
1134      return;
1135
1136   // reset the best info
1137   std::string best_symbol;
1138   FPTR best_addr = 0;
1139
1140   // parse the file, looking for valid entries
1141   std::string symbol;
1142   char line[1024];
1143   while (fgets(line, sizeof(line) - 1, srcfile))
1144   {
1145      // parse the line looking for an interesting symbol
1146      FPTR addr = 0;
1147      bool valid = is_symfile ? parse_sym_line(line, addr, symbol) : parse_map_line(line, addr, symbol);
1148
1149      // if we got one, see if this is the best
1150      if (valid)
1151      {
1152         // if this is the best one so far, remember it
1153         if (addr <= address && addr > best_addr)
1154         {
1155            best_addr = addr;
1156            best_symbol = symbol;
1157         }
1158
1159         // also create a cache entry if we can
1160         if (create_cache)
1161            m_cache.append(*global_alloc(cache_entry(addr, symbol.c_str())));
1162      }
1163   }
1164
1165   // close the file
1166   fclose(srcfile);
1167
1168   // format the symbol and remember the last base
1169   format_symbol(best_symbol.c_str(), address - best_addr);
1170   m_last_base = best_addr;
1171}
1172
1173
1174//-------------------------------------------------
1175//  scan_cache_for_address - walk the cache to
1176//  find the best match for the given address
1177//-------------------------------------------------
1178
1179void symbol_manager::scan_cache_for_address(FPTR address)
1180{
1181   // reset the best info
1182   std::string best_symbol;
1183   FPTR best_addr = 0;
1184
1185   // walk the cache, looking for valid entries
1186   for (cache_entry *entry = m_cache.first(); entry != NULL; entry = entry->next())
1187
1188      // if this is the best one so far, remember it
1189      if (entry->m_address <= address && entry->m_address > best_addr)
1190      {
1191         best_addr = entry->m_address;
1192         best_symbol = entry->m_name;
1193      }
1194
1195   // format the symbol and remember the last base
1196   format_symbol(best_symbol.c_str(), address - best_addr);
1197   m_last_base = best_addr;
1198}
1199
1200
1201//-------------------------------------------------
1202//  parse_sym_line - parse a line from a sym file
1203//  which is just the output of objdump
1204//-------------------------------------------------
1205
1206bool symbol_manager::parse_sym_line(const char *line, FPTR &address, std::string &symbol)
1207{
1208#ifdef __GNUC__
1209/*
1210    32-bit gcc symbol line:
1211[271778](sec  1)(fl 0x00)(ty  20)(scl   3) (nx 0) 0x007df675 line_to_symbol(char const*, unsigned int&, bool)
1212
1213    64-bit gcc symbol line:
1214[271775](sec  1)(fl 0x00)(ty  20)(scl   3) (nx 0) 0x00000000008dd1e9 line_to_symbol(char const*, unsigned long long&, bool)
1215*/
1216
1217   // first look for a (ty) entry
1218   const char *type = strstr(line, "(ty  20)");
1219   if (type == NULL)
1220      return false;
1221
1222   // scan forward in the line to find the address
1223   bool in_parens = false;
1224   for (const char *chptr = type; *chptr != 0; chptr++)
1225   {
1226      // track open/close parentheses
1227      if (*chptr == '(')
1228         in_parens = true;
1229      else if (*chptr == ')')
1230         in_parens = false;
1231
1232      // otherwise, look for an 0x address
1233      else if (!in_parens && *chptr == '0' && chptr[1] == 'x')
1234      {
1235         // make sure we can get an address
1236         void *temp;
1237         if (sscanf(chptr, "0x%p", &temp) != 1)
1238            return false;
1239         address = m_text_base + reinterpret_cast<FPTR>(temp);
1240
1241         // skip forward until we're past the space
1242         while (*chptr != 0 && !isspace(*chptr))
1243            chptr++;
1244
1245         // extract the symbol name
1246         strtrimspace(symbol.assign(chptr));
1247         return (symbol.length() > 0);
1248      }
1249   }
1250#endif
1251   return false;
1252}
1253
1254
1255//-------------------------------------------------
1256//  parse_map_line - parse a line from a linker-
1257//  generated map file
1258//-------------------------------------------------
1259
1260bool symbol_manager::parse_map_line(const char *line, FPTR &address, std::string &symbol)
1261{
1262#ifdef __GNUC__
1263/*
1264    32-bit gcc map line:
1265                0x0089cb00                nbmj9195_palette_r(_address_space const*, unsigned int)
1266
1267    64-bit gcc map line:
1268                0x0000000000961afc                nbmj9195_palette_r(_address_space const*, unsigned int)
1269*/
1270
1271   // find a matching start
1272   if (strncmp(line, "                0x", 18) == 0)
1273   {
1274      // make sure we can get an address
1275      void *temp;
1276      if (sscanf(&line[16], "0x%p", &temp) != 1)
1277         return false;
1278      address = reinterpret_cast<FPTR>(temp);
1279
1280      // skip forward until we're past the space
1281      const char *chptr = &line[16];
1282      while (*chptr != 0 && !isspace(*chptr))
1283         chptr++;
1284
1285      // extract the symbol name
1286      strtrimspace(symbol.assign(chptr));
1287      return (symbol.length() > 0);
1288   }
1289#endif
1290   return false;
1291}
1292
1293
1294//-------------------------------------------------
1295//  format_symbol - common symbol formatting
1296//-------------------------------------------------
1297
1298void symbol_manager::format_symbol(const char *name, UINT32 displacement, const char *filename, int linenumber)
1299{
1300   // start with the address and offset
1301   strprintf(m_buffer, " (%s", name);
1302   if (displacement != 0)
1303      strcatprintf(m_buffer, "+0x%04x", (UINT32)displacement);
1304
1305   // append file/line if present
1306   if (filename != NULL)
1307      strcatprintf(m_buffer, ", %s:%d", filename, linenumber);
1308
1309   // close up the string
1310   m_buffer.append(")");
1311}
1312
1313
1314//-------------------------------------------------
1315//  get_text_section_base - figure out the base
1316//  of the .text section
1317//-------------------------------------------------
1318
1319FPTR symbol_manager::get_text_section_base()
1320{
1321   dynamic_bind<PIMAGE_SECTION_HEADER (WINAPI *)(PIMAGE_NT_HEADERS, PVOID, ULONG)> image_rva_to_section(TEXT("dbghelp.dll"), "ImageRvaToSection");
1322   dynamic_bind<PIMAGE_NT_HEADERS (WINAPI *)(PVOID)> image_nt_header(TEXT("dbghelp.dll"), "ImageNtHeader");
1323
1324   // start with the image base
1325   PVOID base = reinterpret_cast<PVOID>(GetModuleHandleUni());
1326   assert(base != NULL);
1327
1328   // make sure we have the functions we need
1329   if (image_nt_header && image_rva_to_section)
1330   {
1331      // get the NT header
1332      PIMAGE_NT_HEADERS headers = (*image_nt_header)(base);
1333      assert(headers != NULL);
1334
1335      // look ourself up (assuming we are in the .text section)
1336      PIMAGE_SECTION_HEADER section = (*image_rva_to_section)(headers, base, reinterpret_cast<FPTR>(get_text_section_base) - reinterpret_cast<FPTR>(base));
1337      if (section != NULL)
1338         return reinterpret_cast<FPTR>(base) + section->VirtualAddress;
1339   }
1340
1341   // fallback to returning the image base (wrong)
1342   return reinterpret_cast<FPTR>(base);
1343}
1344
1345
1346
1347//**************************************************************************
1348//  SAMPLING PROFILER
1349//**************************************************************************
1350
1351//-------------------------------------------------
1352//  sampling_profiler - constructor
1353//-------------------------------------------------
1354
1355sampling_profiler::sampling_profiler(UINT32 max_seconds, UINT8 stack_depth = 0)
1356   : m_thread(NULL),
1357      m_thread_id(0),
1358      m_thread_exit(false),
1359      m_stack_depth(stack_depth),
1360      m_entry_stride(stack_depth + 2),
1361      m_buffer(max_seconds * 1000 * m_entry_stride),
1362      m_buffer_ptr(&m_buffer[0]),
1363      m_buffer_end(&m_buffer[0] + max_seconds * 1000 * m_entry_stride)
1364{
1365}
1366
1367
1368//-------------------------------------------------
1369//  sampling_profiler - destructor
1370//-------------------------------------------------
1371
1372sampling_profiler::~sampling_profiler()
1373{
1374}
1375
1376
1377//-------------------------------------------------
1378//  start - begin gathering profiling information
1379//-------------------------------------------------
1380
1381void sampling_profiler::start()
1382{
1383   // do the dance to get a handle to ourself
1384   BOOL result = DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &m_target_thread,
1385         THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, FALSE, 0);
1386   assert_always(result, "Failed to get thread handle for main thread");
1387
1388   // reset the exit flag
1389   m_thread_exit = false;
1390
1391   // start the thread
1392   m_thread = CreateThread(NULL, 0, thread_entry, (LPVOID)this, 0, &m_thread_id);
1393   assert_always(m_thread != NULL, "Failed to create profiler thread\n");
1394
1395   // max out the priority
1396   SetThreadPriority(m_thread, THREAD_PRIORITY_TIME_CRITICAL);
1397}
1398
1399
1400//-------------------------------------------------
1401//  stop - stop gathering profiling information
1402//-------------------------------------------------
1403
1404void sampling_profiler::stop()
1405{
1406   // set the flag and wait a couple of seconds (max)
1407   m_thread_exit = true;
1408   WaitForSingleObject(m_thread, 2000);
1409
1410   // regardless, close the handle
1411   CloseHandle(m_thread);
1412}
1413
1414
1415//-------------------------------------------------
1416//  compare_address - compare two entries by their
1417//  bucket address
1418//-------------------------------------------------
1419
1420int CLIB_DECL sampling_profiler::compare_address(const void *item1, const void *item2)
1421{
1422   const FPTR *entry1 = reinterpret_cast<const FPTR *>(item1);
1423   const FPTR *entry2 = reinterpret_cast<const FPTR *>(item2);
1424   int mincount = MIN(entry1[0], entry2[0]);
1425
1426   // sort in order of: bucket, caller, caller's caller, etc.
1427   for (int index = 1; index <= mincount; index++)
1428      if (entry1[index] != entry2[index])
1429         return entry1[index] - entry2[index];
1430
1431   // if we match to the end, sort by the depth of the stack
1432   return entry1[0] - entry2[0];
1433}
1434
1435
1436//-------------------------------------------------
1437//  compare_frequency - compare two entries by
1438//  their frequency of occurrence
1439//-------------------------------------------------
1440
1441int CLIB_DECL sampling_profiler::compare_frequency(const void *item1, const void *item2)
1442{
1443   const FPTR *entry1 = reinterpret_cast<const FPTR *>(item1);
1444   const FPTR *entry2 = reinterpret_cast<const FPTR *>(item2);
1445
1446   // sort by frequency, then by address
1447   if (entry1[0] != entry2[0])
1448      return entry2[0] - entry1[0];
1449   return entry1[1] - entry2[1];
1450}
1451
1452
1453//-------------------------------------------------
1454//  print_results - output the results
1455//-------------------------------------------------
1456
1457void sampling_profiler::print_results(symbol_manager &symbols)
1458{
1459   // cache the symbols
1460   symbols.cache_symbols();
1461
1462   // step 1: find the base of each entry
1463   for (FPTR *current = &m_buffer[0]; current < m_buffer_ptr; current += m_entry_stride)
1464   {
1465      assert(current[0] >= 1 && current[0] < m_entry_stride);
1466
1467      // convert the sampled PC to its function base as a bucket
1468      symbols.symbol_for_address(current[1]);
1469      current[1] = symbols.last_base();
1470   }
1471
1472   // step 2: sort the results
1473   qsort(&m_buffer[0], (m_buffer_ptr - &m_buffer[0]) / m_entry_stride, m_entry_stride * sizeof(FPTR), compare_address);
1474
1475   // step 3: count and collapse unique entries
1476   UINT32 total_count = 0;
1477   for (FPTR *current = &m_buffer[0]; current < m_buffer_ptr; )
1478   {
1479      int count = 1;
1480      FPTR *scan;
1481      for (scan = current + m_entry_stride; scan < m_buffer_ptr; scan += m_entry_stride)
1482      {
1483         if (compare_address(current, scan) != 0)
1484            break;
1485         scan[0] = 0;
1486         count++;
1487      }
1488      current[0] = count;
1489      total_count += count;
1490      current = scan;
1491   }
1492
1493   // step 4: sort the results again, this time by frequency
1494   qsort(&m_buffer[0], (m_buffer_ptr - &m_buffer[0]) / m_entry_stride, m_entry_stride * sizeof(FPTR), compare_frequency);
1495
1496   // step 5: print the results
1497   UINT32 num_printed = 0;
1498   for (FPTR *current = &m_buffer[0]; current < m_buffer_ptr && num_printed < 30; current += m_entry_stride)
1499   {
1500      // once we hit 0 frequency, we're done
1501      if (current[0] == 0)
1502         break;
1503
1504      // output the result
1505      printf("%4.1f%% - %6d : %p%s\n", (double)current[0] * 100.0 / (double)total_count, (UINT32)current[0], reinterpret_cast<void *>(current[1]), symbols.symbol_for_address(current[1]));
1506      for (int index = 2; index < m_entry_stride; index++)
1507      {
1508         if (current[index] == 0)
1509            break;
1510         printf("                 %p%s\n", reinterpret_cast<void *>(current[index]), symbols.symbol_for_address(current[index]));
1511      }
1512      printf("\n");
1513      num_printed++;
1514   }
1515   symbols.reset_cache();
1516}
1517
1518
1519//-------------------------------------------------
1520//  thread_entry - thread entry stub
1521//-------------------------------------------------
1522
1523DWORD WINAPI sampling_profiler::thread_entry(LPVOID lpParameter)
1524{
1525   reinterpret_cast<sampling_profiler *>(lpParameter)->thread_run();
1526   return 0;
1527}
1528
1529
1530//-------------------------------------------------
1531//  thread_run - sampling thread
1532//-------------------------------------------------
1533
1534void sampling_profiler::thread_run()
1535{
1536   CONTEXT context;
1537   memset(&context, 0, sizeof(context));
1538
1539   // loop until done
1540   stack_walker walker;
1541   while (!m_thread_exit && m_buffer_ptr < m_buffer_end)
1542   {
1543      // pause the main thread and get its context
1544      SuspendThread(m_target_thread);
1545      context.ContextFlags = CONTEXT_FULL;
1546      GetThreadContext(m_target_thread, &context);
1547
1548      // first entry is a count
1549      FPTR *count = m_buffer_ptr++;
1550      *count = 0;
1551
1552      // iterate over the frames until we run out or hit an error
1553      walker.reset(context, m_target_thread);
1554      int frame;
1555      for (frame = 0; frame <= m_stack_depth && walker.unwind(); frame++)
1556      {
1557         *m_buffer_ptr++ = walker.ip();
1558         *count += 1;
1559      }
1560
1561      // fill in any missing parts with NULLs
1562      for (; frame <= m_stack_depth; frame++)
1563         *m_buffer_ptr++ = 0;
1564
1565      // resume the thread
1566      ResumeThread(m_target_thread);
1567
1568      // sleep for 1ms
1569      Sleep(1);
1570   }
1571}


Previous 199869 Revisions Next


© 1997-2024 The MAME Team