diff options
Diffstat (limited to 'src/osd/modules/render/drawdd.cpp')
-rw-r--r-- | src/osd/modules/render/drawdd.cpp | 1317 |
1 files changed, 0 insertions, 1317 deletions
diff --git a/src/osd/modules/render/drawdd.cpp b/src/osd/modules/render/drawdd.cpp deleted file mode 100644 index fb82dff3c1f..00000000000 --- a/src/osd/modules/render/drawdd.cpp +++ /dev/null @@ -1,1317 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -//============================================================ -// -// drawdd.c - Win32 DirectDraw implementation -// -//============================================================ - -// standard windows headers -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <mmsystem.h> -#include <ddraw.h> -#undef interface - -// MAME headers -#include "emu.h" -#include "render.h" -#include "rendutil.h" -#include "rendersw.inc" - -// MAMEOS headers -#include "winmain.h" -#include "window.h" - - - -//============================================================ -// TYPE DEFINITIONS -//============================================================ - -typedef HRESULT (WINAPI *directdrawcreateex_ptr)(GUID FAR *lpGuid, LPVOID *lplpDD, REFIID iid, IUnknown FAR *pUnkOuter); -typedef HRESULT (WINAPI *directdrawenumerateex_ptr)(LPDDENUMCALLBACKEXA lpCallback, LPVOID lpContext, DWORD dwFlags); - - -/* dd_info is the information about DirectDraw for the current screen */ -class renderer_dd : public osd_renderer -{ -public: - renderer_dd(osd_window *window) - : osd_renderer(window, FLAG_NONE), - width(0), - height(0), - refresh(0), - //adapter(0), - adapter_ptr(NULL), - clearouter(0), - blitwidth(0), blitheight(0), - //lastdest - ddraw(NULL), - primary(NULL), - back(NULL), - blit(NULL), - clipper(NULL), - gamma(NULL), - //DDSURFACEDESC2 primarydesc; - //DDSURFACEDESC2 blitdesc; - //DDSURFACEDESC2 origmode; - //ddcaps(0), - //helcaps(0), - membuffer(NULL), - membuffersize(0) - { } - - virtual ~renderer_dd() { } - - virtual int create() override; - virtual render_primitive_list *get_primitives() override; - virtual int draw(const int update) override; - virtual void save() override {}; - virtual void record() override {}; - virtual void toggle_fsfx() override {}; - virtual void destroy() override; - - int width, height; // current width, height - int refresh; // current refresh rate - -private: - - inline void update_outer_rects(); - - // surface management - int ddraw_create(); - int ddraw_create_surfaces(); - void ddraw_delete(); - void ddraw_delete_surfaces(); - int ddraw_verify_caps(); - int ddraw_test_cooperative(); - HRESULT create_surface(DDSURFACEDESC2 *desc, IDirectDrawSurface7 **surface, const char *type); - int create_clipper(); - - // drawing helpers - void compute_blit_surface_size(); - void blit_to_primary(int srcwidth, int srcheight); - - // video modes - int config_adapter_mode(); - void get_adapter_for_monitor(osd_monitor_info *monitor); - void pick_best_mode(); - - // various - void calc_fullscreen_margins(DWORD desc_width, DWORD desc_height, RECT *margins); - - - GUID adapter; // current display adapter - GUID * adapter_ptr; // pointer to current display adapter - int clearouter; // clear the outer areas? - - INT32 blitwidth, blitheight; // current blit width/height values - RECT lastdest; // last destination rectangle - - IDirectDraw7 * ddraw; // pointer to the DirectDraw object - IDirectDrawSurface7 * primary; // pointer to the primary surface object - IDirectDrawSurface7 * back; // pointer to the back buffer surface object - IDirectDrawSurface7 * blit; // pointer to the blit surface object - IDirectDrawClipper * clipper; // pointer to the clipper object - IDirectDrawGammaControl *gamma; // pointer to the gamma control object - - DDSURFACEDESC2 primarydesc; // description of the primary surface - DDSURFACEDESC2 blitdesc; // description of the blitting surface - DDSURFACEDESC2 origmode; // original video mode - - DDCAPS ddcaps; // capabilities of the device - DDCAPS helcaps; // capabilities of the hardware - - UINT8 * membuffer; // memory buffer for complex rendering - UINT32 membuffersize; // current size of the memory buffer -}; - - -/* monitor_enum_info holds information during a monitor enumeration */ -struct monitor_enum_info -{ - osd_monitor_info * monitor; // pointer to monitor we want - GUID guid; // GUID of the one we found - GUID * guid_ptr; // pointer to our GUID - int foundit; // TRUE if we found what we wanted -}; - - -/* mode_enum_info holds information during a display mode enumeration */ -struct mode_enum_info -{ - renderer_dd * renderer; - osd_window * window; - INT32 minimum_width, minimum_height; - INT32 target_width, target_height; - double target_refresh; - float best_score; -}; - - - -//============================================================ -// GLOBALS -//============================================================ - -static HINSTANCE dllhandle; -static directdrawcreateex_ptr directdrawcreateex; -static directdrawenumerateex_ptr directdrawenumerateex; - - - -//============================================================ -// INLINES -//============================================================ - -inline void renderer_dd::update_outer_rects() -{ - clearouter = (back != NULL) ? 3 : 1; -} - - -static inline int better_mode(int width0, int height0, int width1, int height1, float desired_aspect) -{ - float aspect0 = (float)width0 / (float)height0; - float aspect1 = (float)width1 / (float)height1; - return (fabs(desired_aspect - aspect0) < fabs(desired_aspect - aspect1)) ? 0 : 1; -} - - - -//============================================================ -// PROTOTYPES -//============================================================ - -// core functions -static void drawdd_exit(void); - - - -//============================================================ -// drawnone_create -//============================================================ - -static osd_renderer *drawdd_create(osd_window *window) -{ - return global_alloc(renderer_dd(window)); -} - - -//============================================================ -// drawdd_init -//============================================================ - -int drawdd_init(running_machine &machine, osd_draw_callbacks *callbacks) -{ - // dynamically grab the create function from ddraw.dll - dllhandle = LoadLibrary(TEXT("ddraw.dll")); - if (dllhandle == NULL) - { - osd_printf_verbose("DirectDraw: Unable to access ddraw.dll\n"); - return 1; - } - - // import the create function - directdrawcreateex = (directdrawcreateex_ptr)GetProcAddress(dllhandle, "DirectDrawCreateEx"); - if (directdrawcreateex == NULL) - { - osd_printf_verbose("DirectDraw: Unable to find DirectDrawCreateEx\n"); - FreeLibrary(dllhandle); - dllhandle = NULL; - return 1; - } - - // import the enumerate function - directdrawenumerateex = (directdrawenumerateex_ptr)GetProcAddress(dllhandle, "DirectDrawEnumerateExA"); - if (directdrawenumerateex == NULL) - { - osd_printf_verbose("DirectDraw: Unable to find DirectDrawEnumerateExA\n"); - FreeLibrary(dllhandle); - dllhandle = NULL; - return 1; - } - - // fill in the callbacks - memset(callbacks, 0, sizeof(*callbacks)); - callbacks->exit = drawdd_exit; - callbacks->create = drawdd_create; - - osd_printf_verbose("DirectDraw: Using DirectDraw 7\n"); - return 0; -} - - - -//============================================================ -// drawdd_exit -//============================================================ - -static void drawdd_exit(void) -{ - if (dllhandle != NULL) - FreeLibrary(dllhandle); -} - - - -//============================================================ -// drawdd_window_init -//============================================================ - -int renderer_dd::create() -{ - // configure the adapter for the mode we want - if (config_adapter_mode()) - { - osd_printf_error("Unable to configure adapter.\n"); - goto error; - } - - // create the ddraw object - if (ddraw_create()) - { - osd_printf_error("Unable to create ddraw object.\n"); - goto error; - } - - return 0; - -error: - destroy(); - osd_printf_error("Unable to initialize DirectDraw.\n"); - return 1; -} - - - -//============================================================ -// drawdd_window_destroy -//============================================================ - -void renderer_dd::destroy() -{ - // delete the ddraw object - ddraw_delete(); -} - - - -//============================================================ -// drawdd_window_get_primitives -//============================================================ - -render_primitive_list *renderer_dd::get_primitives() -{ - compute_blit_surface_size(); - window().target()->set_bounds(blitwidth, blitheight, 0); - window().target()->set_max_update_rate((refresh == 0) ? origmode.dwRefreshRate : refresh); - - return &window().target()->get_primitives(); -} - - - -//============================================================ -// drawdd_window_draw -//============================================================ - -int renderer_dd::draw(const int update) -{ - render_primitive *prim; - int usemembuffer = FALSE; - HRESULT result; - - // if we're updating, remember to erase the outer stuff - if (update) - update_outer_rects(); - - // if we have a ddraw object, check the cooperative level - if (ddraw_test_cooperative()) - return 1; - - // get the size; if we're too small, delete the existing surfaces - if (blitwidth > blitdesc.dwWidth || blitheight > blitdesc.dwHeight) - ddraw_delete_surfaces(); - - // if we need to create surfaces, do it now - if (blit == NULL && ddraw_create_surfaces() != 0) - return 1; - - // select our surface and lock it - result = IDirectDrawSurface7_Lock(blit, NULL, &blitdesc, DDLOCK_WAIT, NULL); - if (result == DDERR_SURFACELOST) - { - osd_printf_verbose("DirectDraw: Lost surfaces; deleting and retrying next frame\n"); - ddraw_delete_surfaces(); - return 1; - } - if (result != DD_OK) - { - osd_printf_verbose("DirectDraw: Error %08X locking blit surface\n", (int)result); - return 1; - } - - // render to it - window().m_primlist->acquire_lock(); - - // scan the list of primitives for tricky stuff - for (prim = window().m_primlist->first(); prim != NULL; prim = prim->next()) - if (PRIMFLAG_GET_BLENDMODE(prim->flags) != BLENDMODE_NONE || - (prim->texture.base != NULL && PRIMFLAG_GET_TEXFORMAT(prim->flags) == TEXFORMAT_ARGB32)) - { - usemembuffer = TRUE; - break; - } - - // if we're using the memory buffer, draw offscreen first and then copy - if (usemembuffer) - { - int x, y; - - // based on the target format, use one of our standard renderers - switch (blitdesc.ddpfPixelFormat.dwRBitMask) - { - case 0x00ff0000: software_renderer<UINT32, 0,0,0, 16,8,0>::draw_primitives(*window().m_primlist, membuffer, blitwidth, blitheight, blitwidth); break; - case 0x000000ff: software_renderer<UINT32, 0,0,0, 0,8,16>::draw_primitives(*window().m_primlist, membuffer, blitwidth, blitheight, blitwidth); break; - case 0xf800: software_renderer<UINT16, 3,2,3, 11,5,0>::draw_primitives(*window().m_primlist, membuffer, blitwidth, blitheight, blitwidth); break; - case 0x7c00: software_renderer<UINT16, 3,3,3, 10,5,0>::draw_primitives(*window().m_primlist, membuffer, blitwidth, blitheight, blitwidth); break; - default: - osd_printf_verbose("DirectDraw: Unknown target mode: R=%08X G=%08X B=%08X\n", (int)blitdesc.ddpfPixelFormat.dwRBitMask, (int)blitdesc.ddpfPixelFormat.dwGBitMask, (int)blitdesc.ddpfPixelFormat.dwBBitMask); - break; - } - - // handle copying to both 16bpp and 32bpp destinations - for (y = 0; y < blitheight; y++) - { - if (blitdesc.ddpfPixelFormat.dwRGBBitCount == 32) - { - UINT32 *src = (UINT32 *)membuffer + y * blitwidth; - UINT32 *dst = (UINT32 *)((UINT8 *)blitdesc.lpSurface + y * blitdesc.lPitch); - for (x = 0; x < blitwidth; x++) - *dst++ = *src++; - } - else if (blitdesc.ddpfPixelFormat.dwRGBBitCount == 16) - { - UINT16 *src = (UINT16 *)membuffer + y * blitwidth; - UINT16 *dst = (UINT16 *)((UINT8 *)blitdesc.lpSurface + y * blitdesc.lPitch); - for (x = 0; x < blitwidth; x++) - *dst++ = *src++; - } - } - - } - - // otherwise, draw directly - else - { - // based on the target format, use one of our standard renderers - switch (blitdesc.ddpfPixelFormat.dwRBitMask) - { - case 0x00ff0000: software_renderer<UINT32, 0,0,0, 16,8,0, true>::draw_primitives(*window().m_primlist, blitdesc.lpSurface, blitwidth, blitheight, blitdesc.lPitch / 4); break; - case 0x000000ff: software_renderer<UINT32, 0,0,0, 0,8,16, true>::draw_primitives(*window().m_primlist, blitdesc.lpSurface, blitwidth, blitheight, blitdesc.lPitch / 4); break; - case 0xf800: software_renderer<UINT16, 3,2,3, 11,5,0, true>::draw_primitives(*window().m_primlist, blitdesc.lpSurface, blitwidth, blitheight, blitdesc.lPitch / 2); break; - case 0x7c00: software_renderer<UINT16, 3,3,3, 10,5,0, true>::draw_primitives(*window().m_primlist, blitdesc.lpSurface, blitwidth, blitheight, blitdesc.lPitch / 2); break; - default: - osd_printf_verbose("DirectDraw: Unknown target mode: R=%08X G=%08X B=%08X\n", (int)blitdesc.ddpfPixelFormat.dwRBitMask, (int)blitdesc.ddpfPixelFormat.dwGBitMask, (int)blitdesc.ddpfPixelFormat.dwBBitMask); - break; - } - } - window().m_primlist->release_lock(); - - // unlock and blit - result = IDirectDrawSurface7_Unlock(blit, NULL); - if (result != DD_OK) osd_printf_verbose("DirectDraw: Error %08X unlocking blit surface\n", (int)result); - - // sync to VBLANK - if ((video_config.waitvsync || video_config.syncrefresh) && window().machine().video().throttled() && (!window().fullscreen() || back == NULL)) - { - result = IDirectDraw7_WaitForVerticalBlank(ddraw, DDWAITVB_BLOCKBEGIN, NULL); - if (result != DD_OK) osd_printf_verbose("DirectDraw: Error %08X waiting for VBLANK\n", (int)result); - } - - // complete the blitting - blit_to_primary(blitwidth, blitheight); - return 0; -} - - - -//============================================================ -// ddraw_create -//============================================================ - -int renderer_dd::ddraw_create() -{ - HRESULT result; - int verify; - - // if a device exists, free it - if (ddraw != NULL) - ddraw_delete(); - - // create the DirectDraw object - result = (*directdrawcreateex)(adapter_ptr, (LPVOID *)&ddraw, WRAP_REFIID(IID_IDirectDraw7), NULL); - if (result != DD_OK) - { - osd_printf_verbose("DirectDraw: Error %08X during DirectDrawCreateEx call\n", (int)result); - goto error; - } - - // verify the caps - verify = ddraw_verify_caps(); - if (verify == 2) - { - osd_printf_error("DirectDraw: Error - Device does not meet minimum requirements for DirectDraw rendering\n"); - goto error; - } - if (verify == 1) - osd_printf_verbose("DirectDraw: Warning - Device may not perform well for DirectDraw rendering\n"); - - // set the cooperative level - // for non-window modes, we will use full screen here - result = IDirectDraw7_SetCooperativeLevel(ddraw, win_window_list->m_hwnd, DDSCL_SETFOCUSWINDOW); - if (result != DD_OK) - { - osd_printf_verbose("DirectDraw: Error %08X during IDirectDraw7_SetCooperativeLevel(FOCUSWINDOW) call\n", (int)result); - goto error; - } - result = IDirectDraw7_SetCooperativeLevel(ddraw, window().m_hwnd, DDSCL_SETDEVICEWINDOW | (window().fullscreen() ? DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE : DDSCL_NORMAL)); - if (result != DD_OK) - { - osd_printf_verbose("DirectDraw: Error %08X during IDirectDraw7_SetCooperativeLevel(DEVICEWINDOW) call\n", (int)result); - goto error; - } - - // full screen mode: set the resolution - if (window().fullscreen() && video_config.switchres) - { - result = IDirectDraw7_SetDisplayMode(ddraw, width, height, 32, refresh, 0); - if (result != DD_OK) - { - osd_printf_verbose("DirectDraw: Error %08X attempting to set video mode %dx%d@%d call\n", (int)result, width, height, refresh); - goto error; - } - } - - return ddraw_create_surfaces(); - -error: - ddraw_delete(); - return 1; -} - - - -//============================================================ -// ddraw_create_surfaces -//============================================================ - -int renderer_dd::ddraw_create_surfaces() -{ - HRESULT result; - - // make a description of the primary surface - memset(&primarydesc, 0, sizeof(primarydesc)); - primarydesc.dwSize = sizeof(primarydesc); - primarydesc.dwFlags = DDSD_CAPS; - primarydesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - - // for triple-buffered full screen mode, allocate flipping surfaces - if (window().fullscreen() && video_config.triplebuf) - { - primarydesc.dwFlags |= DDSD_BACKBUFFERCOUNT; - primarydesc.ddsCaps.dwCaps |= DDSCAPS_FLIP | DDSCAPS_COMPLEX; - primarydesc.dwBackBufferCount = 2; - } - - // create the primary surface and report errors - result = create_surface(&primarydesc, &primary, "primary"); - if (result != DD_OK) goto error; - - // full screen mode: get the back surface - back = NULL; - if (window().fullscreen() && video_config.triplebuf) - { - DDSCAPS2 caps = { DDSCAPS_BACKBUFFER }; - result = IDirectDrawSurface7_GetAttachedSurface(primary, &caps, &back); - if (result != DD_OK) - { - osd_printf_verbose("DirectDraw: Error %08X getting attached back surface\n", (int)result); - goto error; - } - } - - // now make a description of our blit surface, based on the primary surface - if (blitwidth == 0 || blitheight == 0) - compute_blit_surface_size(); - blitdesc = primarydesc; - blitdesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS; - blitdesc.dwWidth = blitwidth; - blitdesc.dwHeight = blitheight; - blitdesc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY; - - // then create the blit surface, fall back to system memory if video mem doesn't work - result = create_surface(&blitdesc, &blit, "blit"); - if (result != DD_OK) - { - blitdesc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY; - result = create_surface(&blitdesc, &blit, "blit"); - } - if (result != DD_OK) goto error; - - // create a memory buffer for offscreen drawing - if (membuffersize < blitwidth * blitheight * 4) - { - membuffersize = blitwidth * blitheight * 4; - global_free_array(membuffer); - membuffer = global_alloc_array(UINT8, membuffersize); - } - if (membuffer == NULL) - goto error; - - // create a clipper for windowed mode - if (!window().fullscreen() && create_clipper()) - goto error; - - // full screen mode: set the gamma - if (window().fullscreen()) - { - // only set the gamma if it's not 1.0f - windows_options &options = downcast<windows_options &>(window().machine().options()); - float brightness = options.full_screen_brightness(); - float contrast = options.full_screen_contrast(); - float fgamma = options.full_screen_gamma(); - if (brightness != 1.0f || contrast != 1.0f || fgamma != 1.0f) - { - // see if we can get a GammaControl object - result = IDirectDrawSurface_QueryInterface(primary, WRAP_REFIID(IID_IDirectDrawGammaControl), (void **)&gamma); - if (result != DD_OK) - { - osd_printf_warning("DirectDraw: Warning - device does not support full screen gamma correction.\n"); - this->gamma = NULL; - } - - // proceed if we can - if (this->gamma != NULL) - { - DDGAMMARAMP ramp; - int i; - - // create a standard ramp and set it - for (i = 0; i < 256; i++) - ramp.red[i] = ramp.green[i] = ramp.blue[i] = apply_brightness_contrast_gamma(i, brightness, contrast, fgamma) << 8; - - // attempt to set it - result = IDirectDrawGammaControl_SetGammaRamp(this->gamma, 0, &ramp); - if (result != DD_OK) - osd_printf_verbose("DirectDraw: Error %08X attempting to set gamma correction.\n", (int)result); - } - } - } - - // force some updates - update_outer_rects(); - return 0; - -error: - ddraw_delete_surfaces(); - return 1; -} - - - -//============================================================ -// ddraw_delete -//============================================================ - -void renderer_dd::ddraw_delete() -{ - // free surfaces - ddraw_delete_surfaces(); - - // restore resolutions - if (ddraw != NULL) - IDirectDraw7_RestoreDisplayMode(ddraw); - - // reset cooperative level - if (ddraw != NULL && window().m_hwnd != NULL) - IDirectDraw7_SetCooperativeLevel(ddraw, window().m_hwnd, DDSCL_NORMAL); - - // release the DirectDraw object itself - if (ddraw != NULL) - IDirectDraw7_Release(ddraw); - ddraw = NULL; -} - - - -//============================================================ -// ddraw_delete_surfaces -//============================================================ - -void renderer_dd::ddraw_delete_surfaces() -{ - // release the gamma control - if (gamma != NULL) - IDirectDrawGammaControl_Release(gamma); - gamma = NULL; - - // release the clipper - if (clipper != NULL) - IDirectDrawClipper_Release(clipper); - clipper = NULL; - - // free the memory buffer - global_free_array(membuffer); - membuffer = NULL; - membuffersize = 0; - - // release the blit surface - if (blit != NULL) - IDirectDrawSurface7_Release(blit); - blit = NULL; - - // release the back surface - if (back != NULL) - IDirectDrawSurface7_Release(back); - back = NULL; - - // release the primary surface - if (primary != NULL) - IDirectDrawSurface7_Release(primary); - primary = NULL; -} - - - -//============================================================ -// ddraw_verify_caps -//============================================================ - -int renderer_dd::ddraw_verify_caps() -{ - int retval = 0; - HRESULT result; - - // get the capabilities - ddcaps.dwSize = sizeof(ddcaps); - helcaps.dwSize = sizeof(helcaps); - result = IDirectDraw7_GetCaps(ddraw, &ddcaps, &helcaps); - if (result != DD_OK) - { - osd_printf_verbose("DirectDraw: Error %08X during IDirectDraw7_GetCaps call\n", (int)result); - return 1; - } - - // determine if hardware stretching is available - if ((ddcaps.dwCaps & DDCAPS_BLTSTRETCH) == 0) - { - osd_printf_verbose("DirectDraw: Warning - Device does not support hardware stretching\n"); - retval = 1; - } - - return retval; -} - - - -//============================================================ -// ddraw_test_cooperative -//============================================================ - -int renderer_dd::ddraw_test_cooperative() -{ - HRESULT result; - - // check our current status; if we lost the device, punt to GDI - result = IDirectDraw7_TestCooperativeLevel(ddraw); - switch (result) - { - // punt to GDI if someone else has exclusive mode - case DDERR_NOEXCLUSIVEMODE: - case DDERR_EXCLUSIVEMODEALREADYSET: - ddraw_delete_surfaces(); - return 1; - - // if we're ok, but we don't have a primary surface, create one - default: - case DD_OK: - if (primary == NULL) - return ddraw_create_surfaces(); - return 0; - } -} - - - -//============================================================ -// create_surface -//============================================================ - -HRESULT renderer_dd::create_surface(DDSURFACEDESC2 *desc, IDirectDrawSurface7 **surface, const char *type) -{ - HRESULT result; - - // create the surface as requested - result = IDirectDraw7_CreateSurface(ddraw, desc, surface, NULL); - if (result != DD_OK) - { - osd_printf_verbose("DirectDraw: Error %08X creating %s surface\n", (int)result, type); - return result; - } - - // get a description of the primary surface - result = IDirectDrawSurface7_GetSurfaceDesc(*surface, desc); - if (result != DD_OK) - { - osd_printf_verbose("DirectDraw: Error %08X getting %s surface desciption\n", (int)result, type); - IDirectDrawSurface7_Release(*surface); - *surface = NULL; - return result; - } - - // print out the good stuff - osd_printf_verbose("DirectDraw: %s surface created: %dx%dx%d (R=%08X G=%08X B=%08X)\n", - type, - (int)desc->dwWidth, - (int)desc->dwHeight, - (int)desc->ddpfPixelFormat.dwRGBBitCount, - (UINT32)desc->ddpfPixelFormat.dwRBitMask, - (UINT32)desc->ddpfPixelFormat.dwGBitMask, - (UINT32)desc->ddpfPixelFormat.dwBBitMask); - return result; -} - - - -//============================================================ -// create_clipper -//============================================================ - -int renderer_dd::create_clipper() -{ - HRESULT result; - - // create a clipper for the primary surface - result = IDirectDraw7_CreateClipper(ddraw, 0, &clipper, NULL); - if (result != DD_OK) - { - osd_printf_verbose("DirectDraw: Error %08X creating clipper\n", (int)result); - return 1; - } - - // set the clipper's hwnd - result = IDirectDrawClipper_SetHWnd(clipper, 0, window().m_hwnd); - if (result != DD_OK) - { - osd_printf_verbose("DirectDraw: Error %08X setting clipper hwnd\n", (int)result); - return 1; - } - - // set the clipper on the primary surface - result = IDirectDrawSurface7_SetClipper(primary, clipper); - if (result != DD_OK) - { - osd_printf_verbose("DirectDraw: Error %08X setting clipper on primary surface\n", (int)result); - return 1; - } - return 0; -} - - - -//============================================================ -// compute_blit_surface_size -//============================================================ - -void renderer_dd::compute_blit_surface_size() -{ - INT32 newwidth, newheight; - int xscale, yscale; - RECT client; - - // start with the minimum size - window().target()->compute_minimum_size(newwidth, newheight); - - // get the window's client rectangle - GetClientRect(window().m_hwnd, &client); - - // hardware stretch case: apply prescale - if (video_config.hwstretch) - { - int prescale = (window().prescale() < 1) ? 1 : window().prescale(); - - // clamp the prescale to something smaller than the target bounds - xscale = prescale; - while (xscale > 1 && newwidth * xscale > rect_width(&client)) - xscale--; - yscale = prescale; - while (yscale > 1 && newheight * yscale > rect_height(&client)) - yscale--; - } - - // non stretch case - else - { - INT32 target_width = rect_width(&client); - INT32 target_height = rect_height(&client); - float desired_aspect = 1.0f; - - // compute the appropriate visible area if we're trying to keepaspect - if (video_config.keepaspect) - { - osd_monitor_info *monitor = window().winwindow_video_window_monitor(NULL); - window().target()->compute_visible_area(target_width, target_height, monitor->aspect(), window().target()->orientation(), target_width, target_height); - desired_aspect = (float)target_width / (float)target_height; - } - - // compute maximum integral scaling to fit the window - xscale = (target_width + 2) / newwidth; - yscale = (target_height + 2) / newheight; - - // try a little harder to keep the aspect ratio if desired - if (video_config.keepaspect) - { - // if we could stretch more in the X direction, and that makes a better fit, bump the xscale - while (newwidth * (xscale + 1) <= rect_width(&client) && - better_mode(newwidth * xscale, newheight * yscale, newwidth * (xscale + 1), newheight * yscale, desired_aspect)) - xscale++; - - // if we could stretch more in the Y direction, and that makes a better fit, bump the yscale - while (newheight * (yscale + 1) <= rect_height(&client) && - better_mode(newwidth * xscale, newheight * yscale, newwidth * xscale, newheight * (yscale + 1), desired_aspect)) - yscale++; - - // now that we've maxed out, see if backing off the maximally stretched one makes a better fit - if (rect_width(&client) - newwidth * xscale < rect_height(&client) - newheight * yscale) - { - while (xscale > 1 && better_mode(newwidth * xscale, newheight * yscale, newwidth * (xscale - 1), newheight * yscale, desired_aspect)) - xscale--; - } - else - { - while (yscale > 1 && better_mode(newwidth * xscale, newheight * yscale, newwidth * xscale, newheight * (yscale - 1), desired_aspect)) - yscale--; - } - } - } - - // ensure at least a scale factor of 1 - if (xscale == 0) xscale = 1; - if (yscale == 0) yscale = 1; - - // apply the final scale - newwidth *= xscale; - newheight *= yscale; - if (newwidth != blitwidth || newheight != blitheight) - { - // force some updates - update_outer_rects(); - osd_printf_verbose("DirectDraw: New blit size = %dx%d\n", newwidth, newheight); - } - blitwidth = newwidth; - blitheight = newheight; -} - - - -//============================================================ -// calc_fullscreen_margins -//============================================================ - -void renderer_dd::calc_fullscreen_margins(DWORD desc_width, DWORD desc_height, RECT *margins) -{ - margins->left = 0; - margins->top = 0; - margins->right = desc_width; - margins->bottom = desc_height; - - if (window().win_has_menu()) - { - static int height_with_menubar = 0; - if (height_with_menubar == 0) - { - RECT with_menu = { 100, 100, 200, 200 }; - RECT without_menu = { 100, 100, 200, 200 }; - AdjustWindowRect(&with_menu, WS_OVERLAPPED, TRUE); - AdjustWindowRect(&without_menu, WS_OVERLAPPED, FALSE); - height_with_menubar = (with_menu.bottom - with_menu.top) - (without_menu.bottom - without_menu.top); - } - margins->top = height_with_menubar; - } -} - - - -//============================================================ -// blit_to_primary -//============================================================ - -void renderer_dd::blit_to_primary(int srcwidth, int srcheight) -{ - IDirectDrawSurface7 *target = (back != NULL) ? back : primary; - osd_monitor_info *monitor = window().winwindow_video_window_monitor(NULL); - DDBLTFX blitfx = { sizeof(DDBLTFX) }; - RECT clear, outer, dest, source; - INT32 dstwidth, dstheight; - HRESULT result; - - // compute source rect - source.left = source.top = 0; - source.right = srcwidth; - source.bottom = srcheight; - - // compute outer rect -- windowed version - if (!window().fullscreen()) - { - GetClientRect(window().m_hwnd, &outer); - ClientToScreen(window().m_hwnd, &((LPPOINT)&outer)[0]); - ClientToScreen(window().m_hwnd, &((LPPOINT)&outer)[1]); - - // adjust to be relative to the monitor - osd_rect pos = monitor->position_size(); - outer.left -= pos.left(); - outer.right -= pos.left(); - outer.top -= pos.top(); - outer.bottom -= pos.top(); - } - - // compute outer rect -- full screen version - else - { - calc_fullscreen_margins(primarydesc.dwWidth, primarydesc.dwHeight, &outer); - } - - // if we're respecting the aspect ratio, we need to adjust to fit - dstwidth = rect_width(&outer); - dstheight = rect_height(&outer); - if (!video_config.hwstretch) - { - // trim the source if necessary - if (rect_width(&outer) < srcwidth) - { - source.left += (srcwidth - rect_width(&outer)) / 2; - source.right = source.left + rect_width(&outer); - } - if (rect_height(&outer) < srcheight) - { - source.top += (srcheight - rect_height(&outer)) / 2; - source.bottom = source.top + rect_height(&outer); - } - - // match the destination and source sizes - dstwidth = srcwidth = source.right - source.left; - dstheight = srcheight = source.bottom - source.top; - } - else if (video_config.keepaspect) - { - // compute the appropriate visible area - window().target()->compute_visible_area(rect_width(&outer), rect_height(&outer), monitor->aspect(), window().target()->orientation(), dstwidth, dstheight); - } - - // center within - dest.left = outer.left + (rect_width(&outer) - dstwidth) / 2; - dest.right = dest.left + dstwidth; - dest.top = outer.top + (rect_height(&outer) - dstheight) / 2; - dest.bottom = dest.top + dstheight; - - // compare against last destination; if different, force a redraw - if (dest.left != lastdest.left || dest.right != lastdest.right || dest.top != lastdest.top || dest.bottom != lastdest.bottom) - { - lastdest = dest; - update_outer_rects(); - } - - // clear outer rects if we need to - if (clearouter != 0) - { - clearouter--; - - // clear the left edge - if (dest.left > outer.left) - { - clear = outer; - clear.right = dest.left; - result = IDirectDrawSurface_Blt(target, &clear, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &blitfx); - if (result != DD_OK) osd_printf_verbose("DirectDraw: Error %08X clearing the screen\n", (int)result); - } - - // clear the right edge - if (dest.right < outer.right) - { - clear = outer; - clear.left = dest.right; - result = IDirectDrawSurface_Blt(target, &clear, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &blitfx); - if (result != DD_OK) osd_printf_verbose("DirectDraw: Error %08X clearing the screen\n", (int)result); - } - - // clear the top edge - if (dest.top > outer.top) - { - clear = outer; - clear.bottom = dest.top; - result = IDirectDrawSurface_Blt(target, &clear, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &blitfx); - if (result != DD_OK) osd_printf_verbose("DirectDraw: Error %08X clearing the screen\n", (int)result); - } - - // clear the bottom edge - if (dest.bottom < outer.bottom) - { - clear = outer; - clear.top = dest.bottom; - result = IDirectDrawSurface_Blt(target, &clear, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &blitfx); - if (result != DD_OK) osd_printf_verbose("DirectDraw: Error %08X clearing the screen\n", (int)result); - } - } - - // do the blit - result = IDirectDrawSurface7_Blt(target, &dest, blit, &source, DDBLT_WAIT, NULL); - if (result != DD_OK) osd_printf_verbose("DirectDraw: Error %08X blitting to the screen\n", (int)result); - - // page flip if triple buffered - if (window().fullscreen() && back != NULL) - { - result = IDirectDrawSurface7_Flip(primary, NULL, DDFLIP_WAIT); - if (result != DD_OK) osd_printf_verbose("DirectDraw: Error %08X waiting for VBLANK\n", (int)result); - } -} - - - -//============================================================ -// config_adapter_mode -//============================================================ - -int renderer_dd::config_adapter_mode() -{ - DDDEVICEIDENTIFIER2 identifier; - HRESULT result; - - // choose the monitor number - get_adapter_for_monitor(window().monitor()); - - // create a temporary DirectDraw object - result = (*directdrawcreateex)(adapter_ptr, (LPVOID *)&ddraw, WRAP_REFIID(IID_IDirectDraw7), NULL); - if (result != DD_OK) - { - osd_printf_verbose("DirectDraw: Error %08X during DirectDrawCreateEx call\n", (int)result); - return 1; - } - - // get the identifier - result = IDirectDraw7_GetDeviceIdentifier(ddraw, &identifier, 0); - if (result != DD_OK) - { - osd_printf_error("Error getting identifier for device\n"); - return 1; - } - osd_printf_verbose("DirectDraw: Configuring device %s\n", identifier.szDescription); - - // get the current display mode - memset(&origmode, 0, sizeof(origmode)); - origmode.dwSize = sizeof(origmode); - result = IDirectDraw7_GetDisplayMode(ddraw, &origmode); - if (result != DD_OK) - { - osd_printf_verbose("DirectDraw: Error %08X getting current display mode\n", (int)result); - IDirectDraw7_Release(ddraw); - return 1; - } - - // choose a resolution: full screen mode case - if (window().fullscreen()) - { - // default to the current mode exactly - width = origmode.dwWidth; - height = origmode.dwHeight; - refresh = origmode.dwRefreshRate; - - // if we're allowed to switch resolutions, override with something better - if (video_config.switchres) - pick_best_mode(); - } - - // release the DirectDraw object - IDirectDraw7_Release(ddraw); - ddraw = NULL; - - // if we're not changing resolutions, make sure we have a resolution we can handle - if (!window().fullscreen() || !video_config.switchres) - { - switch (origmode.ddpfPixelFormat.dwRBitMask) - { - case 0x00ff0000: - case 0x000000ff: - case 0xf800: - case 0x7c00: - break; - - default: - osd_printf_verbose("DirectDraw: Unknown target mode: R=%08X G=%08X B=%08X\n", (int)origmode.ddpfPixelFormat.dwRBitMask, (int)origmode.ddpfPixelFormat.dwGBitMask, (int)origmode.ddpfPixelFormat.dwBBitMask); - return 1; - } - } - - return 0; -} - - - -//============================================================ -// monitor_enum_callback -//============================================================ - -static BOOL WINAPI monitor_enum_callback(GUID FAR *guid, LPSTR description, LPSTR name, LPVOID context, HMONITOR hmonitor) -{ - monitor_enum_info *einfo = (monitor_enum_info *)context; - - // do we match the desired monitor? - if (hmonitor == *((HMONITOR *)einfo->monitor->oshandle()) || (hmonitor == NULL && einfo->monitor->is_primary())) - { - einfo->guid_ptr = (guid != NULL) ? &einfo->guid : NULL; - if (guid != NULL) - einfo->guid = *guid; - einfo->foundit = TRUE; - } - return 1; -} - - - -//============================================================ -// get_adapter_for_monitor -//============================================================ - -void renderer_dd::get_adapter_for_monitor(osd_monitor_info *monitor) -{ - monitor_enum_info einfo; - HRESULT result; - - // try to find our monitor - memset(&einfo, 0, sizeof(einfo)); - einfo.monitor = monitor; - result = (*directdrawenumerateex)(monitor_enum_callback, &einfo, DDENUM_ATTACHEDSECONDARYDEVICES); - if (result != DD_OK) osd_printf_verbose("DirectDraw: Error %08X during DirectDrawEnumerateEx call\n", (int)result); - - // set up the adapter - if (einfo.foundit && einfo.guid_ptr != NULL) - { - adapter = einfo.guid; - adapter_ptr = &adapter; - } - else - adapter_ptr = NULL; -} - - - -//============================================================ -// enum_modes_callback -//============================================================ - -static HRESULT WINAPI enum_modes_callback(LPDDSURFACEDESC2 desc, LPVOID context) -{ - float size_score, refresh_score, final_score; - mode_enum_info *einfo = (mode_enum_info *)context; - renderer_dd *dd = einfo->renderer; - - // skip non-32 bit modes - if (desc->ddpfPixelFormat.dwRGBBitCount != 32) - return DDENUMRET_OK; - - // compute initial score based on difference between target and current - size_score = 1.0f / (1.0f + fabs((float)((INT32)desc->dwWidth - einfo->target_width)) + fabs((float)((INT32)desc->dwHeight - einfo->target_height))); - - // if the mode is too small, give a big penalty - if (desc->dwWidth < einfo->minimum_width || desc->dwHeight < einfo->minimum_height) - size_score *= 0.01f; - - // if mode is smaller than we'd like, it only scores up to 0.1 - if (desc->dwWidth < einfo->target_width || desc->dwHeight < einfo->target_height) - size_score *= 0.1f; - - // if we're looking for a particular mode, that's a winner - if (desc->dwWidth == einfo->window->m_win_config.width && desc->dwHeight == einfo->window->m_win_config.height) - size_score = 2.0f; - - // compute refresh score - refresh_score = 1.0f / (1.0f + fabs((double)desc->dwRefreshRate - einfo->target_refresh)); - - // if refresh is smaller than we'd like, it only scores up to 0.1 - if ((double)desc->dwRefreshRate < einfo->target_refresh) - refresh_score *= 0.1f; - - // if we're looking for a particular refresh, make sure it matches - if (desc->dwRefreshRate == einfo->window->m_win_config.refresh) - refresh_score = 2.0f; - - // weight size and refresh equally - final_score = size_score + refresh_score; - - // best so far? - osd_printf_verbose(" %4dx%4d@%3dHz -> %f\n", (int)desc->dwWidth, (int)desc->dwHeight, (int)desc->dwRefreshRate, final_score * 1000.0f); - if (final_score > einfo->best_score) - { - einfo->best_score = final_score; - dd->width = desc->dwWidth; - dd->height = desc->dwHeight; - dd->refresh = desc->dwRefreshRate; - } - return DDENUMRET_OK; -} - - - -//============================================================ -// pick_best_mode -//============================================================ - -void renderer_dd::pick_best_mode() -{ - mode_enum_info einfo; - HRESULT result; - - // determine the minimum width/height for the selected target - // note: technically we should not be calling this from an alternate window - // thread; however, it is only done during init time, and the init code on - // the main thread is waiting for us to finish, so it is safe to do so here - window().target()->compute_minimum_size(einfo.minimum_width, einfo.minimum_height); - - // use those as the target for now - einfo.target_width = einfo.minimum_width * MAX(1, window().prescale()); - einfo.target_height = einfo.minimum_height * MAX(1, window().prescale()); - - // determine the refresh rate of the primary screen - einfo.target_refresh = 60.0; - const screen_device *primary_screen = window().machine().config().first_screen(); - if (primary_screen != NULL) - einfo.target_refresh = ATTOSECONDS_TO_HZ(primary_screen->refresh_attoseconds()); - printf("Target refresh = %f\n", einfo.target_refresh); - - // if we're not stretching, allow some slop on the minimum since we can handle it - if (!video_config.hwstretch) - { - einfo.minimum_width -= 4; - einfo.minimum_height -= 4; - } - - // if we are stretching, aim for a mode approximately 2x the game's resolution - else if (window().prescale() <= 1) - { - einfo.target_width *= 2; - einfo.target_height *= 2; - } - - // fill in the rest of the data - einfo.window = &window(); - einfo.renderer = this; - einfo.best_score = 0.0f; - - // enumerate the modes - osd_printf_verbose("DirectDraw: Selecting video mode...\n"); - result = IDirectDraw7_EnumDisplayModes(ddraw, DDEDM_REFRESHRATES, NULL, &einfo, enum_modes_callback); - if (result != DD_OK) osd_printf_verbose("DirectDraw: Error %08X during EnumDisplayModes call\n", (int)result); - osd_printf_verbose("DirectDraw: Mode selected = %4dx%4d@%3dHz\n", width, height, refresh); -} |