/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * DirectDraw acceleration. * * By Stefan Schimanski. * * Bugfixes by Isaac Cruz. * * Accelerated rectfill() and hline() added by Shawn Hargreaves. * * See readme.txt for copyright information. */ #include "wddraw.h" #define PREFIX_I "al-ddaccel INFO: " #define PREFIX_W "al-ddaccel WARNING: " #define PREFIX_E "al-ddaccel ERROR: " /* software version pointers */ static void (*_orig_hline) (BITMAP * bmp, int x1, int y, int x2, int color); static void (*_orig_vline) (BITMAP * bmp, int x, int y1, int y2, int color); static void (*_orig_rectfill) (BITMAP * bmp, int x1, int y1, int x2, int y2, int color); static void (*_orig_draw_sprite) (BITMAP * bmp, BITMAP * sprite, int x, int y); static void (*_orig_masked_blit) (BITMAP * source, BITMAP * dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height); /* ddraw_blit_to_self: * Accelerated vram -> vram blitting routine. */ static void ddraw_blit_to_self(BITMAP * source, BITMAP * dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height) { RECT src_rect; int dest_parent_x = dest_x + dest->x_ofs; int dest_parent_y = dest_y + dest->y_ofs; BITMAP *dest_parent; BITMAP *source_parent; src_rect.left = source_x + source->x_ofs; src_rect.top = source_y + source->y_ofs; src_rect.right = source_x + source->x_ofs + width; src_rect.bottom = source_y + source->y_ofs + height; /* find parents */ dest_parent = dest; while (dest_parent->id & BMP_ID_SUB) dest_parent = (BITMAP *)dest_parent->extra; source_parent = source; while (source_parent->id & BMP_ID_SUB) source_parent = (BITMAP *)source_parent->extra; _enter_gfx_critical(); gfx_directx_release_lock(dest); gfx_directx_release_lock(source); IDirectDrawSurface2_BltFast(DDRAW_SURFACE_OF(dest_parent)->id, dest_parent_x, dest_parent_y, DDRAW_SURFACE_OF(source_parent)->id, &src_rect, DDBLTFAST_WAIT); _exit_gfx_critical(); /* only for windowed mode */ if ((gfx_driver->id == GFX_DIRECTX_WIN) && (dest_parent == gfx_directx_forefront_bitmap)) { src_rect.left = dest_parent_x; src_rect.top = dest_parent_y; src_rect.right = dest_parent_x + width; src_rect.bottom = dest_parent_y + height; win_gfx_driver->paint(&src_rect); } } /* ddraw_masked_blit: * Accelerated masked blitting routine. */ static void ddraw_masked_blit(BITMAP * source, BITMAP * dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height) { RECT dest_rect, source_rect; DDCOLORKEY src_key; HRESULT hr; BITMAP *dest_parent; BITMAP *source_parent; dest_rect.left = dest_x + dest->x_ofs; dest_rect.top = dest_y + dest->y_ofs; dest_rect.right = dest_x + dest->x_ofs + width; dest_rect.bottom = dest_y + dest->y_ofs + height; source_rect.left = source_x + source->x_ofs; source_rect.top = source_y + source->y_ofs; source_rect.right = source_x + source->x_ofs + width; source_rect.bottom = source_y + source->y_ofs + height; src_key.dwColorSpaceLowValue = source->vtable->mask_color; src_key.dwColorSpaceHighValue = source->vtable->mask_color; if (is_video_bitmap(source) || is_system_bitmap(source)) { /* find parents */ dest_parent = dest; while (dest_parent->id & BMP_ID_SUB) dest_parent = (BITMAP *)dest_parent->extra; source_parent = source; while (source_parent->id & BMP_ID_SUB) source_parent = (BITMAP *)source_parent->extra; _enter_gfx_critical(); gfx_directx_release_lock(dest); gfx_directx_release_lock(source); IDirectDrawSurface2_SetColorKey(DDRAW_SURFACE_OF(source_parent)->id, DDCKEY_SRCBLT, &src_key); hr = IDirectDrawSurface2_Blt(DDRAW_SURFACE_OF(dest_parent)->id, &dest_rect, DDRAW_SURFACE_OF(source_parent)->id, &source_rect, DDBLT_KEYSRC | DDBLT_WAIT, NULL); _exit_gfx_critical(); if (FAILED(hr)) _TRACE(PREFIX_E "Blt failed (%x)\n", hr); /* only for windowed mode */ if ((gfx_driver->id == GFX_DIRECTX_WIN) && (dest_parent == gfx_directx_forefront_bitmap)) win_gfx_driver->paint(&dest_rect); } else { /* have to use the original software version */ _orig_masked_blit(source, dest, source_x, source_y, dest_x, dest_y, width, height); } } /* ddraw_draw_sprite: * Accelerated sprite drawing routine. */ static void ddraw_draw_sprite(BITMAP * bmp, BITMAP * sprite, int x, int y) { int sx, sy, w, h; if (is_video_bitmap(sprite) || is_system_bitmap(sprite)) { sx = sprite->x_ofs; sy = sprite->y_ofs; w = sprite->w; h = sprite->h; if (bmp->clip) { if (x < bmp->cl) { sx += bmp->cl - x; w -= bmp->cl - x; x = bmp->cl; } if (y < bmp->ct) { sy += bmp->ct - y; h -= bmp->ct - y; y = bmp->ct; } if (x + w > bmp->cr) w = bmp->cr - x; if (w <= 0) return; if (y + h > bmp->cb) h = bmp->cb - y; if (h <= 0) return; } ddraw_masked_blit(sprite, bmp, sx, sy, x, y, w, h); } else { /* have to use the original software version */ _orig_draw_sprite(bmp, sprite, x, y); } } /* ddraw_clear_to_color: * Accelerated screen clear routine. */ static void ddraw_clear_to_color(BITMAP * bitmap, int color) { RECT dest_rect; HRESULT hr; DDBLTFX blt_fx; BITMAP *parent; dest_rect.left = bitmap->cl + bitmap->x_ofs; dest_rect.top = bitmap->ct + bitmap->y_ofs; dest_rect.right = bitmap->x_ofs + bitmap->cr; dest_rect.bottom = bitmap->y_ofs + bitmap->cb; /* find parent */ parent = bitmap; while (parent->id & BMP_ID_SUB) parent = (BITMAP *)parent->extra; /* set fill color */ blt_fx.dwSize = sizeof(blt_fx); blt_fx.dwDDFX = 0; blt_fx.dwFillColor = color; _enter_gfx_critical(); gfx_directx_release_lock(bitmap); hr = IDirectDrawSurface2_Blt(DDRAW_SURFACE_OF(parent)->id, &dest_rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &blt_fx); _exit_gfx_critical(); if (FAILED(hr)) _TRACE(PREFIX_E "Blt failed (%x)\n", hr); /* only for windowed mode */ if ((gfx_driver->id == GFX_DIRECTX_WIN) && (parent == gfx_directx_forefront_bitmap)) win_gfx_driver->paint(&dest_rect); } /* ddraw_rectfill: * Accelerated rectangle fill routine. */ static void ddraw_rectfill(BITMAP *bitmap, int x1, int y1, int x2, int y2, int color) { RECT dest_rect; HRESULT hr; DDBLTFX blt_fx; BITMAP *parent; if (_drawing_mode != DRAW_MODE_SOLID) { _orig_rectfill(bitmap, x1, y1, x2, y2, color); return; } if (x2 < x1) { int tmp = x1; x1 = x2; x2 = tmp; } if (y2 < y1) { int tmp = y1; y1 = y2; y2 = tmp; } if (bitmap->clip) { if (x1 < bitmap->cl) x1 = bitmap->cl; if (x2 >= bitmap->cr) x2 = bitmap->cr-1; if (x2 < x1) return; if (y1 < bitmap->ct) y1 = bitmap->ct; if (y2 >= bitmap->cb) y2 = bitmap->cb-1; if (y2 < y1) return; } dest_rect.left = x1 + bitmap->x_ofs; dest_rect.top = y1 + bitmap->y_ofs; dest_rect.right = x2 + bitmap->x_ofs + 1; dest_rect.bottom = y2 + bitmap->y_ofs + 1; /* find parent */ parent = bitmap; while (parent->id & BMP_ID_SUB) parent = (BITMAP *)parent->extra; /* set fill color */ blt_fx.dwSize = sizeof(blt_fx); blt_fx.dwDDFX = 0; blt_fx.dwFillColor = color; _enter_gfx_critical(); gfx_directx_release_lock(bitmap); hr = IDirectDrawSurface2_Blt(DDRAW_SURFACE_OF(parent)->id, &dest_rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &blt_fx); _exit_gfx_critical(); if (FAILED(hr)) _TRACE(PREFIX_E "Blt failed (%x)\n", hr); /* only for windowed mode */ if ((gfx_driver->id == GFX_DIRECTX_WIN) && (parent == gfx_directx_forefront_bitmap)) win_gfx_driver->paint(&dest_rect); } /* ddraw_hline: * Accelerated scanline fill routine. */ static void ddraw_hline(BITMAP *bitmap, int x1, int y, int x2, int color) { RECT dest_rect; HRESULT hr; DDBLTFX blt_fx; BITMAP *parent; if (_drawing_mode != DRAW_MODE_SOLID) { _orig_hline(bitmap, x1, y, x2, color); return; } if (x1 > x2) { int tmp = x1; x1 = x2; x2 = tmp; } if (bitmap->clip) { if ((y < bitmap->ct) || (y >= bitmap->cb)) return; if (x1 < bitmap->cl) x1 = bitmap->cl; if (x2 >= bitmap->cr) x2 = bitmap->cr-1; if (x2 < x1) return; } dest_rect.left = x1 + bitmap->x_ofs; dest_rect.top = y + bitmap->y_ofs; dest_rect.right = x2 + bitmap->x_ofs + 1; dest_rect.bottom = y + bitmap->y_ofs + 1; /* find parent */ parent = bitmap; while (parent->id & BMP_ID_SUB) parent = (BITMAP *)parent->extra; /* set fill color */ blt_fx.dwSize = sizeof(blt_fx); blt_fx.dwDDFX = 0; blt_fx.dwFillColor = color; _enter_gfx_critical(); gfx_directx_release_lock(bitmap); hr = IDirectDrawSurface2_Blt(DDRAW_SURFACE_OF(parent)->id, &dest_rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &blt_fx); _exit_gfx_critical(); if (FAILED(hr)) _TRACE(PREFIX_E "Blt failed (%x)\n", hr); /* only for windowed mode */ if ((gfx_driver->id == GFX_DIRECTX_WIN) && (parent == gfx_directx_forefront_bitmap)) win_gfx_driver->paint(&dest_rect); } /* ddraw_vline: * Accelerated vline routine. */ static void ddraw_vline(BITMAP *bitmap, int x, int y1, int y2, int color) { RECT dest_rect; HRESULT hr; DDBLTFX blt_fx; BITMAP *parent; if (_drawing_mode != DRAW_MODE_SOLID) { _orig_vline(bitmap, x, y1, y2, color); return; } if (y1 > y2) { int tmp = y1; y1 = y2; y2 = tmp; } if (bitmap->clip) { if ((x < bitmap->cl) || (x >= bitmap->cr)) return; if (y1 < bitmap->ct) y1 = bitmap->ct; if (y2 >= bitmap->cb) y2 = bitmap->cb-1; if (y2 < y1) return; } dest_rect.top = y1 + bitmap->y_ofs; dest_rect.left = x + bitmap->x_ofs; dest_rect.bottom = y2 + bitmap->y_ofs + 1; dest_rect.right = x + bitmap->x_ofs + 1; /* find parent */ parent = bitmap; while (parent->id & BMP_ID_SUB) parent = (BITMAP *)parent->extra; /* set fill color */ blt_fx.dwSize = sizeof(blt_fx); blt_fx.dwDDFX = 0; blt_fx.dwFillColor = color; _enter_gfx_critical(); gfx_directx_release_lock(bitmap); hr = IDirectDrawSurface2_Blt(DDRAW_SURFACE_OF(parent)->id, &dest_rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &blt_fx); _exit_gfx_critical(); if (FAILED(hr)) _TRACE(PREFIX_E "Blt failed (%x)\n", hr); /* only for windowed mode */ if ((gfx_driver->id == GFX_DIRECTX_WIN) && (parent == gfx_directx_forefront_bitmap)) win_gfx_driver->paint(&dest_rect); } /* gfx_directx_enable_acceleration: * Checks graphic driver for capabilities to accelerate Allegro. */ void gfx_directx_enable_acceleration(GFX_DRIVER * drv) { /* safe pointer to software versions */ _orig_hline = _screen_vtable.hline; _orig_vline = _screen_vtable.vline; _orig_rectfill = _screen_vtable.rectfill; _orig_draw_sprite = _screen_vtable.draw_sprite; _orig_masked_blit = _screen_vtable.masked_blit; /* accelerated video to video blits? */ if (ddcaps.dwCaps & DDCAPS_BLT) { _screen_vtable.blit_to_self = ddraw_blit_to_self; _screen_vtable.blit_to_self_forward = ddraw_blit_to_self; _screen_vtable.blit_to_self_backward = ddraw_blit_to_self; _screen_vtable.blit_from_system = ddraw_blit_to_self; _screen_vtable.blit_to_system = ddraw_blit_to_self; gfx_capabilities |= (GFX_HW_VRAM_BLIT | GFX_HW_SYS_TO_VRAM_BLIT); } /* accelerated color fills? */ if (ddcaps.dwCaps & DDCAPS_BLTCOLORFILL) { _screen_vtable.clear_to_color = ddraw_clear_to_color; _screen_vtable.rectfill = ddraw_rectfill; _screen_vtable.hline = ddraw_hline; _screen_vtable.vline = ddraw_vline; gfx_capabilities |= (GFX_HW_HLINE | GFX_HW_FILL); } /* accelerated color key blits? */ if ((ddcaps.dwCaps & DDCAPS_COLORKEY) && (ddcaps.dwCKeyCaps & DDCKEYCAPS_SRCBLT)) { _screen_vtable.masked_blit = ddraw_masked_blit; _screen_vtable.draw_sprite = ddraw_draw_sprite; if (_screen_vtable.color_depth == 8) _screen_vtable.draw_256_sprite = ddraw_draw_sprite; gfx_capabilities |= (GFX_HW_VRAM_BLIT_MASKED | GFX_HW_SYS_TO_VRAM_BLIT_MASKED); } } /* gfx_directx_enable_triple_buffering: * Checks graphic driver for triple buffering capability. */ void gfx_directx_enable_triple_buffering(GFX_DRIVER *drv) { HRESULT hr; hr = IDirectDrawSurface2_GetFlipStatus(DDRAW_SURFACE_OF(gfx_directx_forefront_bitmap)->id, DDGFS_ISFLIPDONE); if ((hr == DD_OK) || (hr == DDERR_WASSTILLDRAWING)) { drv->poll_scroll = gfx_directx_poll_scroll; gfx_capabilities |= GFX_CAN_TRIPLE_BUFFER; } }