Advertisement
Guest User

drawd3d.c

a guest
Feb 15th, 2015
369
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 94.66 KB | None | 0 0
  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 "d3dintf.h"
  39. #include "winmain.h"
  40. #include "window.h"
  41. #include "config.h"
  42. #include "strconv.h"
  43. #include "d3dcomm.h"
  44. #include "drawd3d.h"
  45.  
  46.  
  47.  
  48. //============================================================
  49. //  DEBUGGING
  50. //============================================================
  51.  
  52. extern void mtlog_add(const char *event);
  53.  
  54.  
  55.  
  56. //============================================================
  57. //  CONSTANTS
  58. //============================================================
  59.  
  60. #define ENABLE_BORDER_PIX   (1)
  61.  
  62. enum
  63. {
  64.     TEXTURE_TYPE_PLAIN,
  65.     TEXTURE_TYPE_DYNAMIC,
  66.     TEXTURE_TYPE_SURFACE
  67. };
  68.  
  69.  
  70.  
  71. //============================================================
  72. //  MACROS
  73. //============================================================
  74.  
  75. #define FSWAP(var1, var2) do { float temp = var1; var1 = var2; var2 = temp; } while (0)
  76.  
  77.  
  78.  
  79. //============================================================
  80. //  GLOBALS
  81. //============================================================
  82.  
  83. static const line_aa_step line_aa_1step[] =
  84. {
  85.     {  0.00f,  0.00f,  1.00f  },
  86.     { 0 }
  87. };
  88.  
  89. static const line_aa_step line_aa_4step[] =
  90. {
  91.     { -0.25f,  0.00f,  0.25f  },
  92.     {  0.25f,  0.00f,  0.25f  },
  93.     {  0.00f, -0.25f,  0.25f  },
  94.     {  0.00f,  0.25f,  0.25f  },
  95.     { 0 }
  96. };
  97.  
  98. //============================================================
  99. //  INLINES
  100. //============================================================
  101.  
  102. INLINE BOOL GetClientRectExceptMenu(HWND hWnd, PRECT pRect, BOOL fullscreen)
  103. {
  104.     static HMENU last_menu;
  105.     static RECT last_rect;
  106.     static RECT cached_rect;
  107.     HMENU menu = GetMenu(hWnd);
  108.     BOOL result = GetClientRect(hWnd, pRect);
  109.  
  110.     if (!fullscreen || !menu)
  111.         return result;
  112.  
  113.     // to avoid flicker use cache if we can use
  114.     if (last_menu != menu || memcmp(&last_rect, pRect, sizeof *pRect) != 0)
  115.     {
  116.         last_menu = menu;
  117.         last_rect = *pRect;
  118.  
  119.         SetMenu(hWnd, NULL);
  120.         result = GetClientRect(hWnd, &cached_rect);
  121.         SetMenu(hWnd, menu);
  122.     }
  123.  
  124.     *pRect = cached_rect;
  125.     return result;
  126. }
  127.  
  128.  
  129. INLINE UINT32 ycc_to_rgb(UINT8 y, UINT8 cb, UINT8 cr)
  130. {
  131.     /* original equations:
  132.  
  133.         C = Y - 16
  134.         D = Cb - 128
  135.         E = Cr - 128
  136.  
  137.         R = clip(( 298 * C           + 409 * E + 128) >> 8)
  138.         G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8)
  139.         B = clip(( 298 * C + 516 * D           + 128) >> 8)
  140.  
  141.         R = clip(( 298 * (Y - 16)                    + 409 * (Cr - 128) + 128) >> 8)
  142.         G = clip(( 298 * (Y - 16) - 100 * (Cb - 128) - 208 * (Cr - 128) + 128) >> 8)
  143.         B = clip(( 298 * (Y - 16) + 516 * (Cb - 128)                    + 128) >> 8)
  144.  
  145.         R = clip(( 298 * Y - 298 * 16                        + 409 * Cr - 409 * 128 + 128) >> 8)
  146.         G = clip(( 298 * Y - 298 * 16 - 100 * Cb + 100 * 128 - 208 * Cr + 208 * 128 + 128) >> 8)
  147.         B = clip(( 298 * Y - 298 * 16 + 516 * Cb - 516 * 128                        + 128) >> 8)
  148.  
  149.         R = clip(( 298 * Y - 298 * 16                        + 409 * Cr - 409 * 128 + 128) >> 8)
  150.         G = clip(( 298 * Y - 298 * 16 - 100 * Cb + 100 * 128 - 208 * Cr + 208 * 128 + 128) >> 8)
  151.         B = clip(( 298 * Y - 298 * 16 + 516 * Cb - 516 * 128                        + 128) >> 8)
  152.     */
  153.     int r, g, b, common;
  154.  
  155.     common = 298 * y - 298 * 16;
  156.     r = (common +                        409 * cr - 409 * 128 + 128) >> 8;
  157.     g = (common - 100 * cb + 100 * 128 - 208 * cr + 208 * 128 + 128) >> 8;
  158.     b = (common + 516 * cb - 516 * 128                        + 128) >> 8;
  159.  
  160.     if (r < 0) r = 0;
  161.     else if (r > 255) r = 255;
  162.     if (g < 0) g = 0;
  163.     else if (g > 255) g = 255;
  164.     if (b < 0) b = 0;
  165.     else if (b > 255) b = 255;
  166.  
  167.     return rgb_t(0xff, r, g, b);
  168. }
  169.  
  170. //============================================================
  171. //  drawd3d_init
  172. //============================================================
  173.  
  174. static d3d::base *               d3dintf; // FIX ME
  175.  
  176. //============================================================
  177. //  PROTOTYPES
  178. //============================================================
  179.  
  180. // core functions
  181. static void drawd3d_exit(void);
  182. static int drawd3d_window_init(win_window_info *window);
  183. static void drawd3d_window_destroy(win_window_info *window);
  184. static render_primitive_list *drawd3d_window_get_primitives(win_window_info *window);
  185. static void drawd3d_window_save(win_window_info *window);
  186. static void drawd3d_window_record(win_window_info *window);
  187. static void drawd3d_window_toggle_fsfx(win_window_info *window);
  188. static int drawd3d_window_draw(win_window_info *window, HDC dc, int update);
  189.  
  190.  
  191. //============================================================
  192. //  drawd3d_window_init
  193. //============================================================
  194.  
  195. static int drawd3d_window_init(win_window_info *window)
  196. {
  197.     // allocate memory for our structures
  198.     d3d::renderer *d3d = global_alloc(d3d::renderer(window));
  199.     window->m_drawdata = d3d;
  200.  
  201.     if (!d3d->initialize())
  202.     {
  203.         drawd3d_window_destroy(window);
  204.         osd_printf_error("Unable to initialize Direct3D.\n");
  205.         return 1;
  206.     }
  207.     else
  208.     {
  209.         // set max update rate and bounds
  210.         drawd3d_window_get_primitives(window);
  211.     }
  212.  
  213.     return 0;
  214. }
  215.  
  216. //============================================================
  217. //  drawd3d_exit
  218. //============================================================
  219.  
  220. static void drawd3d_exit(void)
  221. {
  222.     if (d3dintf != NULL)
  223.         (*d3dintf->d3d.release)(d3dintf);
  224. }
  225.  
  226. static void drawd3d_window_toggle_fsfx(win_window_info *window)
  227. {
  228.     d3d::renderer *d3d = (d3d::renderer *)window->m_drawdata;
  229.     d3d->set_restarting(true);
  230. }
  231.  
  232. static void drawd3d_window_record(win_window_info *window)
  233. {
  234.     d3d::renderer *d3d = (d3d::renderer *)window->m_drawdata;
  235.     d3d->get_shaders()->window_record();
  236. }
  237.  
  238. static void drawd3d_window_save(win_window_info *window)
  239. {
  240.     d3d::renderer *d3d = (d3d::renderer *)window->m_drawdata;
  241.     d3d->get_shaders()->window_save();
  242. }
  243.  
  244.  
  245.  
  246. //============================================================
  247. //  drawd3d_window_destroy
  248. //============================================================
  249.  
  250. static void drawd3d_window_destroy(win_window_info *window)
  251. {
  252.     d3d::renderer *d3d = (d3d::renderer *)window->m_drawdata;
  253.  
  254.     // skip if nothing
  255.     if (d3d == NULL)
  256.         return;
  257.  
  258.     if (d3d->get_shaders() != NULL && d3d->get_shaders()->recording())
  259.         d3d->get_shaders()->window_record();
  260.  
  261.     // free the memory in the window
  262.     global_free(d3d);
  263.     window->m_drawdata = NULL;
  264. }
  265.  
  266.  
  267.  
  268. //============================================================
  269. //  drawd3d_window_get_primitives
  270. //============================================================
  271.  
  272. static render_primitive_list *drawd3d_window_get_primitives(win_window_info *window)
  273. {
  274.     d3d::renderer *d3d = (d3d::renderer *)window->m_drawdata;
  275.     RECT client;
  276.  
  277.     GetClientRectExceptMenu(window->m_hwnd, &client, window->m_fullscreen);
  278.     if (rect_width(&client) > 0 && rect_height(&client) > 0)
  279.     {
  280.         window->m_target->set_bounds(rect_width(&client), rect_height(&client), window->m_monitor->get_aspect());
  281.         window->m_target->set_max_update_rate((d3d->get_refresh() == 0) ? d3d->get_origmode().RefreshRate : d3d->get_refresh());
  282.     }
  283.     return &window->m_target->get_primitives();
  284. }
  285.  
  286. int drawd3d_init(running_machine &machine, win_draw_callbacks *callbacks)
  287. {
  288.     d3dintf = NULL;
  289.  
  290.     // Use Direct3D9
  291.     d3dintf = d3d::drawd3d9_init();
  292.  
  293.     // if we failed, note the error
  294.     if (d3dintf == NULL)
  295.     {
  296.         osd_printf_error("Unable to initialize Direct3D.\n");
  297.         return 1;
  298.     }
  299.  
  300.     // fill in the callbacks
  301.     memset(callbacks, 0, sizeof(*callbacks));
  302.     callbacks->exit = drawd3d_exit;
  303.     callbacks->window_init = drawd3d_window_init;
  304.     callbacks->window_get_primitives = drawd3d_window_get_primitives;
  305.     callbacks->window_draw = drawd3d_window_draw;
  306.     callbacks->window_save = drawd3d_window_save;
  307.     callbacks->window_record = drawd3d_window_record;
  308.     callbacks->window_toggle_fsfx = drawd3d_window_toggle_fsfx;
  309.     callbacks->window_destroy = drawd3d_window_destroy;
  310.     return 0;
  311. }
  312.  
  313. //============================================================
  314. //  drawd3d_window_draw
  315. //============================================================
  316.  
  317. static int drawd3d_window_draw(win_window_info *window, HDC dc, int update)
  318. {
  319.     d3d::renderer *d3d = (d3d::renderer *)window->m_drawdata;
  320.  
  321.     // if we haven't been created, just punt
  322.     if (d3d == NULL)
  323.         return 1;
  324.  
  325.     int check = d3d->pre_window_draw_check();
  326.     if (check >= 0)
  327.         return check;
  328.  
  329.     d3d->begin_frame();
  330.     d3d->process_primitives();
  331.     d3d->end_frame();
  332.  
  333.     return 0;
  334. }
  335.  
  336. namespace d3d
  337. {
  338. void renderer::set_texture(texture_info *texture)
  339. {
  340.     if (texture != m_last_texture)
  341.     {
  342.         m_last_texture = texture;
  343.         m_last_texture_flags = (texture == NULL ? 0 : texture->get_flags());
  344.         HRESULT result = (*d3dintf->device.set_texture)(m_device, 0, (texture == NULL) ? get_default_texture()->get_finaltex() : texture->get_finaltex());
  345.         m_shaders->set_texture(texture);
  346.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture call\n", (int)result);
  347.     }
  348. }
  349.  
  350.  
  351. void renderer::set_filter(int filter)
  352. {
  353.     if (filter != m_last_filter)
  354.     {
  355.         m_last_filter = filter;
  356.         HRESULT result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MINFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT);
  357.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
  358.         result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MAGFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT);
  359.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
  360.         result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MINFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT);
  361.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
  362.         result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MAGFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT);
  363.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
  364.     }
  365. }
  366.  
  367.  
  368. void renderer::set_wrap(D3DTEXTUREADDRESS wrap)
  369. {
  370.     if (wrap != m_last_wrap)
  371.     {
  372.         m_last_wrap = wrap;
  373.         HRESULT result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSU, wrap);
  374.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
  375.         result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSV, wrap);
  376.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
  377.         result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSU, wrap);
  378.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
  379.         result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSV, wrap);
  380.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
  381.     }
  382. }
  383.  
  384.  
  385. void renderer::set_modmode(DWORD modmode)
  386. {
  387.     if (modmode != m_last_modmode)
  388.     {
  389.         m_last_modmode = modmode;
  390.         HRESULT result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, D3DTSS_COLOROP, modmode);
  391.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
  392.         result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, D3DTSS_COLOROP, modmode);
  393.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result);
  394.     }
  395. }
  396.  
  397.  
  398. void renderer::set_blendmode(int blendmode)
  399. {
  400.     int blendenable;
  401.     int blendop;
  402.     int blendsrc;
  403.     int blenddst;
  404.  
  405.     // choose the parameters
  406.     switch (blendmode)
  407.     {
  408.         default:
  409.         case BLENDMODE_NONE:            blendenable = FALSE;    blendop = D3DBLENDOP_ADD;   blendsrc = D3DBLEND_SRCALPHA;   blenddst = D3DBLEND_INVSRCALPHA;    break;
  410.         case BLENDMODE_ALPHA:           blendenable = TRUE;     blendop = D3DBLENDOP_ADD;   blendsrc = D3DBLEND_SRCALPHA;   blenddst = D3DBLEND_INVSRCALPHA;    break;
  411.         case BLENDMODE_RGB_MULTIPLY:    blendenable = TRUE;     blendop = D3DBLENDOP_ADD;   blendsrc = D3DBLEND_DESTCOLOR;  blenddst = D3DBLEND_ZERO;           break;
  412.         case BLENDMODE_ADD:             blendenable = TRUE;     blendop = D3DBLENDOP_ADD;   blendsrc = D3DBLEND_SRCALPHA;   blenddst = D3DBLEND_ONE;            break;
  413.     }
  414.  
  415.     // adjust the bits that changed
  416.     if (blendenable != m_last_blendenable)
  417.     {
  418.         m_last_blendenable = blendenable;
  419.         HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHABLENDENABLE, blendenable);
  420.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result);
  421.     }
  422.  
  423.     if (blendop != m_last_blendop)
  424.     {
  425.         m_last_blendop = blendop;
  426.         HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_BLENDOP, blendop);
  427.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result);
  428.     }
  429.  
  430.     if (blendsrc != m_last_blendsrc)
  431.     {
  432.         m_last_blendsrc = blendsrc;
  433.         HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_SRCBLEND, blendsrc);
  434.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result);
  435.     }
  436.  
  437.     if (blenddst != m_last_blenddst)
  438.     {
  439.         m_last_blenddst = blenddst;
  440.         HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_DESTBLEND, blenddst);
  441.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result);
  442.     }
  443. }
  444.  
  445.  
  446. void renderer::reset_render_states()
  447. {
  448.     // this ensures subsequent calls to the above setters will force-update the data
  449.     m_last_texture = (texture_info *)~0;
  450.     m_last_filter = -1;
  451.     m_last_blendenable = -1;
  452.     m_last_blendop = -1;
  453.     m_last_blendsrc = -1;
  454.     m_last_blenddst = -1;
  455.     m_last_wrap = (D3DTEXTUREADDRESS)-1;
  456. }
  457.  
  458.  
  459.  
  460. texture_manager::texture_manager(renderer *d3d)
  461. {
  462.     m_renderer = d3d;
  463.  
  464.     m_texlist = NULL;
  465.     m_vector_texture = NULL;
  466.     m_default_texture = NULL;
  467.  
  468.     // check for dynamic texture support
  469.     DWORD tempcaps;
  470.     HRESULT result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_CAPS2, &tempcaps);
  471.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
  472.     m_dynamic_supported = ((tempcaps & D3DCAPS2_DYNAMICTEXTURES) != 0);
  473.     if (m_dynamic_supported) osd_printf_verbose("Direct3D: Using dynamic textures\n");
  474.  
  475.     // check for stretchrect support
  476.     result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_STRETCH_RECT_FILTER, &tempcaps);
  477.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
  478.     m_stretch_supported = ((tempcaps & D3DPTFILTERCAPS_MAGFPOINT) != 0);
  479.     if (m_stretch_supported && video_config.prescale > 1) osd_printf_verbose("Direct3D: Using StretchRect for prescaling\n");
  480.  
  481.     // get texture caps
  482.     result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_TEXTURE_CAPS, &m_texture_caps);
  483.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
  484.     result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_MAX_TEXTURE_ASPECT, &m_texture_max_aspect);
  485.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
  486.     result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_MAX_TEXTURE_WIDTH, &m_texture_max_width);
  487.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
  488.     result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_MAX_TEXTURE_HEIGHT, &m_texture_max_height);
  489.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
  490.  
  491.     // pick a YUV texture format
  492.     m_yuv_format = D3DFMT_UYVY;
  493.     result = (*d3dintf->d3d.check_device_format)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, d3d->get_pixel_format(), 0, D3DRTYPE_TEXTURE, D3DFMT_UYVY);
  494.     if (result != D3D_OK)
  495.     {
  496.         m_yuv_format = D3DFMT_YUY2;
  497.         result = (*d3dintf->d3d.check_device_format)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, d3d->get_pixel_format(), 0, D3DRTYPE_TEXTURE, D3DFMT_YUY2);
  498.         if (result != D3D_OK)
  499.             m_yuv_format = D3DFMT_A8R8G8B8;
  500.     }
  501.     osd_printf_verbose("Direct3D: YUV format = %s\n", (m_yuv_format == D3DFMT_YUY2) ? "YUY2" : (m_yuv_format == D3DFMT_UYVY) ? "UYVY" : "RGB");
  502.  
  503.     // set the max texture size
  504.     d3d->get_window()->m_target->set_max_texture_size(m_texture_max_width, m_texture_max_height);
  505.     osd_printf_verbose("Direct3D: Max texture size = %dx%d\n", (int)m_texture_max_width, (int)m_texture_max_height);
  506. }
  507.  
  508. texture_manager::~texture_manager()
  509. {
  510. }
  511.  
  512. void texture_manager::create_resources()
  513. {
  514.     // experimental: load a PNG to use for vector rendering; it is treated
  515.     // as a brightness map
  516.     emu_file file(m_renderer->get_window()->machine().options().art_path(), OPEN_FLAG_READ);
  517.     render_load_png(m_vector_bitmap, file, NULL, "vector.png");
  518.     if (m_vector_bitmap.valid())
  519.     {
  520.         m_vector_bitmap.fill(rgb_t(0xff,0xff,0xff,0xff));
  521.         render_load_png(m_vector_bitmap, file, NULL, "vector.png", true);
  522.     }
  523.  
  524.     m_default_bitmap.allocate(8, 8);
  525.     m_default_bitmap.fill(rgb_t(0xff,0xff,0xff,0xff));
  526.  
  527.     if (m_default_bitmap.valid())
  528.     {
  529.         render_texinfo texture;
  530.  
  531.         // fake in the basic data so it looks like it came from render.c
  532.         texture.base = m_default_bitmap.raw_pixptr(0);
  533.         texture.rowpixels = m_default_bitmap.rowpixels();
  534.         texture.width = m_default_bitmap.width();
  535.         texture.height = m_default_bitmap.height();
  536.         texture.set_palette(NULL);
  537.         texture.seqid = 0;
  538.  
  539.         // now create it
  540.         m_default_texture = global_alloc(texture_info(this, &texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32)));
  541.     }
  542.  
  543.     // experimental: if we have a vector bitmap, create a texture for it
  544.     if (m_vector_bitmap.valid())
  545.     {
  546.         render_texinfo texture;
  547.  
  548.         // fake in the basic data so it looks like it came from render.c
  549.         texture.base = &m_vector_bitmap.pix32(0);
  550.         texture.rowpixels = m_vector_bitmap.rowpixels();
  551.         texture.width = m_vector_bitmap.width();
  552.         texture.height = m_vector_bitmap.height();
  553.         texture.set_palette(NULL);
  554.         texture.seqid = 0;
  555.  
  556.         // now create it
  557.         m_vector_texture = global_alloc(texture_info(this, &texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32)));
  558.     }
  559. }
  560.  
  561. void texture_manager::delete_resources()
  562. {
  563.     // is part of m_texlist and will be free'd there
  564.     //global_free(m_default_texture);
  565.     m_default_texture = NULL;
  566.  
  567.     //global_free(m_vector_texture);
  568.     m_vector_texture = NULL;
  569.  
  570.     // free all textures
  571.     while (m_texlist != NULL)
  572.     {
  573.         texture_info *tex = m_texlist;
  574.         m_texlist = tex->get_next();
  575.         global_free(tex);
  576.     }
  577. }
  578.  
  579. UINT32 texture_manager::texture_compute_hash(const render_texinfo *texture, UINT32 flags)
  580. {
  581.     return (FPTR)texture->base ^ (flags & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK));
  582. }
  583.  
  584. texture_info *texture_manager::find_texinfo(const render_texinfo *texinfo, UINT32 flags)
  585. {
  586.     UINT32 hash = texture_compute_hash(texinfo, flags);
  587.     texture_info *texture;
  588.  
  589.     // find a match
  590.     for (texture = m_renderer->get_texture_manager()->get_texlist(); texture != NULL; texture = texture->get_next())
  591.     {
  592.         UINT32 test_screen = (UINT32)texture->get_texinfo().osddata >> 1;
  593.         UINT32 test_page = (UINT32)texture->get_texinfo().osddata & 1;
  594.         UINT32 prim_screen = (UINT32)texinfo->osddata >> 1;
  595.         UINT32 prim_page = (UINT32)texinfo->osddata & 1;
  596.         if (test_screen != prim_screen || test_page != prim_page)
  597.         {
  598.             continue;
  599.         }
  600.  
  601.         if (texture->get_hash() == hash &&
  602.             texture->get_texinfo().base == texinfo->base &&
  603.             texture->get_texinfo().width == texinfo->width &&
  604.             texture->get_texinfo().height == texinfo->height &&
  605.             ((texture->get_flags() ^ flags) & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) == 0)
  606.         {
  607.             // Reject a texture if it belongs to an out-of-date render target, so as to cause the HLSL system to re-cache
  608.             if (m_renderer->get_shaders()->enabled() && texinfo->width != 0 && texinfo->height != 0 && (flags & PRIMFLAG_SCREENTEX_MASK) != 0)
  609.             {
  610.                 if (m_renderer->get_shaders()->find_render_target(texture) != NULL)
  611.                 {
  612.                     return texture;
  613.                 }
  614.             }
  615.             else
  616.             {
  617.                 return texture;
  618.             }
  619.         }
  620.     }
  621.  
  622.     // Nothing found, check if we need to unregister something with HLSL
  623.     if (m_renderer->get_shaders()->enabled())
  624.     {
  625.         if (texinfo->width == 0 || texinfo->height == 0)
  626.         {
  627.             return NULL;
  628.         }
  629.  
  630.         UINT32 prim_screen = texinfo->osddata >> 1;
  631.         UINT32 prim_page = texinfo->osddata & 1;
  632.  
  633.         for (texture = m_renderer->get_texture_manager()->get_texlist(); texture != NULL; texture = texture->get_next())
  634.         {
  635.             UINT32 test_screen = texture->get_texinfo().osddata >> 1;
  636.             UINT32 test_page = texture->get_texinfo().osddata & 1;
  637.             if (test_screen != prim_screen || test_page != prim_page)
  638.             {
  639.                 continue;
  640.             }
  641.  
  642.             // Clear out our old texture reference
  643.             if (texture->get_hash() == hash &&
  644.                 texture->get_texinfo().base == texinfo->base &&
  645.                 ((texture->get_flags() ^ flags) & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) == 0 &&
  646.                 (texture->get_texinfo().width != texinfo->width ||
  647.                     texture->get_texinfo().height != texinfo->height))
  648.             {
  649.                 m_renderer->get_shaders()->remove_render_target(texture);
  650.             }
  651.         }
  652.     }
  653.  
  654.     return NULL;
  655. }
  656.  
  657. renderer::renderer(win_window_info *window)
  658. {
  659.     m_device = NULL;
  660.     m_restarting = false;
  661.     m_window = window;
  662.     m_shaders = NULL;
  663.     m_numverts = 0;
  664.     m_numpolys = 0;
  665.     m_vertexbuf = NULL;
  666.     m_lockedbuf = NULL;
  667.     m_vectorbatch = NULL;
  668.     m_last_texture = NULL;
  669.     m_hlsl_buf = NULL;
  670.     m_texture_manager = NULL;
  671. }
  672.  
  673. int renderer::initialize()
  674. {
  675.     // configure the adapter for the mode we want
  676.     if (config_adapter_mode())
  677.         return false;
  678.  
  679.     // create the device immediately for the full screen case (defer for window mode)
  680.     if (m_window->m_fullscreen && device_create())
  681.         return false;
  682.  
  683.     return true;
  684. }
  685.  
  686. int renderer::pre_window_draw_check()
  687. {
  688.     // if we're in the middle of resizing, leave things alone
  689.     if (m_window->m_resize_state == RESIZE_STATE_RESIZING)
  690.         return 0;
  691.  
  692.     // if we're restarting the renderer, leave things alone
  693.     if (m_restarting)
  694.     {
  695.         m_shaders->toggle();
  696.  
  697.         // free all existing resources and re-create
  698.         device_delete_resources();
  699.         device_create_resources();
  700.  
  701.         m_restarting = false;
  702.     }
  703.  
  704.     // if we have a device, check the cooperative level
  705.     if (m_device != NULL)
  706.     {
  707.         if (device_test_cooperative())
  708.         {
  709.             return 1;
  710.         }
  711.     }
  712.  
  713.     // in window mode, we need to track the window size
  714.     if (!m_window->m_fullscreen || m_device == NULL)
  715.     {
  716.         // if the size changes, skip this update since the render target will be out of date
  717.         if (update_window_size())
  718.             return 0;
  719.  
  720.         // if we have no device, after updating the size, return an error so GDI can try
  721.         if (m_device == NULL)
  722.             return 1;
  723.     }
  724.  
  725.     return -1;
  726. }
  727.  
  728. void texture_manager::update_textures()
  729. {
  730.     for (render_primitive *prim = m_renderer->get_window()->m_primlist->first(); prim != NULL; prim = prim->next())
  731.     {
  732.         if (prim->texture.base != NULL)
  733.         {
  734.             texture_info *texture = find_texinfo(&prim->texture, prim->flags);
  735.             if (texture == NULL)
  736.             {
  737.                 // if there isn't one, create a new texture
  738.                 global_alloc(texture_info(this, &prim->texture, prim->flags));
  739.             }
  740.             else
  741.             {
  742.                 // if there is one, but with a different seqid, copy the data
  743.                 if (texture->get_texinfo().seqid != prim->texture.seqid)
  744.                 {
  745.                     texture->set_data(&prim->texture, prim->flags);
  746.                     texture->get_texinfo().seqid = prim->texture.seqid;
  747.                 }
  748.             }
  749.         }
  750.         else if(m_renderer->get_shaders()->vector_enabled() && PRIMFLAG_GET_VECTORBUF(prim->flags))
  751.         {
  752.             if (!m_renderer->get_shaders()->get_vector_target())
  753.             {
  754.                 m_renderer->get_shaders()->create_vector_target(prim);
  755.             }
  756.         }
  757.     }
  758. }
  759.  
  760. void renderer::begin_frame()
  761. {
  762.     HRESULT result = (*d3dintf->device.clear)(m_device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0);
  763.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result);
  764.  
  765.     m_shaders->begin_frame();
  766.  
  767.     m_window->m_primlist->acquire_lock();
  768.  
  769.     // first update any textures
  770.     m_texture_manager->update_textures();
  771.  
  772.     // begin the scene
  773. mtlog_add("drawd3d_window_draw: begin_scene");
  774.     result = (*d3dintf->device.begin_scene)(m_device);
  775.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device begin_scene call\n", (int)result);
  776.  
  777.     m_lockedbuf = NULL;
  778.  
  779.     if(m_shaders->enabled())
  780.     {
  781.         m_hlsl_buf = (void*)mesh_alloc(6);
  782.         m_shaders->init_fsfx_quad(m_hlsl_buf);
  783.     }
  784.  
  785.     m_line_count = 0;
  786.  
  787.     // loop over primitives
  788.     for (render_primitive *prim = m_window->m_primlist->first(); prim != NULL; prim = prim->next())
  789.         if (prim->type == render_primitive::LINE && PRIMFLAG_GET_VECTOR(prim->flags))
  790.             m_line_count++;
  791. }
  792.  
  793. void renderer::process_primitives()
  794. {
  795.     // Rotating index for vector time offsets
  796.     for (render_primitive *prim = m_window->m_primlist->first(); prim != NULL; prim = prim->next())
  797.     {
  798.         switch (prim->type)
  799.         {
  800.             case render_primitive::LINE:
  801.                 if (PRIMFLAG_GET_VECTOR(prim->flags))
  802.                 {
  803.                     if (m_line_count > 0)
  804.                         batch_vectors();
  805.                     else
  806.                         continue;
  807.                 }
  808.                 else
  809.                 {
  810.                     draw_line(prim);
  811.                 }
  812.                 break;
  813.  
  814.             case render_primitive::QUAD:
  815.                 draw_quad(prim);
  816.                 break;
  817.  
  818.             default:
  819.                 throw emu_fatalerror("Unexpected render_primitive type");
  820.         }
  821.     }
  822. }
  823.  
  824. void renderer::end_frame()
  825. {
  826.     m_window->m_primlist->release_lock();
  827.  
  828.     // flush any pending polygons
  829.     primitive_flush_pending();
  830.  
  831.     m_shaders->end_frame();
  832.  
  833.     // finish the scene
  834.     HRESULT result = (*d3dintf->device.end_scene)(m_device);
  835.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device end_scene call\n", (int)result);
  836.  
  837.     // present the current buffers
  838.     result = (*d3dintf->device.present)(m_device, NULL, NULL, NULL, NULL, 0);
  839.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device present call\n", (int)result);
  840. }
  841.  
  842. //============================================================
  843. //  device_create
  844. //============================================================
  845.  
  846. int renderer::device_create()
  847. {
  848.     // if a device exists, free it
  849.     if (m_device != NULL)
  850.         device_delete();
  851.  
  852.     // verify the caps
  853.     int verify = device_verify_caps();
  854.     if (verify == 2)
  855.     {
  856.         osd_printf_error("Error: Device does not meet minimum requirements for Direct3D rendering\n");
  857.         return 1;
  858.     }
  859.     if (verify == 1)
  860.         osd_printf_warning("Warning: Device may not perform well for Direct3D rendering\n");
  861.  
  862.     // verify texture formats
  863.     HRESULT result = (*d3dintf->d3d.check_device_format)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, 0, D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8);
  864.     if (result != D3D_OK)
  865.     {
  866.         osd_printf_error("Error: A8R8G8B8 format textures not supported\n");
  867.         return 1;
  868.     }
  869.  
  870.     m_texture_manager = global_alloc(texture_manager(this));
  871.  
  872. try_again:
  873.     // try for XRGB first
  874.     m_screen_format = D3DFMT_X8R8G8B8;
  875.     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);
  876.     if (result != D3D_OK)
  877.     {
  878.         // if not, try for ARGB
  879.         m_screen_format = D3DFMT_A8R8G8B8;
  880.         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);
  881.         if (result != D3D_OK && m_texture_manager->is_dynamic_supported())
  882.         {
  883.             m_texture_manager->set_dynamic_supported(FALSE);
  884.             goto try_again;
  885.         }
  886.         if (result != D3D_OK)
  887.         {
  888.             osd_printf_error("Error: unable to configure a screen texture format\n");
  889.             return 1;
  890.         }
  891.     }
  892.  
  893.     // initialize the D3D presentation parameters
  894.     memset(&m_presentation, 0, sizeof(m_presentation));
  895.     m_presentation.BackBufferWidth               = m_width;
  896.     m_presentation.BackBufferHeight              = m_height;
  897.     m_presentation.BackBufferFormat              = m_pixformat;
  898.     m_presentation.BackBufferCount               = video_config.triplebuf ? 2 : 1;
  899.     m_presentation.MultiSampleType               = D3DMULTISAMPLE_NONE;
  900.     m_presentation.SwapEffect                    = D3DSWAPEFFECT_DISCARD;
  901.     m_presentation.hDeviceWindow                 = m_window->m_hwnd;
  902.     m_presentation.Windowed                      = !m_window->m_fullscreen || win_has_menu(m_window);
  903.     m_presentation.EnableAutoDepthStencil        = FALSE;
  904.     m_presentation.AutoDepthStencilFormat        = D3DFMT_D16;
  905.     m_presentation.Flags                         = 0;
  906.     m_presentation.FullScreen_RefreshRateInHz    = m_refresh;
  907.     m_presentation.PresentationInterval          = ((video_config.triplebuf && m_window->m_fullscreen) ||
  908.                                                     video_config.waitvsync || video_config.syncrefresh) ?
  909.                                                     D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
  910.  
  911.     // create the D3D device
  912.     result = (*d3dintf->d3d.create_device)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_window->m_focus_hwnd,
  913.                     D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &m_presentation, &m_device);
  914.     if (result != D3D_OK)
  915.     {
  916.         // if we got a "DEVICELOST" error, it may be transitory; count it and only fail if
  917.         // we exceed a threshold
  918.         if (result == D3DERR_DEVICELOST)
  919.         {
  920.             m_create_error_count++;
  921.             if (m_create_error_count < 10)
  922.             {
  923.                 return 0;
  924.             }
  925.         }
  926.  
  927.         //  fatal error if we just can't do it
  928.         osd_printf_error("Unable to create the Direct3D device (%08X)\n", (UINT32)result);
  929.         return 1;
  930.     }
  931.     m_create_error_count = 0;
  932.     osd_printf_verbose("Direct3D: Device created at %dx%d\n", m_width, m_height);
  933.  
  934.     // set the gamma if we need to
  935.     if (m_window->m_fullscreen)
  936.     {
  937.         // only set the gamma if it's not 1.0f
  938.         windows_options &options = downcast<windows_options &>(m_window->machine().options());
  939.         float brightness = options.full_screen_brightness();
  940.         float contrast = options.full_screen_contrast();
  941.         float gamma = options.full_screen_gamma();
  942.         if (brightness != 1.0f || contrast != 1.0f || gamma != 1.0f)
  943.         {
  944.             // warn if we can't do it
  945.             if (!m_gamma_supported)
  946.             {
  947.                 osd_printf_warning("Direct3D: Warning - device does not support full screen gamma correction.\n");
  948.             }
  949.             else
  950.             {
  951.                 // create a standard ramp and set it
  952.                 D3DGAMMARAMP ramp;
  953.                 for (int i = 0; i < 256; i++)
  954.                 {
  955.                     ramp.red[i] = ramp.green[i] = ramp.blue[i] = apply_brightness_contrast_gamma(i, brightness, contrast, gamma) << 8;
  956.                 }
  957.                 (*d3dintf->device.set_gamma_ramp)(m_device, 0, &ramp);
  958.             }
  959.         }
  960.     }
  961.  
  962.     int ret = m_shaders->create_resources(false);
  963.     if (ret != 0)
  964.         return ret;
  965.  
  966.     return device_create_resources();
  967. }
  968.  
  969.  
  970.  
  971. //============================================================
  972. //  device_create_resources
  973. //============================================================
  974.  
  975. int renderer::device_create_resources()
  976. {
  977.     // allocate a vertex buffer to use
  978.     HRESULT result = (*d3dintf->device.create_vertex_buffer)(m_device,
  979.                 sizeof(vertex) * VERTEX_BUFFER_SIZE,
  980.                 D3DUSAGE_DYNAMIC | D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_WRITEONLY,
  981.                 VERTEX_BASE_FORMAT | ((m_shaders->enabled() && d3dintf->post_fx_available) ? D3DFVF_XYZW : D3DFVF_XYZRHW),
  982.                 D3DPOOL_DEFAULT, &m_vertexbuf);
  983.     if (result != D3D_OK)
  984.     {
  985.         osd_printf_error("Error creating vertex buffer (%08X)\n", (UINT32)result);
  986.         return 1;
  987.     }
  988.  
  989.     // set the vertex format
  990.     result = (*d3dintf->device.set_vertex_format)(m_device, (D3DFORMAT)(VERTEX_BASE_FORMAT | ((m_shaders->enabled() &&
  991.         d3dintf->post_fx_available) ? D3DFVF_XYZW : D3DFVF_XYZRHW)));
  992.     if (result != D3D_OK)
  993.     {
  994.         osd_printf_error("Error setting vertex format (%08X)\n", (UINT32)result);
  995.         return 1;
  996.     }
  997.  
  998.     // set the fixed render state
  999.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ZENABLE, D3DZB_FALSE);
  1000.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_FILLMODE, D3DFILL_SOLID);
  1001.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_SHADEMODE, D3DSHADE_FLAT);
  1002.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ZWRITEENABLE, FALSE);
  1003.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHATESTENABLE, TRUE);
  1004.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_LASTPIXEL, TRUE);
  1005.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_CULLMODE, D3DCULL_NONE);
  1006.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ZFUNC, D3DCMP_LESS);
  1007.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHAREF, 0);
  1008.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHAFUNC, D3DCMP_GREATER);
  1009.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_DITHERENABLE, FALSE);
  1010.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_FOGENABLE, FALSE);
  1011.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_SPECULARENABLE, FALSE);
  1012.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_STENCILENABLE, FALSE);
  1013.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_WRAP0, FALSE);
  1014.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_CLIPPING, TRUE);
  1015.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_LIGHTING, FALSE);
  1016.     result = (*d3dintf->device.set_render_state)(m_device, D3DRS_COLORVERTEX, TRUE);
  1017.  
  1018.     result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, D3DTSS_COLOROP, D3DTOP_MODULATE);
  1019.     result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
  1020.     result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, D3DTSS_COLOROP, D3DTOP_MODULATE);
  1021.     result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
  1022.  
  1023.     // reset the local states to force updates
  1024.     reset_render_states();
  1025.  
  1026.     // clear the buffer
  1027.     result = (*d3dintf->device.clear)(m_device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0);
  1028.     result = (*d3dintf->device.present)(m_device, NULL, NULL, NULL, NULL, 0);
  1029.  
  1030.     m_texture_manager->create_resources();
  1031.  
  1032.     return 0;
  1033. }
  1034.  
  1035.  
  1036.  
  1037. //============================================================
  1038. //  device_delete
  1039. //============================================================
  1040.  
  1041. renderer::~renderer()
  1042. {
  1043.     device_delete();
  1044. }
  1045.  
  1046. void renderer::device_delete()
  1047. {
  1048.     if (m_shaders != NULL)
  1049.     {
  1050.         // free our effects
  1051.         m_shaders->delete_resources(false);
  1052.  
  1053.         // delete the HLSL interface
  1054.         global_free(m_shaders);
  1055.     }
  1056.  
  1057.     // free our base resources
  1058.     device_delete_resources();
  1059.  
  1060.     if (m_texture_manager != NULL)
  1061.     {
  1062.         global_free(m_texture_manager);
  1063.     }
  1064.     m_texture_manager = NULL;
  1065.  
  1066.     // free the device itself
  1067.     if (m_device != NULL)
  1068.     {
  1069.         (*d3dintf->device.reset)(m_device, &m_presentation);
  1070.         (*d3dintf->device.release)(m_device);
  1071.     }
  1072.     m_device = NULL;
  1073. }
  1074.  
  1075. //============================================================
  1076. //  device_delete_resources
  1077. //============================================================
  1078.  
  1079. void renderer::device_delete_resources()
  1080. {
  1081.     if (m_texture_manager != NULL)
  1082.         m_texture_manager->delete_resources();
  1083.     // free the vertex buffer
  1084.     if (m_vertexbuf != NULL)
  1085.         (*d3dintf->vertexbuf.release)(m_vertexbuf);
  1086.     m_vertexbuf = NULL;
  1087. }
  1088.  
  1089.  
  1090.  
  1091. //============================================================
  1092. //  device_verify_caps
  1093. //============================================================
  1094.  
  1095. int renderer::device_verify_caps()
  1096. {
  1097.     int retval = 0;
  1098.  
  1099.     m_shaders = global_alloc_clear(shaders);
  1100.     m_shaders->init(d3dintf, m_window);
  1101.  
  1102.     DWORD tempcaps;
  1103.     HRESULT result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_MAX_PS30_INSN_SLOTS, &tempcaps);
  1104.     if (result != D3D_OK) osd_printf_verbose("Direct3D Error %08X during get_caps_dword call\n", (int)result);
  1105.     if(tempcaps < 512)
  1106.     {
  1107.         osd_printf_verbose("Direct3D: Warning - Device does not support Pixel Shader 3.0, falling back to non-PS rendering\n");
  1108.         d3dintf->post_fx_available = false;
  1109.     }
  1110.  
  1111.     // verify presentation capabilities
  1112.     result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_PRESENTATION_INTERVALS, &tempcaps);
  1113.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
  1114.     if (!(tempcaps & D3DPRESENT_INTERVAL_IMMEDIATE))
  1115.     {
  1116.         osd_printf_verbose("Direct3D: Error - Device does not support immediate presentations\n");
  1117.         retval = 2;
  1118.     }
  1119.     if (!(tempcaps & D3DPRESENT_INTERVAL_ONE))
  1120.     {
  1121.         osd_printf_verbose("Direct3D: Error - Device does not support per-refresh presentations\n");
  1122.         retval = 2;
  1123.     }
  1124.  
  1125.     // verify device capabilities
  1126.     result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_DEV_CAPS, &tempcaps);
  1127.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
  1128.     if (!(tempcaps & D3DDEVCAPS_CANRENDERAFTERFLIP))
  1129.     {
  1130.         osd_printf_verbose("Direct3D: Warning - Device does not support queued rendering after a page flip\n");
  1131.         retval = 1;
  1132.     }
  1133.     if (!(tempcaps & D3DDEVCAPS_HWRASTERIZATION))
  1134.     {
  1135.         osd_printf_verbose("Direct3D: Warning - Device does not support hardware rasterization\n");
  1136.         retval = 1;
  1137.     }
  1138.  
  1139.     // verify texture operation capabilities
  1140.     result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_TEXTURE_OP_CAPS, &tempcaps);
  1141.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
  1142.     if (!(tempcaps & D3DTEXOPCAPS_MODULATE))
  1143.     {
  1144.         osd_printf_verbose("Direct3D: Warning - Device does not support texture modulation\n");
  1145.         retval = 1;
  1146.     }
  1147.  
  1148.     // set a simpler flag to indicate mod2x and mod4x texture modes
  1149.     m_mod2x_supported = ((tempcaps & D3DTEXOPCAPS_MODULATE2X) != 0);
  1150.     m_mod4x_supported = ((tempcaps & D3DTEXOPCAPS_MODULATE4X) != 0);
  1151.  
  1152.     result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_CAPS2, &tempcaps);
  1153.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result);
  1154.     m_gamma_supported = ((tempcaps & D3DCAPS2_FULLSCREENGAMMA) != 0);
  1155.  
  1156.     return retval;
  1157. }
  1158.  
  1159.  
  1160.  
  1161. //============================================================
  1162. //  device_test_cooperative
  1163. //============================================================
  1164.  
  1165. int renderer::device_test_cooperative()
  1166. {
  1167.     // check our current status; if we lost the device, punt to GDI
  1168.     HRESULT result = (*d3dintf->device.test_cooperative_level)(m_device);
  1169.     if (result == D3DERR_DEVICELOST)
  1170.         return 1;
  1171.  
  1172.     // if we're able to reset ourselves, try it
  1173.     if (result == D3DERR_DEVICENOTRESET)
  1174.     {
  1175.         osd_printf_verbose("Direct3D: resetting device\n");
  1176.  
  1177.         // free all existing resources and call reset on the device
  1178.         //device_delete();
  1179.         device_delete_resources();
  1180.         m_shaders->delete_resources(true);
  1181.         result = (*d3dintf->device.reset)(m_device, &m_presentation);
  1182.  
  1183.         // if it didn't work, punt to GDI
  1184.         if (result != D3D_OK)
  1185.         {
  1186.             osd_printf_error("Unable to reset, result %08x\n", (UINT32)result);
  1187.             return 1;
  1188.         }
  1189.  
  1190.         // try to create the resources again; if that didn't work, delete the whole thing
  1191.         if (device_create_resources())
  1192.         {
  1193.             osd_printf_verbose("Direct3D: failed to recreate resources for device; failing permanently\n");
  1194.             device_delete();
  1195.             return 1;
  1196.         }
  1197.  
  1198.         if (m_shaders->create_resources(true))
  1199.         {
  1200.             osd_printf_verbose("Direct3D: failed to recreate HLSL resources for device; failing permanently\n");
  1201.             device_delete();
  1202.             return 1;
  1203.         }
  1204.     }
  1205.     return 0;
  1206. }
  1207.  
  1208.  
  1209.  
  1210. //============================================================
  1211. //  config_adapter_mode
  1212. //============================================================
  1213.  
  1214. int renderer::config_adapter_mode()
  1215. {
  1216.     adapter_identifier identifier;
  1217.  
  1218.     // choose the monitor number
  1219.     m_adapter = get_adapter_for_monitor();
  1220.  
  1221.     // get the identifier
  1222.     HRESULT result = (*d3dintf->d3d.get_adapter_identifier)(d3dintf, m_adapter, 0, &identifier);
  1223.     if (result != D3D_OK)
  1224.     {
  1225.         osd_printf_error("Error getting identifier for adapter #%d\n", m_adapter);
  1226.         return 1;
  1227.     }
  1228.     osd_printf_verbose("Direct3D: Configuring adapter #%d = %s\n", m_adapter, identifier.Description);
  1229.  
  1230.     // get the current display mode
  1231.     result = (*d3dintf->d3d.get_adapter_display_mode)(d3dintf, m_adapter, &m_origmode);
  1232.     if (result != D3D_OK)
  1233.     {
  1234.         osd_printf_error("Error getting mode for adapter #%d\n", m_adapter);
  1235.         return 1;
  1236.     }
  1237.  
  1238.     // choose a resolution: window mode case
  1239.     if (!m_window->m_fullscreen || !video_config.switchres || win_has_menu(m_window))
  1240.     {
  1241.         RECT client;
  1242.  
  1243.         // bounds are from the window client rect
  1244.         GetClientRectExceptMenu(m_window->m_hwnd, &client, m_window->m_fullscreen);
  1245.         m_width = client.right - client.left;
  1246.         m_height = client.bottom - client.top;
  1247.  
  1248.         // pix format is from the current mode
  1249.         m_pixformat = m_origmode.Format;
  1250.         m_refresh = 0;
  1251.  
  1252.         // make sure it's a pixel format we can get behind
  1253.         if (m_pixformat != D3DFMT_X1R5G5B5 && m_pixformat != D3DFMT_R5G6B5 && m_pixformat != D3DFMT_X8R8G8B8)
  1254.         {
  1255.             char *utf8_device = utf8_from_tstring(m_window->m_monitor->info.szDevice);
  1256.             if (utf8_device != NULL)
  1257.             {
  1258.                 osd_printf_error("Device %s currently in an unsupported mode\n", utf8_device);
  1259.                 osd_free(utf8_device);
  1260.             }
  1261.             return 1;
  1262.         }
  1263.     }
  1264.  
  1265.     // choose a resolution: full screen mode case
  1266.     else
  1267.     {
  1268.         // default to the current mode exactly
  1269.         m_width = m_origmode.Width;
  1270.         m_height = m_origmode.Height;
  1271.         m_pixformat = m_origmode.Format;
  1272.         m_refresh = m_origmode.RefreshRate;
  1273.  
  1274.         // if we're allowed to switch resolutions, override with something better
  1275.         if (video_config.switchres)
  1276.             pick_best_mode();
  1277.     }
  1278.  
  1279.     // see if we can handle the device type
  1280.     result = (*d3dintf->d3d.check_device_type)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, m_pixformat, !m_window->m_fullscreen);
  1281.     if (result != D3D_OK)
  1282.     {
  1283.         char *utf8_device = utf8_from_tstring(m_window->m_monitor->info.szDevice);
  1284.         if (utf8_device != NULL)
  1285.         {
  1286.             osd_printf_error("Proposed video mode not supported on device %s\n", utf8_device);
  1287.             osd_free(utf8_device);
  1288.         }
  1289.         return 1;
  1290.     }
  1291.     return 0;
  1292. }
  1293.  
  1294.  
  1295.  
  1296. //============================================================
  1297. //  get_adapter_for_monitor
  1298. //============================================================
  1299.  
  1300. int renderer::get_adapter_for_monitor()
  1301. {
  1302.     int maxadapter = (*d3dintf->d3d.get_adapter_count)(d3dintf);
  1303.  
  1304.     // iterate over adapters until we error or find a match
  1305.     for (int adapternum = 0; adapternum < maxadapter; adapternum++)
  1306.     {
  1307.         // get the monitor for this adapter
  1308.         HMONITOR curmonitor = (*d3dintf->d3d.get_adapter_monitor)(d3dintf, adapternum);
  1309.  
  1310.         // if we match the proposed monitor, this is it
  1311.         if (curmonitor == m_window->m_monitor->handle)
  1312.         {
  1313.             return adapternum;
  1314.         }
  1315.     }
  1316.  
  1317.     // default to the default
  1318.     return D3DADAPTER_DEFAULT;
  1319. }
  1320.  
  1321.  
  1322.  
  1323. //============================================================
  1324. //  pick_best_mode
  1325. //============================================================
  1326.  
  1327. void renderer::pick_best_mode()
  1328. {
  1329.     double target_refresh = 60.0;
  1330.     INT32 minwidth, minheight;
  1331.     float best_score = 0.0f;
  1332.  
  1333.     // determine the refresh rate of the primary screen
  1334.     const screen_device *primary_screen = m_window->machine().config().first_screen();
  1335.     if (primary_screen != NULL)
  1336.     {
  1337.         target_refresh = ATTOSECONDS_TO_HZ(primary_screen->refresh_attoseconds());
  1338.     }
  1339.  
  1340.     // determine the minimum width/height for the selected target
  1341.     // note: technically we should not be calling this from an alternate window
  1342.     // thread; however, it is only done during init time, and the init code on
  1343.     // the main thread is waiting for us to finish, so it is safe to do so here
  1344.     m_window->m_target->compute_minimum_size(minwidth, minheight);
  1345.  
  1346.     // use those as the target for now
  1347.     INT32 target_width = minwidth;
  1348.     INT32 target_height = minheight;
  1349.  
  1350.     // determine the maximum number of modes
  1351.     int maxmodes = (*d3dintf->d3d.get_adapter_mode_count)(d3dintf, m_adapter, D3DFMT_X8R8G8B8);
  1352.  
  1353.     // enumerate all the video modes and find the best match
  1354.     osd_printf_verbose("Direct3D: Selecting video mode...\n");
  1355.     for (int modenum = 0; modenum < maxmodes; modenum++)
  1356.     {
  1357.         // check this mode
  1358.         D3DDISPLAYMODE mode;
  1359.         HRESULT result = (*d3dintf->d3d.enum_adapter_modes)(d3dintf, m_adapter, D3DFMT_X8R8G8B8, modenum, &mode);
  1360.         if (result != D3D_OK)
  1361.             break;
  1362.  
  1363.         // skip non-32 bit modes
  1364.         if (mode.Format != D3DFMT_X8R8G8B8)
  1365.             continue;
  1366.  
  1367.         // compute initial score based on difference between target and current
  1368.         float size_score = 1.0f / (1.0f + fabs((float)(mode.Width - target_width)) + fabs((float)(mode.Height - target_height)));
  1369.  
  1370.         // if the mode is too small, give a big penalty
  1371.         if (mode.Width < minwidth || mode.Height < minheight)
  1372.             size_score *= 0.01f;
  1373.  
  1374.         // if mode is smaller than we'd like, it only scores up to 0.1
  1375.         if (mode.Width < target_width || mode.Height < target_height)
  1376.             size_score *= 0.1f;
  1377.  
  1378.         // if we're looking for a particular mode, that's a winner
  1379.         if (mode.Width == m_window->m_maxwidth && mode.Height == m_window->m_maxheight)
  1380.             size_score = 2.0f;
  1381.  
  1382.         // compute refresh score
  1383.         float refresh_score = 1.0f / (1.0f + fabs((double)mode.RefreshRate - target_refresh));
  1384.  
  1385.         // if refresh is smaller than we'd like, it only scores up to 0.1
  1386.         if ((double)mode.RefreshRate < target_refresh)
  1387.             refresh_score *= 0.1f;
  1388.  
  1389.         // if we're looking for a particular refresh, make sure it matches
  1390.         if (mode.RefreshRate == m_window->m_refresh)
  1391.             refresh_score = 2.0f;
  1392.  
  1393.         // weight size and refresh equally
  1394.         float final_score = size_score + refresh_score;
  1395.  
  1396.         // best so far?
  1397.         osd_printf_verbose("  %4dx%4d@%3dHz -> %f\n", mode.Width, mode.Height, mode.RefreshRate, final_score * 1000.0f);
  1398.         if (final_score > best_score)
  1399.         {
  1400.             best_score = final_score;
  1401.             m_width = mode.Width;
  1402.             m_height = mode.Height;
  1403.             m_pixformat = mode.Format;
  1404.             m_refresh = mode.RefreshRate;
  1405.         }
  1406.     }
  1407.     osd_printf_verbose("Direct3D: Mode selected = %4dx%4d@%3dHz\n", m_width, m_height, m_refresh);
  1408. }
  1409.  
  1410.  
  1411.  
  1412. //============================================================
  1413. //  update_window_size
  1414. //============================================================
  1415.  
  1416. int renderer::update_window_size()
  1417. {
  1418.     // get the current window bounds
  1419.     RECT client;
  1420.     GetClientRectExceptMenu(m_window->m_hwnd, &client, m_window->m_fullscreen);
  1421.  
  1422.     // if we have a device and matching width/height, nothing to do
  1423.     if (m_device != NULL && rect_width(&client) == m_width && rect_height(&client) == m_height)
  1424.     {
  1425.         // clear out any pending resizing if the area didn't change
  1426.         if (m_window->m_resize_state == RESIZE_STATE_PENDING)
  1427.             m_window->m_resize_state = RESIZE_STATE_NORMAL;
  1428.         return FALSE;
  1429.     }
  1430.  
  1431.     // if we're in the middle of resizing, leave it alone as well
  1432.     if (m_window->m_resize_state == RESIZE_STATE_RESIZING)
  1433.         return FALSE;
  1434.  
  1435.     // set the new bounds and create the device again
  1436.     m_width = rect_width(&client);
  1437.     m_height = rect_height(&client);
  1438.     if (device_create())
  1439.         return FALSE;
  1440.  
  1441.     // reset the resize state to normal, and indicate we made a change
  1442.     m_window->m_resize_state = RESIZE_STATE_NORMAL;
  1443.     return TRUE;
  1444. }
  1445.  
  1446. //============================================================
  1447. //  batch_vectors
  1448. //============================================================
  1449.  
  1450. void renderer::batch_vectors()
  1451. {
  1452.     windows_options &options = downcast<windows_options &>(m_window->machine().options());
  1453.  
  1454.     int vector_size = (options.antialias() ? 24 : 6);
  1455.     m_vectorbatch = mesh_alloc(m_line_count * vector_size);
  1456.     m_batchindex = 0;
  1457.  
  1458.     static int start_index = 0;
  1459.     int line_index = 0;
  1460.     float period = options.screen_vector_time_period();
  1461.     UINT32 cached_flags = 0;
  1462.     for (render_primitive *prim = m_window->m_primlist->first(); prim != NULL; prim = prim->next())
  1463.     {
  1464.         switch (prim->type)
  1465.         {
  1466.             case render_primitive::LINE:
  1467.                 if (PRIMFLAG_GET_VECTOR(prim->flags))
  1468.                 {
  1469.                     if (period == 0.0f || m_line_count == 0)
  1470.                     {
  1471.                         batch_vector(prim, 1.0f);
  1472.                     }
  1473.                     else
  1474.                     {
  1475.                         batch_vector(prim, (float)(start_index + line_index) / ((float)m_line_count * period));
  1476.                         line_index++;
  1477.                     }
  1478.                     cached_flags = prim->flags;
  1479.                 }
  1480.                 break;
  1481.  
  1482.             default:
  1483.                 // Skip
  1484.                 break;
  1485.         }
  1486.     }
  1487.  
  1488.     // now add a polygon entry
  1489.     m_poly[m_numpolys].init(D3DPT_TRIANGLELIST, m_line_count * (options.antialias() ? 8 : 2), vector_size * m_line_count, cached_flags,
  1490.         m_texture_manager->get_vector_texture(), D3DTOP_MODULATE, 0.0f, 1.0f, 0.0f, 0.0f);
  1491.     m_numpolys++;
  1492.  
  1493.     start_index += (int)((float)line_index * period);
  1494.     if (m_line_count > 0)
  1495.     {
  1496.         start_index %= m_line_count;
  1497.     }
  1498.  
  1499.     m_line_count = 0;
  1500. }
  1501.  
  1502. void renderer::batch_vector(const render_primitive *prim, float line_time)
  1503. {
  1504.     // compute the effective width based on the direction of the line
  1505.     float effwidth = prim->width;
  1506.     if (effwidth < 0.5f)
  1507.     {
  1508.         effwidth = 0.5f;
  1509.     }
  1510.  
  1511.     // determine the bounds of a quad to draw this line
  1512.     render_bounds b0, b1;
  1513.     render_line_to_quad(&prim->bounds, effwidth, &b0, &b1);
  1514.  
  1515.     // iterate over AA steps
  1516.     for (const line_aa_step *step = PRIMFLAG_GET_ANTIALIAS(prim->flags) ? line_aa_4step : line_aa_1step;
  1517.         step->weight != 0; step++)
  1518.     {
  1519.         // get a pointer to the vertex buffer
  1520.         if (m_vectorbatch == NULL)
  1521.             return;
  1522.  
  1523.         m_vectorbatch[m_batchindex + 0].x = b0.x0 + step->xoffs;
  1524.         m_vectorbatch[m_batchindex + 0].y = b0.y0 + step->yoffs;
  1525.         m_vectorbatch[m_batchindex + 1].x = b0.x1 + step->xoffs;
  1526.         m_vectorbatch[m_batchindex + 1].y = b0.y1 + step->yoffs;
  1527.         m_vectorbatch[m_batchindex + 2].x = b1.x0 + step->xoffs;
  1528.         m_vectorbatch[m_batchindex + 2].y = b1.y0 + step->yoffs;
  1529.  
  1530.         m_vectorbatch[m_batchindex + 3].x = b0.x1 + step->xoffs;
  1531.         m_vectorbatch[m_batchindex + 3].y = b0.y1 + step->yoffs;
  1532.         m_vectorbatch[m_batchindex + 4].x = b1.x0 + step->xoffs;
  1533.         m_vectorbatch[m_batchindex + 4].y = b1.y0 + step->yoffs;
  1534.         m_vectorbatch[m_batchindex + 5].x = b1.x1 + step->xoffs;
  1535.         m_vectorbatch[m_batchindex + 5].y = b1.y1 + step->yoffs;
  1536.  
  1537.         float dx = b1.x1 - b0.x1;
  1538.         float dy = b1.y1 - b0.y1;
  1539.         float line_length = sqrtf(dx * dx + dy * dy);
  1540.  
  1541.         // determine the color of the line
  1542.         INT32 r = (INT32)(prim->color.r * step->weight * 255.0f);
  1543.         INT32 g = (INT32)(prim->color.g * step->weight * 255.0f);
  1544.         INT32 b = (INT32)(prim->color.b * step->weight * 255.0f);
  1545.         INT32 a = (INT32)(prim->color.a * 255.0f);
  1546.         if (r > 255 || g > 255 || b > 255)
  1547.         {
  1548.             if (r > 2*255 || g > 2*255 || b > 2*255)
  1549.             {
  1550.                 r >>= 2; g >>= 2; b >>= 2;
  1551.             }
  1552.             else
  1553.             {
  1554.                 r >>= 1; g >>= 1; b >>= 1;
  1555.             }
  1556.         }
  1557.         if (r > 255) r = 255;
  1558.         if (g > 255) g = 255;
  1559.         if (b > 255) b = 255;
  1560.         if (a > 255) a = 255;
  1561.         DWORD color = D3DCOLOR_ARGB(a, r, g, b);
  1562.  
  1563.         vec2f& start = (get_vector_texture() ? get_vector_texture()->get_uvstart() : get_default_texture()->get_uvstart());
  1564.         vec2f& stop = (get_vector_texture() ? get_vector_texture()->get_uvstop() : get_default_texture()->get_uvstop());
  1565.  
  1566.         m_vectorbatch[m_batchindex + 0].u0 = start.c.x;
  1567.         m_vectorbatch[m_batchindex + 0].v0 = start.c.y;
  1568.         m_vectorbatch[m_batchindex + 1].u0 = start.c.x;
  1569.         m_vectorbatch[m_batchindex + 1].v0 = stop.c.y;
  1570.         m_vectorbatch[m_batchindex + 2].u0 = stop.c.x;
  1571.         m_vectorbatch[m_batchindex + 2].v0 = start.c.y;
  1572.  
  1573.         m_vectorbatch[m_batchindex + 3].u0 = start.c.x;
  1574.         m_vectorbatch[m_batchindex + 3].v0 = stop.c.y;
  1575.         m_vectorbatch[m_batchindex + 4].u0 = stop.c.x;
  1576.         m_vectorbatch[m_batchindex + 4].v0 = start.c.y;
  1577.         m_vectorbatch[m_batchindex + 5].u0 = stop.c.x;
  1578.         m_vectorbatch[m_batchindex + 5].v0 = stop.c.y;
  1579.  
  1580.         m_vectorbatch[m_batchindex + 0].u1 = line_length;
  1581.         m_vectorbatch[m_batchindex + 1].u1 = line_length;
  1582.         m_vectorbatch[m_batchindex + 2].u1 = line_length;
  1583.         m_vectorbatch[m_batchindex + 3].u1 = line_length;
  1584.         m_vectorbatch[m_batchindex + 4].u1 = line_length;
  1585.         m_vectorbatch[m_batchindex + 5].u1 = line_length;
  1586.  
  1587.         // set the color, Z parameters to standard values
  1588.         for (int i = 0; i < 6; i++)
  1589.         {
  1590.             m_vectorbatch[m_batchindex + i].z = 0.0f;
  1591.             m_vectorbatch[m_batchindex + i].rhw = 1.0f;
  1592.             m_vectorbatch[m_batchindex + i].color = color;
  1593.         }
  1594.  
  1595.         m_batchindex += 6;
  1596.     }
  1597. }
  1598.  
  1599. //============================================================
  1600. //  draw_line
  1601. //============================================================
  1602.  
  1603. void renderer::draw_line(const render_primitive *prim)
  1604. {
  1605.     // compute the effective width based on the direction of the line
  1606.     float effwidth = prim->width;
  1607.     if (effwidth < 0.5f)
  1608.     {
  1609.         effwidth = 0.5f;
  1610.     }
  1611.  
  1612.     // determine the bounds of a quad to draw this line
  1613.     render_bounds b0, b1;
  1614.     render_line_to_quad(&prim->bounds, effwidth, &b0, &b1);
  1615.  
  1616.     // iterate over AA steps
  1617.     for (const line_aa_step *step = PRIMFLAG_GET_ANTIALIAS(prim->flags) ? line_aa_4step : line_aa_1step;
  1618.         step->weight != 0; step++)
  1619.     {
  1620.         // get a pointer to the vertex buffer
  1621.         vertex *vertex = mesh_alloc(4);
  1622.         if (vertex == NULL)
  1623.             return;
  1624.  
  1625.         // rotate the unit vector by 135 degrees and add to point 0
  1626.         vertex[0].x = b0.x0 + step->xoffs;
  1627.         vertex[0].y = b0.y0 + step->yoffs;
  1628.  
  1629.         // rotate the unit vector by -135 degrees and add to point 0
  1630.         vertex[1].x = b0.x1 + step->xoffs;
  1631.         vertex[1].y = b0.y1 + step->yoffs;
  1632.  
  1633.         // rotate the unit vector by 45 degrees and add to point 1
  1634.         vertex[2].x = b1.x0 + step->xoffs;
  1635.         vertex[2].y = b1.y0 + step->yoffs;
  1636.  
  1637.         // rotate the unit vector by -45 degrees and add to point 1
  1638.         vertex[3].x = b1.x1 + step->xoffs;
  1639.         vertex[3].y = b1.y1 + step->yoffs;
  1640.  
  1641.         // determine the color of the line
  1642.         INT32 r = (INT32)(prim->color.r * step->weight * 255.0f);
  1643.         INT32 g = (INT32)(prim->color.g * step->weight * 255.0f);
  1644.         INT32 b = (INT32)(prim->color.b * step->weight * 255.0f);
  1645.         INT32 a = (INT32)(prim->color.a * 255.0f);
  1646.         if (r > 255) r = 255;
  1647.         if (g > 255) g = 255;
  1648.         if (b > 255) b = 255;
  1649.         if (a > 255) a = 255;
  1650.         DWORD color = D3DCOLOR_ARGB(a, r, g, b);
  1651.  
  1652.         vec2f& start = (get_vector_texture() ? get_vector_texture()->get_uvstart() : get_default_texture()->get_uvstart());
  1653.         vec2f& stop = (get_vector_texture() ? get_vector_texture()->get_uvstop() : get_default_texture()->get_uvstop());
  1654.  
  1655.         vertex[0].u0 = start.c.x;
  1656.         vertex[0].v0 = start.c.y;
  1657.  
  1658.         vertex[2].u0 = stop.c.x;
  1659.         vertex[2].v0 = start.c.y;
  1660.  
  1661.         vertex[1].u0 = start.c.x;
  1662.         vertex[1].v0 = stop.c.y;
  1663.  
  1664.         vertex[3].u0 = stop.c.x;
  1665.         vertex[3].v0 = stop.c.y;
  1666.  
  1667.         // set the color, Z parameters to standard values
  1668.         for (int i = 0; i < 4; i++)
  1669.         {
  1670.             vertex[i].z = 0.0f;
  1671.             vertex[i].rhw = 1.0f;
  1672.             vertex[i].color = color;
  1673.         }
  1674.  
  1675.         // now add a polygon entry
  1676.         m_poly[m_numpolys].init(D3DPT_TRIANGLESTRIP, 2, 4, prim->flags, get_vector_texture(),
  1677.                                 D3DTOP_MODULATE, 0.0f, 1.0f, 0.0f, 0.0f);
  1678.         m_numpolys++;
  1679.     }
  1680. }
  1681.  
  1682.  
  1683.  
  1684. //============================================================
  1685. //  draw_quad
  1686. //============================================================
  1687.  
  1688. void renderer::draw_quad(const render_primitive *prim)
  1689. {
  1690.     texture_info *texture = m_texture_manager->find_texinfo(&prim->texture, prim->flags);
  1691.  
  1692.     if (texture == NULL)
  1693.     {
  1694.         texture = get_default_texture();
  1695.     }
  1696.  
  1697.     // get a pointer to the vertex buffer
  1698.     vertex *vertex = mesh_alloc(4);
  1699.     if (vertex == NULL)
  1700.         return;
  1701.  
  1702.     // fill in the vertexes clockwise
  1703.     vertex[0].x = prim->bounds.x0 - 0.5f;
  1704.     vertex[0].y = prim->bounds.y0 - 0.5f;
  1705.     vertex[1].x = prim->bounds.x1 - 0.5f;
  1706.     vertex[1].y = prim->bounds.y0 - 0.5f;
  1707.     vertex[2].x = prim->bounds.x0 - 0.5f;
  1708.     vertex[2].y = prim->bounds.y1 - 0.5f;
  1709.     vertex[3].x = prim->bounds.x1 - 0.5f;
  1710.     vertex[3].y = prim->bounds.y1 - 0.5f;
  1711.     float width = prim->bounds.x1 - prim->bounds.x0;
  1712.     float height = prim->bounds.y1 - prim->bounds.y0;
  1713.  
  1714.     // set the texture coordinates
  1715.     if(texture != NULL)
  1716.     {
  1717.         vec2f& start = texture->get_uvstart();
  1718.         vec2f& stop = texture->get_uvstop();
  1719.         vec2f delta = stop - start;
  1720.         vertex[0].u0 = start.c.x + delta.c.x * prim->texcoords.tl.u;
  1721.         vertex[0].v0 = start.c.y + delta.c.y * prim->texcoords.tl.v;
  1722.         vertex[1].u0 = start.c.x + delta.c.x * prim->texcoords.tr.u;
  1723.         vertex[1].v0 = start.c.y + delta.c.y * prim->texcoords.tr.v;
  1724.         vertex[2].u0 = start.c.x + delta.c.x * prim->texcoords.bl.u;
  1725.         vertex[2].v0 = start.c.y + delta.c.y * prim->texcoords.bl.v;
  1726.         vertex[3].u0 = start.c.x + delta.c.x * prim->texcoords.br.u;
  1727.         vertex[3].v0 = start.c.y + delta.c.y * prim->texcoords.br.v;
  1728.     }
  1729.  
  1730.     // determine the color, allowing for over modulation
  1731.     INT32 r = (INT32)(prim->color.r * 255.0f);
  1732.     INT32 g = (INT32)(prim->color.g * 255.0f);
  1733.     INT32 b = (INT32)(prim->color.b * 255.0f);
  1734.     INT32 a = (INT32)(prim->color.a * 255.0f);
  1735.     DWORD modmode = D3DTOP_MODULATE;
  1736.     if (texture != NULL)
  1737.     {
  1738.         if (m_mod2x_supported && (r > 255 || g > 255 || b > 255))
  1739.         {
  1740.             if (m_mod4x_supported && (r > 2*255 || g > 2*255 || b > 2*255))
  1741.             {
  1742.                 r >>= 2; g >>= 2; b >>= 2;
  1743.                 modmode = D3DTOP_MODULATE4X;
  1744.             }
  1745.             else
  1746.             {
  1747.                 r >>= 1; g >>= 1; b >>= 1;
  1748.                 modmode = D3DTOP_MODULATE2X;
  1749.             }
  1750.         }
  1751.     }
  1752.     if (r > 255) r = 255;
  1753.     if (g > 255) g = 255;
  1754.     if (b > 255) b = 255;
  1755.     if (a > 255) a = 255;
  1756.     DWORD color = D3DCOLOR_ARGB(a, r, g, b);
  1757.  
  1758.     // set the color, Z parameters to standard values
  1759.     for (int i = 0; i < 4; i++)
  1760.     {
  1761.         vertex[i].z = 0.0f;
  1762.         vertex[i].rhw = 1.0f;
  1763.         vertex[i].color = color;
  1764.     }
  1765.  
  1766.     // now add a polygon entry
  1767.     m_poly[m_numpolys].init(D3DPT_TRIANGLESTRIP, 2, 4, prim->flags, texture, modmode, width, height);
  1768.     m_numpolys++;
  1769. }
  1770.  
  1771. void poly_info::init(D3DPRIMITIVETYPE type, UINT32 count, UINT32 numverts,
  1772.                             UINT32 flags, texture_info *texture, UINT32 modmode,
  1773.                             float line_time, float line_length,
  1774.                             float prim_width, float prim_height)
  1775. {
  1776.     init(type, count, numverts, flags, texture, modmode, prim_width, prim_height);
  1777.     m_line_time = line_time;
  1778.     m_line_length = line_length;
  1779. }
  1780.  
  1781. void poly_info::init(D3DPRIMITIVETYPE type, UINT32 count, UINT32 numverts,
  1782.                             UINT32 flags, texture_info *texture, UINT32 modmode,
  1783.                             float prim_width, float prim_height)
  1784. {
  1785.     m_type = type;
  1786.     m_count = count;
  1787.     m_numverts = numverts;
  1788.     m_flags = flags;
  1789.     m_texture = texture;
  1790.     m_modmode = modmode;
  1791.     m_prim_width = prim_width;
  1792.     m_prim_height = prim_height;
  1793. }
  1794.  
  1795. //============================================================
  1796. //  primitive_alloc
  1797. //============================================================
  1798.  
  1799. vertex *renderer::mesh_alloc(int numverts)
  1800. {
  1801.     HRESULT result;
  1802.  
  1803.     // if we're going to overflow, flush
  1804.     if (m_lockedbuf != NULL && m_numverts + numverts >= VERTEX_BUFFER_SIZE)
  1805.     {
  1806.         primitive_flush_pending();
  1807.  
  1808.         if(m_shaders->enabled())
  1809.         {
  1810.             m_hlsl_buf = (void*)mesh_alloc(6);
  1811.             m_shaders->init_fsfx_quad(m_hlsl_buf);
  1812.         }
  1813.     }
  1814.  
  1815.     // if we don't have a lock, grab it now
  1816.     if (m_lockedbuf == NULL)
  1817.     {
  1818.         result = (*d3dintf->vertexbuf.lock)(m_vertexbuf, 0, 0, (VOID **)&m_lockedbuf, D3DLOCK_DISCARD);
  1819.         if (result != D3D_OK)
  1820.             return NULL;
  1821.     }
  1822.  
  1823.     // if we already have the lock and enough room, just return a pointer
  1824.     if (m_lockedbuf != NULL && m_numverts + numverts < VERTEX_BUFFER_SIZE)
  1825.     {
  1826.         int oldverts = m_numverts;
  1827.         m_numverts += numverts;
  1828.         return &m_lockedbuf[oldverts];
  1829.     }
  1830.     return NULL;
  1831. }
  1832.  
  1833.  
  1834.  
  1835. //============================================================
  1836. //  primitive_flush_pending
  1837. //============================================================
  1838.  
  1839. void renderer::primitive_flush_pending()
  1840. {
  1841.     // ignore if we're not locked
  1842.     if (m_lockedbuf == NULL)
  1843.     {
  1844.         return;
  1845.     }
  1846.  
  1847.     // unlock the buffer
  1848.     HRESULT result = (*d3dintf->vertexbuf.unlock)(m_vertexbuf);
  1849.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during vertex buffer unlock call\n", (int)result);
  1850.     m_lockedbuf = NULL;
  1851.  
  1852.     // set the stream
  1853.     result = (*d3dintf->device.set_stream_source)(m_device, 0, m_vertexbuf, sizeof(vertex));
  1854.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_stream_source call\n", (int)result);
  1855.  
  1856.     m_shaders->begin_draw();
  1857.  
  1858.     int vertnum = 0;
  1859.     if (m_shaders->enabled())
  1860.     {
  1861.         vertnum = 6;
  1862.     }
  1863.  
  1864.     // now do the polys
  1865.     for (int polynum = 0; polynum < m_numpolys; polynum++)
  1866.     {
  1867.         UINT32 flags = m_poly[polynum].get_flags();
  1868.         texture_info *texture = m_poly[polynum].get_texture();
  1869.         int newfilter;
  1870.  
  1871.         // set the texture if different
  1872.         set_texture(texture);
  1873.  
  1874.         // set filtering if different
  1875.         if (texture != NULL)
  1876.         {
  1877.             newfilter = FALSE;
  1878.             if (PRIMFLAG_GET_SCREENTEX(flags))
  1879.                 newfilter = video_config.filter;
  1880.             set_filter(newfilter);
  1881.             set_wrap(PRIMFLAG_GET_TEXWRAP(flags) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP);
  1882.             set_modmode(m_poly[polynum].get_modmode());
  1883.  
  1884.             m_shaders->init_effect_info(&m_poly[polynum]);
  1885.         }
  1886.  
  1887.         // set the blendmode if different
  1888.         set_blendmode(PRIMFLAG_GET_BLENDMODE(flags));
  1889.  
  1890.         if (vertnum + m_poly[polynum].get_vertcount() > m_numverts)
  1891.         {
  1892.             osd_printf_error("Error: vertnum (%d) plus poly vertex count (%d) > %d\n", vertnum, m_poly[polynum].get_vertcount(), m_numverts);
  1893.             fflush(stdout);
  1894.         }
  1895.  
  1896.         assert(vertnum + m_poly[polynum].get_vertcount() <= m_numverts);
  1897.  
  1898.         if(m_shaders->enabled() && d3dintf->post_fx_available)
  1899.         {
  1900.             m_shaders->render_quad(&m_poly[polynum], vertnum);
  1901.         }
  1902.         else
  1903.         {
  1904.             // add the primitives
  1905.             result = (*d3dintf->device.draw_primitive)(m_device, m_poly[polynum].get_type(), vertnum,
  1906.                                                         m_poly[polynum].get_count());
  1907.             if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result);
  1908.         }
  1909.  
  1910.         vertnum += m_poly[polynum].get_vertcount();
  1911.     }
  1912.  
  1913.     m_shaders->end_draw();
  1914.  
  1915.     // reset the vertex count
  1916.     m_numverts = 0;
  1917.     m_numpolys = 0;
  1918. }
  1919.  
  1920. //============================================================
  1921. //  texture_info destructor
  1922. //============================================================
  1923.  
  1924. texture_info::~texture_info()
  1925. {
  1926.     if (m_d3dfinaltex != NULL)
  1927.     {
  1928.         if (m_d3dtex == m_d3dfinaltex)
  1929.         {
  1930.             m_d3dtex = NULL;
  1931.         }
  1932.         (*d3dintf->texture.release)(m_d3dfinaltex);
  1933.         m_d3dfinaltex = NULL;
  1934.     }
  1935.     if (m_d3dtex != NULL)
  1936.     {
  1937.         (*d3dintf->texture.release)(m_d3dtex);
  1938.         m_d3dtex = NULL;
  1939.     }
  1940.     if (m_d3dsurface != NULL)
  1941.     {
  1942.         (*d3dintf->surface.release)(m_d3dsurface);
  1943.         m_d3dsurface = NULL;
  1944.     }
  1945. }
  1946.  
  1947. //============================================================
  1948. //  texture_info constructor
  1949. //============================================================
  1950.  
  1951. texture_info::texture_info(texture_manager *manager, const render_texinfo* texsource, UINT32 flags)
  1952. {
  1953.     HRESULT result;
  1954.  
  1955.     // fill in the core data
  1956.     m_texture_manager = manager;
  1957.     m_renderer = m_texture_manager->get_d3d();
  1958.     m_hash = m_texture_manager->texture_compute_hash(texsource, flags);
  1959.     m_flags = flags;
  1960.     m_texinfo = *texsource;
  1961.     m_xprescale = video_config.prescale;
  1962.     m_yprescale = video_config.prescale;
  1963.  
  1964.     m_d3dtex = NULL;
  1965.     m_d3dsurface = NULL;
  1966.     m_d3dfinaltex = NULL;
  1967.  
  1968.     // compute the size
  1969.     compute_size(texsource->width, texsource->height);
  1970.  
  1971.     // non-screen textures are easy
  1972.     if (!PRIMFLAG_GET_SCREENTEX(flags))
  1973.     {
  1974.         assert(PRIMFLAG_TEXFORMAT(flags) != TEXFORMAT_YUY16);
  1975.         DWORD usage = m_texture_manager->is_dynamic_supported() ? D3DUSAGE_DYNAMIC : 0;
  1976.         D3DPOOL pool = m_texture_manager->is_dynamic_supported() ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
  1977.         result = (*d3dintf->device.create_texture)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, 1, usage, D3DFMT_A8R8G8B8, pool, &m_d3dtex);
  1978.         if (result != D3D_OK)
  1979.             goto error;
  1980.         m_d3dfinaltex = m_d3dtex;
  1981.         m_type = TEXTURE_TYPE_PLAIN;
  1982.     }
  1983.  
  1984.     // screen textures are allocated differently
  1985.     else
  1986.     {
  1987.         D3DFORMAT format;
  1988.         DWORD usage = m_texture_manager->is_dynamic_supported() ? D3DUSAGE_DYNAMIC : 0;
  1989.         D3DPOOL pool = m_texture_manager->is_dynamic_supported() ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
  1990.         int maxdim = MAX(m_renderer->get_presentation()->BackBufferWidth, m_renderer->get_presentation()->BackBufferHeight);
  1991.  
  1992.         // pick the format
  1993.         if (PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_YUY16)
  1994.         {
  1995.             format = m_texture_manager->get_yuv_format();
  1996.         }
  1997.         else if (PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_ARGB32 || PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_PALETTEA16)
  1998.         {
  1999.             format = D3DFMT_A8R8G8B8;
  2000.         }
  2001.         else
  2002.         {
  2003.             format = m_renderer->get_screen_format();
  2004.         }
  2005.  
  2006.         // don't prescale above screen size
  2007.         while (m_xprescale > 1 && m_rawdims.c.x * m_xprescale >= 2 * maxdim)
  2008.         {
  2009.             m_xprescale--;
  2010.         }
  2011.         while (m_xprescale > 1 && m_rawdims.c.x * m_xprescale > manager->get_max_texture_width())
  2012.         {
  2013.             m_xprescale--;
  2014.         }
  2015.         while (m_yprescale > 1 && m_rawdims.c.y * m_yprescale >= 2 * maxdim)
  2016.         {
  2017.             m_yprescale--;
  2018.         }
  2019.         while (m_yprescale > 1 && m_rawdims.c.y * m_yprescale > manager->get_max_texture_height())
  2020.         {
  2021.             m_yprescale--;
  2022.         }
  2023.         if (m_xprescale != video_config.prescale || m_yprescale != video_config.prescale)
  2024.         {
  2025.             osd_printf_verbose("Direct3D: adjusting prescale from %dx%d to %dx%d\n", video_config.prescale, video_config.prescale, m_xprescale, m_yprescale);
  2026.         }
  2027.  
  2028.         // loop until we allocate something or error
  2029.         for (int attempt = 0; attempt < 2; attempt++)
  2030.         {
  2031.             // second attempt is always 1:1
  2032.             if (attempt == 1)
  2033.             {
  2034.                 m_xprescale = m_yprescale = 1;
  2035.             }
  2036.  
  2037.             // screen textures with no prescaling are pretty easy
  2038.             if (m_xprescale == 1 && m_yprescale == 1)
  2039.             {
  2040.                 result = (*d3dintf->device.create_texture)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, 1, usage, format, pool, &m_d3dtex);
  2041.                 if (result == D3D_OK)
  2042.                 {
  2043.                     m_d3dfinaltex = m_d3dtex;
  2044.                     m_type = m_texture_manager->is_dynamic_supported() ? TEXTURE_TYPE_DYNAMIC : TEXTURE_TYPE_PLAIN;
  2045.  
  2046.                     if (m_renderer->get_shaders()->enabled() && !m_renderer->get_shaders()->register_texture(this))
  2047.                     {
  2048.                         goto error;
  2049.                     }
  2050.  
  2051.                     break;
  2052.                 }
  2053.             }
  2054.  
  2055.             // screen textures with prescaling require two allocations
  2056.             else
  2057.             {
  2058.                 // use an offscreen plain surface for stretching if supported
  2059.                 // (won't work for YUY textures)
  2060.                 if (m_texture_manager->is_stretch_supported() && PRIMFLAG_GET_TEXFORMAT(flags) != TEXFORMAT_YUY16)
  2061.                 {
  2062.                     result = (*d3dintf->device.create_offscreen_plain_surface)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, format, D3DPOOL_DEFAULT, &m_d3dsurface);
  2063.                     if (result != D3D_OK)
  2064.                     {
  2065.                         continue;
  2066.                     }
  2067.                     m_type = TEXTURE_TYPE_SURFACE;
  2068.                 }
  2069.  
  2070.                 // otherwise, we allocate a dynamic texture for the source
  2071.                 else
  2072.                 {
  2073.                     result = (*d3dintf->device.create_texture)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, 1, usage, format, pool, &m_d3dtex);
  2074.                     if (result != D3D_OK)
  2075.                     {
  2076.                         continue;
  2077.                     }
  2078.                     m_type = m_texture_manager->is_dynamic_supported() ? TEXTURE_TYPE_DYNAMIC : TEXTURE_TYPE_PLAIN;
  2079.                 }
  2080.  
  2081.                 // for the target surface, we allocate a render target texture
  2082.                 int scwidth = m_rawdims.c.x * m_xprescale;
  2083.                 int scheight = m_rawdims.c.y * m_yprescale;
  2084.  
  2085.                 // target surfaces typically cannot be YCbCr, so we always pick RGB in that case
  2086.                 D3DFORMAT finalfmt = (format != m_texture_manager->get_yuv_format()) ? format : D3DFMT_A8R8G8B8;
  2087.                 result = (*d3dintf->device.create_texture)(m_renderer->get_device(), scwidth, scheight, 1, D3DUSAGE_RENDERTARGET, finalfmt, D3DPOOL_DEFAULT, &m_d3dfinaltex);
  2088.                 if (result == D3D_OK)
  2089.                 {
  2090.                     if (m_renderer->get_shaders()->enabled() && !m_renderer->get_shaders()->register_prescaled_texture(this))
  2091.                     {
  2092.                         goto error;
  2093.                     }
  2094.                     break;
  2095.                 }
  2096.                 (*d3dintf->texture.release)(m_d3dtex);
  2097.                 m_d3dtex = NULL;
  2098.             }
  2099.         }
  2100.     }
  2101.  
  2102.     // copy the data to the texture
  2103.     set_data(texsource, flags);
  2104.  
  2105.     //texsource->osdhandle = (void*)this;
  2106.     // add us to the texture list
  2107.     if(m_texture_manager->get_texlist() != NULL)
  2108.         m_texture_manager->get_texlist()->m_prev = this;
  2109.     m_prev = NULL;
  2110.     m_next = m_texture_manager->get_texlist();
  2111.     m_texture_manager->set_texlist(this);
  2112.     return;
  2113.  
  2114. error:
  2115.     d3dintf->post_fx_available = false;
  2116.     osd_printf_error("Direct3D: Critical warning: A texture failed to allocate. Expect things to get bad quickly.\n");
  2117.     if (m_d3dsurface != NULL)
  2118.         (*d3dintf->surface.release)(m_d3dsurface);
  2119.     if (m_d3dtex != NULL)
  2120.         (*d3dintf->texture.release)(m_d3dtex);
  2121. }
  2122.  
  2123.  
  2124.  
  2125. //============================================================
  2126. //  texture_info::compute_size
  2127. //============================================================
  2128.  
  2129. void texture_info::compute_size(int texwidth, int texheight)
  2130. {
  2131.     int finalheight = texheight;
  2132.     int finalwidth = texwidth;
  2133.  
  2134.     // if we're not wrapping, add a 1-2 pixel border on all sides
  2135.     m_xborderpix = 0;
  2136.     m_yborderpix = 0;
  2137.     if (ENABLE_BORDER_PIX && !(m_flags & PRIMFLAG_TEXWRAP_MASK))
  2138.     {
  2139.         // note we need 2 pixels in X for YUY textures
  2140.         m_xborderpix = (PRIMFLAG_GET_TEXFORMAT(m_flags) == TEXFORMAT_YUY16) ? 2 : 1;
  2141.         m_yborderpix = 1;
  2142.     }
  2143.  
  2144.     // compute final texture size
  2145.     finalwidth += 2 * m_xborderpix;
  2146.     finalheight += 2 * m_yborderpix;
  2147.  
  2148.     // round width/height up to nearest power of 2 if we need to
  2149.     if (!(m_texture_manager->get_texture_caps() & D3DPTEXTURECAPS_NONPOW2CONDITIONAL))
  2150.     {
  2151.         // first the width
  2152.         if (finalwidth & (finalwidth - 1))
  2153.         {
  2154.             finalwidth |= finalwidth >> 1;
  2155.             finalwidth |= finalwidth >> 2;
  2156.             finalwidth |= finalwidth >> 4;
  2157.             finalwidth |= finalwidth >> 8;
  2158.             finalwidth++;
  2159.         }
  2160.  
  2161.         // then the height
  2162.         if (finalheight & (finalheight - 1))
  2163.         {
  2164.             finalheight |= finalheight >> 1;
  2165.             finalheight |= finalheight >> 2;
  2166.             finalheight |= finalheight >> 4;
  2167.             finalheight |= finalheight >> 8;
  2168.             finalheight++;
  2169.         }
  2170.     }
  2171.  
  2172.     // round up to square if we need to
  2173.     if (m_texture_manager->get_texture_caps() & D3DPTEXTURECAPS_SQUAREONLY)
  2174.     {
  2175.         if (finalwidth < finalheight)
  2176.             finalwidth = finalheight;
  2177.         else
  2178.             finalheight = finalwidth;
  2179.     }
  2180.  
  2181.     // adjust the aspect ratio if we need to
  2182.     while (finalwidth < finalheight && finalheight / finalwidth > m_texture_manager->get_max_texture_aspect())
  2183.     {
  2184.         finalwidth *= 2;
  2185.     }
  2186.     while (finalheight < finalwidth && finalwidth / finalheight > m_texture_manager->get_max_texture_aspect())
  2187.     {
  2188.         finalheight *= 2;
  2189.     }
  2190.  
  2191.     // if we added pixels for the border, and that just barely pushed us over, take it back
  2192.     if ((finalwidth > m_texture_manager->get_max_texture_width() && finalwidth - 2 * m_xborderpix <= m_texture_manager->get_max_texture_width()) ||
  2193.         (finalheight > m_texture_manager->get_max_texture_height() && finalheight - 2 * m_yborderpix <= m_texture_manager->get_max_texture_height()))
  2194.     {
  2195.         finalwidth -= 2 * m_xborderpix;
  2196.         finalheight -= 2 * m_yborderpix;
  2197.         m_xborderpix = 0;
  2198.         m_yborderpix = 0;
  2199.     }
  2200.  
  2201.     // if we're above the max width/height, do what?
  2202.     if (finalwidth > m_texture_manager->get_max_texture_width() || finalheight > m_texture_manager->get_max_texture_height())
  2203.     {
  2204.         static int printed = FALSE;
  2205.         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());
  2206.         printed = TRUE;
  2207.     }
  2208.  
  2209.     // compute the U/V scale factors
  2210.     m_start.c.x = (float)m_xborderpix / (float)finalwidth;
  2211.     m_start.c.y = (float)m_yborderpix / (float)finalheight;
  2212.     m_stop.c.x = (float)(texwidth + m_xborderpix) / (float)finalwidth;
  2213.     m_stop.c.y = (float)(texheight + m_yborderpix) / (float)finalheight;
  2214.  
  2215.     // set the final values
  2216.     m_rawdims.c.x = finalwidth;
  2217.     m_rawdims.c.y = finalheight;
  2218. }
  2219.  
  2220.  
  2221.  
  2222. //============================================================
  2223. //  copyline_palette16
  2224. //============================================================
  2225.  
  2226. INLINE void copyline_palette16(UINT32 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix)
  2227. {
  2228.     int x;
  2229.  
  2230.     assert(xborderpix == 0 || xborderpix == 1);
  2231.     if (xborderpix)
  2232.         *dst++ = 0xff000000 | palette[*src];
  2233.     for (x = 0; x < width; x++)
  2234.         *dst++ = 0xff000000 | palette[*src++];
  2235.     if (xborderpix)
  2236.         *dst++ = 0xff000000 | palette[*--src];
  2237. }
  2238.  
  2239.  
  2240.  
  2241. //============================================================
  2242. //  copyline_palettea16
  2243. //============================================================
  2244.  
  2245. INLINE void copyline_palettea16(UINT32 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix)
  2246. {
  2247.     int x;
  2248.  
  2249.     assert(xborderpix == 0 || xborderpix == 1);
  2250.     if (xborderpix)
  2251.         *dst++ = palette[*src];
  2252.     for (x = 0; x < width; x++)
  2253.         *dst++ = palette[*src++];
  2254.     if (xborderpix)
  2255.         *dst++ = palette[*--src];
  2256. }
  2257.  
  2258.  
  2259.  
  2260. //============================================================
  2261. //  copyline_rgb32
  2262. //============================================================
  2263.  
  2264. INLINE void copyline_rgb32(UINT32 *dst, const UINT32 *src, int width, const rgb_t *palette, int xborderpix)
  2265. {
  2266.     int x;
  2267.  
  2268.     assert(xborderpix == 0 || xborderpix == 1);
  2269.  
  2270.     // palette (really RGB map) case
  2271.     if (palette != NULL)
  2272.     {
  2273.         if (xborderpix)
  2274.         {
  2275.             rgb_t srcpix = *src;
  2276.             *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
  2277.         }
  2278.         for (x = 0; x < width; x++)
  2279.         {
  2280.             rgb_t srcpix = *src++;
  2281.             *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
  2282.         }
  2283.         if (xborderpix)
  2284.         {
  2285.             rgb_t srcpix = *--src;
  2286.             *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
  2287.         }
  2288.     }
  2289.  
  2290.     // direct case
  2291.     else
  2292.     {
  2293.         if (xborderpix)
  2294.             *dst++ = 0xff000000 | *src;
  2295.         for (x = 0; x < width; x++)
  2296.             *dst++ = 0xff000000 | *src++;
  2297.         if (xborderpix)
  2298.             *dst++ = 0xff000000 | *--src;
  2299.     }
  2300. }
  2301.  
  2302.  
  2303.  
  2304. //============================================================
  2305. //  copyline_argb32
  2306. //============================================================
  2307.  
  2308. INLINE void copyline_argb32(UINT32 *dst, const UINT32 *src, int width, const rgb_t *palette, int xborderpix)
  2309. {
  2310.     int x;
  2311.  
  2312.     assert(xborderpix == 0 || xborderpix == 1);
  2313.  
  2314.     // palette (really RGB map) case
  2315.     if (palette != NULL)
  2316.     {
  2317.         if (xborderpix)
  2318.         {
  2319.             rgb_t srcpix = *src;
  2320.             *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
  2321.         }
  2322.         for (x = 0; x < width; x++)
  2323.         {
  2324.             rgb_t srcpix = *src++;
  2325.             *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
  2326.         }
  2327.         if (xborderpix)
  2328.         {
  2329.             rgb_t srcpix = *--src;
  2330.             *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
  2331.         }
  2332.     }
  2333.  
  2334.     // direct case
  2335.     else
  2336.     {
  2337.         if (xborderpix)
  2338.             *dst++ = *src;
  2339.         for (x = 0; x < width; x++)
  2340.             *dst++ = *src++;
  2341.         if (xborderpix)
  2342.             *dst++ = *--src;
  2343.     }
  2344. }
  2345.  
  2346.  
  2347.  
  2348. //============================================================
  2349. //  copyline_yuy16_to_yuy2
  2350. //============================================================
  2351.  
  2352. INLINE void copyline_yuy16_to_yuy2(UINT16 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix)
  2353. {
  2354.     int x;
  2355.  
  2356.     assert(xborderpix == 0 || xborderpix == 2);
  2357.     assert(width % 2 == 0);
  2358.  
  2359.     // palette (really RGB map) case
  2360.     if (palette != NULL)
  2361.     {
  2362.         if (xborderpix)
  2363.         {
  2364.             UINT16 srcpix0 = *src++;
  2365.             UINT16 srcpix1 = *src--;
  2366.             *dst++ = palette[0x000 + (srcpix0 >> 8)] | (srcpix0 << 8);
  2367.             *dst++ = palette[0x000 + (srcpix0 >> 8)] | (srcpix1 << 8);
  2368.         }
  2369.         for (x = 0; x < width; x += 2)
  2370.         {
  2371.             UINT16 srcpix0 = *src++;
  2372.             UINT16 srcpix1 = *src++;
  2373.             *dst++ = palette[0x000 + (srcpix0 >> 8)] | (srcpix0 << 8);
  2374.             *dst++ = palette[0x000 + (srcpix1 >> 8)] | (srcpix1 << 8);
  2375.         }
  2376.         if (xborderpix)
  2377.         {
  2378.             UINT16 srcpix1 = *--src;
  2379.             UINT16 srcpix0 = *--src;
  2380.             *dst++ = palette[0x000 + (srcpix1 >> 8)] | (srcpix0 << 8);
  2381.             *dst++ = palette[0x000 + (srcpix1 >> 8)] | (srcpix1 << 8);
  2382.         }
  2383.     }
  2384.  
  2385.     // direct case
  2386.     else
  2387.     {
  2388.         if (xborderpix)
  2389.         {
  2390.             UINT16 srcpix0 = *src++;
  2391.             UINT16 srcpix1 = *src--;
  2392.             *dst++ = (srcpix0 >> 8) | (srcpix0 << 8);
  2393.             *dst++ = (srcpix0 >> 8) | (srcpix1 << 8);
  2394.         }
  2395.         for (x = 0; x < width; x += 2)
  2396.         {
  2397.             UINT16 srcpix0 = *src++;
  2398.             UINT16 srcpix1 = *src++;
  2399.             *dst++ = (srcpix0 >> 8) | (srcpix0 << 8);
  2400.             *dst++ = (srcpix1 >> 8) | (srcpix1 << 8);
  2401.         }
  2402.         if (xborderpix)
  2403.         {
  2404.             UINT16 srcpix1 = *--src;
  2405.             UINT16 srcpix0 = *--src;
  2406.             *dst++ = (srcpix1 >> 8) | (srcpix0 << 8);
  2407.             *dst++ = (srcpix1 >> 8) | (srcpix1 << 8);
  2408.         }
  2409.     }
  2410. }
  2411.  
  2412.  
  2413.  
  2414. //============================================================
  2415. //  copyline_yuy16_to_uyvy
  2416. //============================================================
  2417.  
  2418. INLINE void copyline_yuy16_to_uyvy(UINT16 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix)
  2419. {
  2420.     int x;
  2421.  
  2422.     assert(xborderpix == 0 || xborderpix == 2);
  2423.     assert(width % 2 == 0);
  2424.  
  2425.     // palette (really RGB map) case
  2426.     if (palette != NULL)
  2427.     {
  2428.         if (xborderpix)
  2429.         {
  2430.             UINT16 srcpix0 = *src++;
  2431.             UINT16 srcpix1 = *src--;
  2432.             *dst++ = palette[0x100 + (srcpix0 >> 8)] | (srcpix0 & 0xff);
  2433.             *dst++ = palette[0x100 + (srcpix0 >> 8)] | (srcpix1 & 0xff);
  2434.         }
  2435.         for (x = 0; x < width; x += 2)
  2436.         {
  2437.             UINT16 srcpix0 = *src++;
  2438.             UINT16 srcpix1 = *src++;
  2439.             *dst++ = palette[0x100 + (srcpix0 >> 8)] | (srcpix0 & 0xff);
  2440.             *dst++ = palette[0x100 + (srcpix1 >> 8)] | (srcpix1 & 0xff);
  2441.         }
  2442.         if (xborderpix)
  2443.         {
  2444.             UINT16 srcpix1 = *--src;
  2445.             UINT16 srcpix0 = *--src;
  2446.             *dst++ = palette[0x100 + (srcpix1 >> 8)] | (srcpix0 & 0xff);
  2447.             *dst++ = palette[0x100 + (srcpix1 >> 8)] | (srcpix1 & 0xff);
  2448.         }
  2449.     }
  2450.  
  2451.     // direct case
  2452.     else
  2453.     {
  2454.         if (xborderpix)
  2455.         {
  2456.             UINT16 srcpix0 = src[0];
  2457.             UINT16 srcpix1 = src[1];
  2458.             *dst++ = srcpix0;
  2459.             *dst++ = (srcpix0 & 0xff00) | (srcpix1 & 0x00ff);
  2460.         }
  2461.         for (x = 0; x < width; x += 2)
  2462.         {
  2463.             *dst++ = *src++;
  2464.             *dst++ = *src++;
  2465.         }
  2466.         if (xborderpix)
  2467.         {
  2468.             UINT16 srcpix1 = *--src;
  2469.             UINT16 srcpix0 = *--src;
  2470.             *dst++ = (srcpix1 & 0xff00) | (srcpix0 & 0x00ff);
  2471.             *dst++ = srcpix1;
  2472.         }
  2473.     }
  2474. }
  2475.  
  2476.  
  2477.  
  2478. //============================================================
  2479. //  copyline_yuy16_to_argb
  2480. //============================================================
  2481.  
  2482. INLINE void copyline_yuy16_to_argb(UINT32 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix)
  2483. {
  2484.     int x;
  2485.  
  2486.     assert(xborderpix == 0 || xborderpix == 2);
  2487.     assert(width % 2 == 0);
  2488.  
  2489.     // palette (really RGB map) case
  2490.     if (palette != NULL)
  2491.     {
  2492.         if (xborderpix)
  2493.         {
  2494.             UINT16 srcpix0 = src[0];
  2495.             UINT16 srcpix1 = src[1];
  2496.             UINT8 cb = srcpix0 & 0xff;
  2497.             UINT8 cr = srcpix1 & 0xff;
  2498.             *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr);
  2499.             *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr);
  2500.         }
  2501.         for (x = 0; x < width / 2; x++)
  2502.         {
  2503.             UINT16 srcpix0 = *src++;
  2504.             UINT16 srcpix1 = *src++;
  2505.             UINT8 cb = srcpix0 & 0xff;
  2506.             UINT8 cr = srcpix1 & 0xff;
  2507.             *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr);
  2508.             *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr);
  2509.         }
  2510.         if (xborderpix)
  2511.         {
  2512.             UINT16 srcpix1 = *--src;
  2513.             UINT16 srcpix0 = *--src;
  2514.             UINT8 cb = srcpix0 & 0xff;
  2515.             UINT8 cr = srcpix1 & 0xff;
  2516.             *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr);
  2517.             *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr);
  2518.         }
  2519.     }
  2520.  
  2521.     // direct case
  2522.     else
  2523.     {
  2524.         if (xborderpix)
  2525.         {
  2526.             UINT16 srcpix0 = src[0];
  2527.             UINT16 srcpix1 = src[1];
  2528.             UINT8 cb = srcpix0 & 0xff;
  2529.             UINT8 cr = srcpix1 & 0xff;
  2530.             *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr);
  2531.             *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr);
  2532.         }
  2533.         for (x = 0; x < width; x += 2)
  2534.         {
  2535.             UINT16 srcpix0 = *src++;
  2536.             UINT16 srcpix1 = *src++;
  2537.             UINT8 cb = srcpix0 & 0xff;
  2538.             UINT8 cr = srcpix1 & 0xff;
  2539.             *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr);
  2540.             *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr);
  2541.         }
  2542.         if (xborderpix)
  2543.         {
  2544.             UINT16 srcpix1 = *--src;
  2545.             UINT16 srcpix0 = *--src;
  2546.             UINT8 cb = srcpix0 & 0xff;
  2547.             UINT8 cr = srcpix1 & 0xff;
  2548.             *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr);
  2549.             *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr);
  2550.         }
  2551.     }
  2552. }
  2553.  
  2554.  
  2555.  
  2556. //============================================================
  2557. //  texture_set_data
  2558. //============================================================
  2559.  
  2560. void texture_info::set_data(const render_texinfo *texsource, UINT32 flags)
  2561. {
  2562.     D3DLOCKED_RECT rect;
  2563.     HRESULT result;
  2564.  
  2565.     // lock the texture
  2566.     switch (m_type)
  2567.     {
  2568.         default:
  2569.         case TEXTURE_TYPE_PLAIN:    result = (*d3dintf->texture.lock_rect)(m_d3dtex, 0, &rect, NULL, 0);                 break;
  2570.         case TEXTURE_TYPE_DYNAMIC:  result = (*d3dintf->texture.lock_rect)(m_d3dtex, 0, &rect, NULL, D3DLOCK_DISCARD);   break;
  2571.         case TEXTURE_TYPE_SURFACE:  result = (*d3dintf->surface.lock_rect)(m_d3dsurface, &rect, NULL, D3DLOCK_DISCARD);  break;
  2572.     }
  2573.     if (result != D3D_OK)
  2574.     {
  2575.         return;
  2576.     }
  2577.  
  2578.     // loop over Y
  2579.     int miny = 0 - m_yborderpix;
  2580.     int maxy = texsource->height + m_yborderpix;
  2581.     for (int dsty = miny; dsty < maxy; dsty++)
  2582.     {
  2583.         int srcy = (dsty < 0) ? 0 : (dsty >= texsource->height) ? texsource->height - 1 : dsty;
  2584.         void *dst = (BYTE *)rect.pBits + (dsty + m_yborderpix) * rect.Pitch;
  2585.  
  2586.         // switch off of the format and
  2587.         switch (PRIMFLAG_GET_TEXFORMAT(flags))
  2588.         {
  2589.             case TEXFORMAT_PALETTE16:
  2590.                 copyline_palette16((UINT32 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette(), m_xborderpix);
  2591.                 break;
  2592.  
  2593.             case TEXFORMAT_PALETTEA16:
  2594.                 copyline_palettea16((UINT32 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette(), m_xborderpix);
  2595.                 break;
  2596.  
  2597.             case TEXFORMAT_RGB32:
  2598.                 copyline_rgb32((UINT32 *)dst, (UINT32 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette(), m_xborderpix);
  2599.                 break;
  2600.  
  2601.             case TEXFORMAT_ARGB32:
  2602.                 copyline_argb32((UINT32 *)dst, (UINT32 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette(), m_xborderpix);
  2603.                 break;
  2604.  
  2605.             case TEXFORMAT_YUY16:
  2606.                 if (m_texture_manager->get_yuv_format() == D3DFMT_YUY2)
  2607.                     copyline_yuy16_to_yuy2((UINT16 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette(), m_xborderpix);
  2608.                 else if (m_texture_manager->get_yuv_format() == D3DFMT_UYVY)
  2609.                     copyline_yuy16_to_uyvy((UINT16 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette(), m_xborderpix);
  2610.                 else
  2611.                     copyline_yuy16_to_argb((UINT32 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette(), m_xborderpix);
  2612.                 break;
  2613.  
  2614.             default:
  2615.                 osd_printf_error("Unknown texture blendmode=%d format=%d\n", PRIMFLAG_GET_BLENDMODE(flags), PRIMFLAG_GET_TEXFORMAT(flags));
  2616.                 break;
  2617.         }
  2618.     }
  2619.  
  2620.     // unlock
  2621.     switch (m_type)
  2622.     {
  2623.         default:
  2624.         case TEXTURE_TYPE_PLAIN:    result = (*d3dintf->texture.unlock_rect)(m_d3dtex, 0);   break;
  2625.         case TEXTURE_TYPE_DYNAMIC:  result = (*d3dintf->texture.unlock_rect)(m_d3dtex, 0);   break;
  2626.         case TEXTURE_TYPE_SURFACE:  result = (*d3dintf->surface.unlock_rect)(m_d3dsurface);  break;
  2627.     }
  2628.     if (result != D3D_OK)
  2629.     {
  2630.         osd_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result);
  2631.     }
  2632.  
  2633.     // prescale
  2634.     prescale();
  2635. }
  2636.  
  2637.  
  2638.  
  2639. //============================================================
  2640. //  texture_info::prescale
  2641. //============================================================
  2642.  
  2643. void texture_info::prescale()
  2644. {
  2645.     surface *scale_surface;
  2646.     HRESULT result;
  2647.     int i;
  2648.  
  2649.     // if we don't need to, just skip it
  2650.     if (m_d3dtex == m_d3dfinaltex)
  2651.         return;
  2652.  
  2653.     // for all cases, we need to get the surface of the render target
  2654.     result = (*d3dintf->texture.get_surface_level)(m_d3dfinaltex, 0, &scale_surface);
  2655.     if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during texture get_surface_level call\n", (int)result);
  2656.  
  2657.     // if we have an offscreen plain surface, we can just StretchRect to it
  2658.     if (m_type == TEXTURE_TYPE_SURFACE)
  2659.     {
  2660.         assert(m_d3dsurface != NULL);
  2661.  
  2662.         // set the source bounds
  2663.         RECT source;
  2664.         source.left = source.top = 0;
  2665.         source.right = m_texinfo.width + 2 * m_xborderpix;
  2666.         source.bottom = m_texinfo.height + 2 * m_yborderpix;
  2667.  
  2668.         // set the target bounds
  2669.         RECT dest;
  2670.         dest = source;
  2671.         dest.right *= m_xprescale;
  2672.         dest.bottom *= m_yprescale;
  2673.  
  2674.         // do the stretchrect
  2675.         result = (*d3dintf->device.stretch_rect)(m_renderer->get_device(), m_d3dsurface, &source, scale_surface, &dest, D3DTEXF_POINT);
  2676.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device stretct_rect call\n", (int)result);
  2677.     }
  2678.  
  2679.     // if we are using a texture render target, we need to do more preparations
  2680.     else
  2681.     {
  2682.         surface *backbuffer;
  2683.  
  2684.         assert(m_d3dtex != NULL);
  2685.  
  2686.         // first remember the original render target and set the new one
  2687.         result = (*d3dintf->device.get_render_target)(m_renderer->get_device(), 0, &backbuffer);
  2688.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device get_render_target call\n", (int)result);
  2689.         result = (*d3dintf->device.set_render_target)(m_renderer->get_device(), 0, scale_surface);
  2690.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call 1\n", (int)result);
  2691.         m_renderer->reset_render_states();
  2692.  
  2693.         // start the scene
  2694.         result = (*d3dintf->device.begin_scene)(m_renderer->get_device());
  2695.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device begin_scene call\n", (int)result);
  2696.  
  2697.         // configure the rendering pipeline
  2698.         m_renderer->set_filter(FALSE);
  2699.         m_renderer->set_blendmode(BLENDMODE_NONE);
  2700.         result = (*d3dintf->device.set_texture)(m_renderer->get_device(), 0, m_d3dtex);
  2701.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture call\n", (int)result);
  2702.  
  2703.         // lock the vertex buffer
  2704.         result = (*d3dintf->vertexbuf.lock)(m_renderer->get_vertex_buffer(), 0, 0, m_renderer->get_locked_buffer_ptr(), D3DLOCK_DISCARD);
  2705.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during vertex buffer lock call\n", (int)result);
  2706.  
  2707.         // configure the X/Y coordinates on the target surface
  2708.         vertex *lockedbuf = m_renderer->get_locked_buffer();
  2709.         lockedbuf[0].x = -0.5f;
  2710.         lockedbuf[0].y = -0.5f;
  2711.         lockedbuf[1].x = (float)((m_texinfo.width + 2 * m_xborderpix) * m_xprescale) - 0.5f;
  2712.         lockedbuf[1].y = -0.5f;
  2713.         lockedbuf[2].x = -0.5f;
  2714.         lockedbuf[2].y = (float)((m_texinfo.height + 2 * m_yborderpix) * m_yprescale) - 0.5f;
  2715.         lockedbuf[3].x = (float)((m_texinfo.width + 2 * m_xborderpix) * m_xprescale) - 0.5f;
  2716.         lockedbuf[3].y = (float)((m_texinfo.height + 2 * m_yborderpix) * m_yprescale) - 0.5f;
  2717.  
  2718.         // configure the U/V coordintes on the source texture
  2719.         lockedbuf[0].u0 = 0.0f;
  2720.         lockedbuf[0].v0 = 0.0f;
  2721.         lockedbuf[1].u0 = (float)(m_texinfo.width + 2 * m_xborderpix) / (float)m_rawdims.c.x;
  2722.         lockedbuf[1].v0 = 0.0f;
  2723.         lockedbuf[2].u0 = 0.0f;
  2724.         lockedbuf[2].v0 = (float)(m_texinfo.height + 2 * m_yborderpix) / (float)m_rawdims.c.y;
  2725.         lockedbuf[3].u0 = (float)(m_texinfo.width + 2 * m_xborderpix) / (float)m_rawdims.c.x;
  2726.         lockedbuf[3].v0 = (float)(m_texinfo.height + 2 * m_yborderpix) / (float)m_rawdims.c.y;
  2727.  
  2728.         // reset the remaining vertex parameters
  2729.         for (i = 0; i < 4; i++)
  2730.         {
  2731.             lockedbuf[i].z = 0.0f;
  2732.             lockedbuf[i].rhw = 1.0f;
  2733.             lockedbuf[i].color = D3DCOLOR_ARGB(0xff,0xff,0xff,0xff);
  2734.         }
  2735.  
  2736.         // unlock the vertex buffer
  2737.         result = (*d3dintf->vertexbuf.unlock)(m_renderer->get_vertex_buffer());
  2738.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during vertex buffer unlock call\n", (int)result);
  2739.         m_renderer->set_locked_buffer(NULL);
  2740.  
  2741.         // set the stream and draw the triangle strip
  2742.         result = (*d3dintf->device.set_stream_source)(m_renderer->get_device(), 0, m_renderer->get_vertex_buffer(), sizeof(vertex));
  2743.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_stream_source call\n", (int)result);
  2744.         result = (*d3dintf->device.draw_primitive)(m_renderer->get_device(), D3DPT_TRIANGLESTRIP, 0, 2);
  2745.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result);
  2746.  
  2747.         // end the scene
  2748.         result = (*d3dintf->device.end_scene)(m_renderer->get_device());
  2749.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device end_scene call\n", (int)result);
  2750.  
  2751.         // reset the render target and release our reference to the backbuffer
  2752.         result = (*d3dintf->device.set_render_target)(m_renderer->get_device(), 0, backbuffer);
  2753.         if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call 2\n", (int)result);
  2754.         (*d3dintf->surface.release)(backbuffer);
  2755.         m_renderer->reset_render_states();
  2756.     }
  2757.  
  2758.     // release our reference to the target surface
  2759.     (*d3dintf->surface.release)(scale_surface);
  2760. }
  2761.  
  2762.  
  2763. //============================================================
  2764. //  cache_target::~cache_target
  2765. //============================================================
  2766.  
  2767. cache_target::~cache_target()
  2768. {
  2769.     for (int index = 0; index < 11; index++)
  2770.     {
  2771.         if (bloom_texture[index] != NULL)
  2772.         {
  2773.             (*d3dintf->texture.release)(bloom_texture[index]);
  2774.             bloom_texture[index] = NULL;
  2775.         }
  2776.         if (bloom_target[index] != NULL)
  2777.         {
  2778.             (*d3dintf->surface.release)(bloom_target[index]);
  2779.             bloom_target[index] = NULL;
  2780.         }
  2781.     }
  2782.  
  2783.     if (last_texture != NULL)
  2784.     {
  2785.         (*d3dintf->texture.release)(last_texture);
  2786.         last_texture = NULL;
  2787.     }
  2788.     if (last_target != NULL)
  2789.     {
  2790.         (*d3dintf->surface.release)(last_target);
  2791.         last_target = NULL;
  2792.     }
  2793. }
  2794.  
  2795.  
  2796. //============================================================
  2797. //  cache_target::init - initializes a target cache
  2798. //============================================================
  2799.  
  2800. bool cache_target::init(renderer *d3d, base *d3dintf, int width, int height, int prescale_x, int prescale_y)
  2801. {
  2802.     int bloom_size = (width < height) ? width : height;
  2803.     int bloom_index = 0;
  2804.     int bloom_width = width;
  2805.     int bloom_height = height;
  2806.     for (; bloom_size >= 2 && bloom_index < 11; bloom_size >>= 1)
  2807.     {
  2808.         bloom_width >>= 1;
  2809.         bloom_height >>= 1;
  2810.         HRESULT result = (*d3dintf->device.create_texture)(d3d->get_device(), bloom_width, bloom_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bloom_texture[bloom_index]);
  2811.         if (result != D3D_OK)
  2812.         {
  2813.             return false;
  2814.         }
  2815.         (*d3dintf->texture.get_surface_level)(bloom_texture[bloom_index], 0, &bloom_target[bloom_index]);
  2816.         bloom_index++;
  2817.     }
  2818.  
  2819.     HRESULT result = (*d3dintf->device.create_texture)(d3d->get_device(), width * prescale_x, height * prescale_y, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &last_texture);
  2820.     if (result != D3D_OK)
  2821.         return false;
  2822.     (*d3dintf->texture.get_surface_level)(last_texture, 0, &last_target);
  2823.  
  2824.     target_width = width * prescale_x;
  2825.     target_height = height * prescale_y;
  2826.  
  2827.     return true;
  2828. }
  2829.  
  2830. //============================================================
  2831. //  render_target::~render_target
  2832. //============================================================
  2833.  
  2834. render_target::~render_target()
  2835. {
  2836.     for (int index = 0; index < 11; index++)
  2837.     {
  2838.         if (bloom_texture[index] != NULL)
  2839.         {
  2840.             (*d3dintf->texture.release)(bloom_texture[index]);
  2841.             bloom_texture[index] = NULL;
  2842.         }
  2843.         if (bloom_target[index] != NULL)
  2844.         {
  2845.             (*d3dintf->surface.release)(bloom_target[index]);
  2846.             bloom_target[index] = NULL;
  2847.         }
  2848.     }
  2849.  
  2850.     for (int index = 0; index < 5; index++)
  2851.     {
  2852.         if (render_texture[index] != NULL)
  2853.         {
  2854.             (*d3dintf->texture.release)(render_texture[index]);
  2855.             render_texture[index] = NULL;
  2856.         }
  2857.         if (target[index] != NULL)
  2858.         {
  2859.             (*d3dintf->surface.release)(target[index]);
  2860.             target[index] = NULL;
  2861.         }
  2862.     }
  2863.  
  2864.     if (prescaletexture != NULL)
  2865.     {
  2866.         (*d3dintf->texture.release)(prescaletexture);
  2867.         prescaletexture = NULL;
  2868.     }
  2869.     if (prescaletarget != NULL)
  2870.     {
  2871.         (*d3dintf->surface.release)(prescaletarget);
  2872.         prescaletarget = NULL;
  2873.     }
  2874.  
  2875.     if (smalltexture != NULL)
  2876.     {
  2877.         (*d3dintf->texture.release)(smalltexture);
  2878.         smalltexture = NULL;
  2879.     }
  2880.     if (smalltarget != NULL)
  2881.     {
  2882.         (*d3dintf->surface.release)(smalltarget);
  2883.         smalltarget = NULL;
  2884.     }
  2885. }
  2886.  
  2887.  
  2888. //============================================================
  2889. //  render_target::init - initializes a render target
  2890. //============================================================
  2891.  
  2892. bool render_target::init(renderer *d3d, base *d3dintf, int width, int height, int prescale_x, int prescale_y)
  2893. {
  2894.     D3DFORMAT format = D3DFMT_A8R8G8B8;
  2895.  
  2896.     HRESULT result = (*d3dintf->device.create_texture)(d3d->get_device(), width * prescale_x, height * prescale_y, 1, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &render_texture[0]);
  2897.     if (result != D3D_OK)
  2898.         return false;
  2899.     (*d3dintf->texture.get_surface_level)(render_texture[0], 0, &target[0]);
  2900.  
  2901.     result = (*d3dintf->device.create_texture)(d3d->get_device(), width * prescale_x, height * prescale_y, 1, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &render_texture[1]);
  2902.     if (result != D3D_OK)
  2903.         return false;
  2904.     (*d3dintf->texture.get_surface_level)(render_texture[1], 0, &target[1]);
  2905.  
  2906.     result = (*d3dintf->device.create_texture)(d3d->get_device(), width * prescale_x, height * prescale_y, 1, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &render_texture[2]);
  2907.     if (result != D3D_OK)
  2908.         return false;
  2909.     (*d3dintf->texture.get_surface_level)(render_texture[2], 0, &target[2]);
  2910.  
  2911.     result = (*d3dintf->device.create_texture)(d3d->get_device(), width, height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &render_texture[3]);
  2912.     if (result != D3D_OK)
  2913.         return false;
  2914.     (*d3dintf->texture.get_surface_level)(render_texture[3], 0, &target[3]);
  2915.  
  2916.     result = (*d3dintf->device.create_texture)(d3d->get_device(), width, height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &render_texture[4]);
  2917.     if (result != D3D_OK)
  2918.         return false;
  2919.     (*d3dintf->texture.get_surface_level)(render_texture[4], 0, &target[4]);
  2920.  
  2921.     result = (*d3dintf->device.create_texture)(d3d->get_device(), width, height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &smalltexture);
  2922.     if (result != D3D_OK)
  2923.         return false;
  2924.     (*d3dintf->texture.get_surface_level)(smalltexture, 0, &smalltarget);
  2925.  
  2926.     result = (*d3dintf->device.create_texture)(d3d->get_device(), width * prescale_x, height * prescale_y, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &prescaletexture);
  2927.     if (result != D3D_OK)
  2928.         return false;
  2929.     (*d3dintf->texture.get_surface_level)(prescaletexture, 0, &prescaletarget);
  2930.  
  2931.     float bloom_size = (d3d->get_width() < d3d->get_height()) ? d3d->get_width() : d3d->get_height();
  2932.     int bloom_index = 0;
  2933.     float bloom_width = d3d->get_width();
  2934.     float bloom_height = d3d->get_height();
  2935.     for (; bloom_size >= 2.0f && bloom_index < 11; bloom_size *= 0.5f)
  2936.     {
  2937.         bloom_width *= 0.5f;
  2938.         bloom_height *= 0.5f;
  2939.         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]);
  2940.         if (result != D3D_OK)
  2941.             return false;
  2942.         (*d3dintf->texture.get_surface_level)(bloom_texture[bloom_index], 0, &bloom_target[bloom_index]);
  2943.         bloom_index++;
  2944.     }
  2945.  
  2946.     this->width = width;
  2947.     this->height = height;
  2948.  
  2949.     target_width = width * prescale_x;
  2950.     target_height = height * prescale_y;
  2951.  
  2952.     return true;
  2953. }
  2954.  
  2955. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement