SHARE
TWEET

ddrawd3d.c - Koopah's D3D Patch/Vivosku .162 edit

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