   Loading REALLY BIG Bitmaps in DirectDraw
   I began working on a project several months ago and could only get bitmaps smaller than 7 megs onto an off screen surface. I tried several things, but just accepted the 7 meg limit after awhile. I recently decided to try again, my results were the same. My first attempt used a few win32 functions to load the bitmap, then put it onto an offscreen surface. My second attempt(based on Andre LaMothe code) does everything without win32. Below is my second attempt, it works fine with small bitmaps, but again there is an under 10 meg limit. Basically, I want the option to use really BIG bitmaps if I desire.  Question 1) What is the bitmap size limit for DD? Question 2) Any ideas on what I could do different?The following code fully compiles, at least on my machine. I have already worked around the bitmap size limitation in my big project, Im just trying to get this to work with big bitmaps for a later time.   #define WIN32_LEAN_AND_MEAN  // just say no to MFC#define INITGUID//////////////Includes//////////////#include <windows.h>  #include <windowsx.h> #include <mmsystem.h>#include <commdlg.h >#include <iostream.h>#include <conio.h>#include <stdlib.h>#include <malloc.h>#include <memory.h>#include <string.h>#include <stdarg.h>#include <stdio.h> #include <math.h>#include <io.h>#include <fcntl.h>#include <ddraw.h>///////////// TYPES /////////////// basic unsigned typestypedef unsigned short USHORT;typedef unsigned short WORD;typedef unsigned char  UCHAR;typedef unsigned char  BYTE;// container structure for bitmaps .BMP filetypedef struct BITMAP_FILE_TAG   {   BITMAPFILEHEADER bitmapfileheader;  // this contains the bitmapfile header   BITMAPINFOHEADER bitmapinfoheader;  // this is all the info including the palette   PALETTEENTRYpalette[256]; // we will store the palette here   UCHAR  *buffer; // this is a pointer to the data   } BITMAP_FILE, *BITMAP_FILE_PTR;/////////////Defines///////////////Windows Interface#define WINDOW_CLASS_NAME "Generic"  #define WINDOW_TITLE "Generic"#define SCREEN_WIDTH 1024   //Pixels wide#define SCREEN_HEIGHT768    //Pixels high#define SCREEN_BPP   32//Bits Per Pixel#define _RGB32BIT(a,r,g,b) ((b) + ((g) << 8) + ((r) << 16) + ((a) << 24))#define DDRAW_INIT_STRUCT(ddstruct) { memset(&ddstruct,0,sizeof(ddstruct)); ddstruct.dwSize=sizeof(ddstruct); }#define BITMAP_ID  0x4D42 // universal id for a bitmap#define MAX_COLORS_PALETTE   256// tests if a key is up or down#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)#define KEYUP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)/////////////Globals/////////////HWND main_window_handle= NULL; //save the window handleHINSTANCE main_instance= NULL; //save the instanceint  window_closed= NULL; //prevents further entry in game loopLPDIRECTDRAW7    lpdd   = NULL;    // dd objectLPDIRECTDRAWSURFACE7  lpddsprimary = NULL;   // dd primary surfaceLPDIRECTDRAWSURFACE7  lpddsback    = NULL;   // dd back surfaceLPDIRECTDRAWCLIPPER   lpddclipper  = NULL;   // dd clipperDDSURFACEDESC2   ddsd;   // a direct draw surface description structDDBLTFXddbltfx;// used to fillDDSCAPS2    ddscaps;// a direct draw surface capabilities structHRESULTddrval; // result back from dd callsBITMAP_FILE bitmap; // holds the bitmapLPDIRECTDRAWSURFACE7  lpdds_small = NULL;LPDIRECTDRAWSURFACE7  lpdds_big   = NULL;////////////////Prototypes////////////////int GameInitialize();int GameMainLoop();int GameClose();int FlipBitmap(UCHAR *image, int bytes_per_line, int height);int LoadBitmapFile(BITMAP_FILE_PTR bitmap, char *filename);int UnloadBitmapFile(BITMAP_FILE_PTR bitmap);LPDIRECTDRAWSURFACE7 LoadBitmapOnSurface(BITMAP_FILE bitmap,int red,int green,int blue);inline int Blit_Object(LPDIRECTDRAWSURFACE7 bmp_surface,   int dx, int dy, int dx2, int dy2,   HWND main_window_handle);LPDIRECTDRAWCLIPPER Attach_Clipper(LPDIRECTDRAWSURFACE7 lpdds,int num_rects,LPRECT clip_list);/////////////WinProc/////////////LRESULT CALLBACK WindowProc(HWND hwnd,UINT msg,    WPARAM wparam,    LPARAM lparam){// this is the main message handler of the systemPAINTSTRUCTps;   // used in WM_PAINTHDChdc;   // handle to a device context// what is the message switch(msg){    case WM_CREATE:    {// do initialization stuff herereturn(0);} break;    case WM_PAINT:    {    // start painting    hdc = BeginPaint(hwnd,&ps);    // end painting    EndPaint(hwnd,&ps);    return(0);   } break;case WM_DESTROY: {// kill the applicationPostQuitMessage(0);return(0);} break;default:break;    } // end switch(msg)// process any messages that we didn''t take care of return (DefWindowProc(hwnd, msg, wparam, lparam));} //end WindowProc//------------------------------------------------------------------------////BEGIN WINMAIN////------------------------------------------------------------------------int WINAPI WinMain(HINSTANCE hinstance,HINSTANCE hprevinstance,LPSTR lpcmdline,int ncmdshow){    WNDCLASSEX Window;   //Main Window    HWND   hwnd = NULL;  //Generic window handle    MSG   msg; //Generic message    ////////////////////    //Window Structure//    ////////////////////    Window.cbSize = sizeof(WNDCLASSEX);    Window.style= CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;    Window.lpfnWndProc    = WindowProc;    Window.cbClsExtra= 0;    Window.cbWndExtra= 0;    Window.hInstance= hinstance;    Window.hIcon= LoadIcon(NULL, IDI_APPLICATION);    Window.hCursor    = LoadCursor(NULL, IDC_ARROW);Window.hbrBackground= (HBRUSH)GetStockObject(BLACK_BRUSH);    Window.lpszMenuName    = NULL;    Window.lpszClassName= WINDOW_CLASS_NAME;    Window.hIconSm= LoadIcon(NULL, IDI_APPLICATION);    //Register the window class    if (!RegisterClassEx(&Window))    return(0);    //Create the game window    if (FAILED(hwnd = CreateWindowEx(NULL,    // extended styleWINDOW_CLASS_NAME,   // class   WINDOW_TITLE,   // title   WS_POPUP | WS_VISIBLE,    0,0, // initial x,y   SCREEN_WIDTH,SCREEN_HEIGHT,    // initial width, height   NULL,  // handle to parent    NULL,  // handle to menu   hinstance, // instance of this application   NULL)))    // extra creation parms{//If failure, Show MB    MessageBox(main_window_handle,"FATAL ERROR:UNABLE TO MAIN GAME WINDOW","Windows Error Message", MB_OK);return(0);} //end if    //Save in globals    main_window_handle = hwnd;    main_instance = hinstance;    //Prepare for game loop    GameInitialize();/////////////////////Main Event Loop/////////////////////while(1) {if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {  // test if this is a quit    if (msg.message == WM_QUIT)    break; // translate any accelerator keys TranslateMessage(&msg); // send the message to the window proc DispatchMessage(&msg);  } // end if    //Game LoopGameMainLoop(); }//end while/////////////////////////End Main Event Loop/////////////////////////    //Game Close    GameClose();    //Return to Windows    return(msg.wParam);}//end WinMain//------------------------------------------------------------------------////END WINMAIN////------------------------------------------------------------------------//////////////////////////Function Definitions////////////////////////////////////////////////GameInitialize()//////////////////////int GameInitialize(){//DirectDraw Interface    if(FAILED(DirectDrawCreateEx(NULL, (void**)&lpdd, IID_IDirectDraw7,NULL))){//If failure, Show MB    MessageBox(main_window_handle,"FATAL ERROR:UNABLE TO CREATE DDRAW OBJECT","DirectX Error Message", MB_OK);return(0);} //end if//Windows Cooperative Levelif(FAILED(lpdd->SetCooperativeLevel(main_window_handle,  DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT |DDSCL_EXCLUSIVE))){//If failure, Show MB    MessageBox(main_window_handle,    "FATAL ERROR:DDRAW COOP LEVEL","DirectX Error Message", MB_OK);return(0);} //end if//Set Display Modeif(FAILED(lpdd->SetDisplayMode(SCREEN_WIDTH,  SCREEN_HEIGHT,   SCREEN_BPP,   0,0))){//If failure, Show MB    MessageBox(main_window_handle,    "FATAL ERROR:UNABLE TO SETUP DISPLAY","DirectX Error Message", MB_OK);return(0);} //end if//Prepare DD Surface DescriptionDDRAW_INIT_STRUCT(ddsd);ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;ddsd.dwBackBufferCount = 1;ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |   DDSCAPS_COMPLEX | DDSCAPS_FLIP;//Create Primary Surfaceif(FAILED(lpdd->CreateSurface(&ddsd, &lpddsprimary, NULL))){//If failure, Show MB    MessageBox(main_window_handle,    "FATAL ERROR:UNABLE TO CREATE PRIMARY SURFACE","DirectX Error Message", MB_OK);return(0);} //end if//Create Backbuffer    ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;if(FAILED(lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsback))){//If failure, Show MB    MessageBox(main_window_handle,    "FATAL ERROR:UNABLE TO CREATE BACKBUFFER","DirectX Error Message", MB_OK);return(0);} //end if    //Setup Clipper on Back Buffer    RECT clip_list[1] = {{0,0,1024,768}};  Attach_Clipper(lpddsback,1,clip_list);   //Load Bitmaps    LoadBitmapFile(&bitmap,"graphics/israel_interface.bmp");    lpdds_small = LoadBitmapOnSurface(bitmap,255,0,255);//LoadBitmapFile(&bitmap,"test.bmp");    //lpdds_big = LoadBitmapOnSurface(bitmap,255,0,255);return(1);}//////////////////////////End GameInitialize()//////////////////////////    ////////////////////GameMainLoop()////////////////////int GameMainLoop(){    //Closes GameMain Gateif(window_closed)return(0);// for now test if user is hitting ESC and send WM_CLOSE    if (KEYDOWN(VK_ESCAPE)){PostMessage(main_window_handle,WM_CLOSE,0,0); window_closed = 1;    } // end if//Blit the small mapBlit_Object(lpdds_small,0,0,1024,768,main_window_handle);//Flip    if(FAILED(lpddsprimary->Flip(NULL, DDFLIP_WAIT))){MessageBox(main_window_handle,    "FATAL ERROR:UNABLE TO PERFORM SURFACE FLIP","DirectX Error Message", MB_OK); return(0);} //end ifreturn(1);}////////////////////End GameMain()/////////////////////////////////////GameClose()/////////////////int GameClose(){UnloadBitmapFile(&bitmap);if(lpdds_small)    lpdds_small->Release();lpdds_small = NULL;if(lpdds_big)    lpdds_big->Release();lpdds_big = NULL;return(1);}/////////////////////end GameClose()///////////////////////////////////////////LoadBitmapFile()//////////////////////int LoadBitmapFile(BITMAP_FILE_PTR bitmap, char *filename){// this function opens a bitmap file and loads the data into bitmapint file_handle,  // the file handle    index;   // looping indexUCHAR   *temp_buffer = NULL; // used to convert 24 bit images to 16 bitOFSTRUCT file_data;// the file data information// open the file if it existsif ((file_handle = OpenFile(filename,&file_data,OF_READ))==-1)   return(0);// now load the bitmap file header_lread(file_handle, &bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));// test if this is a bitmap fileif (bitmap->bitmapfileheader.bfType!=BITMAP_ID)   {   // close the file   _lclose(file_handle);   // return error   return(0);   } // end if// now we know this is a bitmap, so read in all the sections// first the bitmap infoheader// now load the bitmap file header_lread(file_handle, &bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));// now load the color palette if there is oneif (bitmap->bitmapinfoheader.biBitCount == 8)   {   _lread(file_handle, &bitmap->palette,MAX_COLORS_PALETTE*sizeof(PALETTEENTRY));   // now set all the flags in the palette correctly and fix the reversed    // BGR RGBQUAD data format   for (index=0; index < MAX_COLORS_PALETTE; index++)  {  // reverse the red and green fields  int temp_color = bitmap->palette[index].peRed;  bitmap->palette[index].peRed  = bitmap->palette[index].peBlue;  bitmap->palette[index].peBlue = temp_color;    // always set the flags word to this  bitmap->palette[index].peFlags = PC_NOCOLLAPSE;  } // end for index    } // end if// finally the image data itself_lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);// now read in the image, if the image is 8 or 16 bit then simply read it// but if its 24 bit then read it into a temporary area and then convert// it to a 16 bit imageif (bitmap->bitmapinfoheader.biBitCount==8 || bitmap->bitmapinfoheader.biBitCount==16 ||bitmap->bitmapinfoheader.biBitCount==24)   {   // delete the last image if there was one   if (bitmap->buffer)  free(bitmap->buffer);   // allocate the memory for the image   if (!(bitmap->buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage))) { // close the file _lclose(file_handle); // return error return(0); } // end if   // now read it in   _lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);   } // end ifelse   {   // serious problem   return(0);   } // end else#if 0// write the file info out printf("\nfilename:%s \nsize=%d \nwidth=%d \nheight=%d \nbitsperpixel=%d \ncolors=%d \nimpcolors=%d",   filename,   bitmap->bitmapinfoheader.biSizeImage,   bitmap->bitmapinfoheader.biWidth,   bitmap->bitmapinfoheader.biHeight,bitmap->bitmapinfoheader.biBitCount,   bitmap->bitmapinfoheader.biClrUsed,   bitmap->bitmapinfoheader.biClrImportant);#endif// close the file_lclose(file_handle);// flip the bitmapFlipBitmap(bitmap->buffer,   bitmap->bitmapinfoheader.biWidth*(bitmap->bitmapinfoheader.biBitCount/8),   bitmap->bitmapinfoheader.biHeight);// return successreturn(1);} ///////////////////////////End LoadBitmapFile()///////////////////////////////////////////////////UnloadBitmapFile()////////////////////////int UnloadBitmapFile(BITMAP_FILE_PTR bitmap){// this function releases all memory associated with "bitmap"if (bitmap->buffer)   {   // release memory   free(bitmap->buffer);   // reset pointer   bitmap->buffer = NULL;   } // end if// return successreturn(1);}////////////////////////////End UnloadBitmapFile()//////////////////////////////////////////////FlipBitmap()//////////////////int FlipBitmap(UCHAR *image, int bytes_per_line, int height){// this function is used to flip bottom-up .BMP imagesUCHAR *buffer; // used to perform the image processingint index;// looping index// allocate the temporary bufferif (!(buffer = (UCHAR *)malloc(bytes_per_line*height)))   return(0);// copy image to work areamemcpy(buffer,image,bytes_per_line*height);// flip verticallyfor (index=0; index < height; index++)    memcpy(ℑ[((height-1) - index)*bytes_per_line], &buffer[index*bytes_per_line], bytes_per_line);// release the memoryfree(buffer);// return successreturn(1);} ///////////////////////End Flip_Bitmap()//////////////////////////////////////////////////LoadBitmapOnSurface()///////////////////////////LPDIRECTDRAWSURFACE7 LoadBitmapOnSurface(BITMAP_FILE bitmap,int red,int green,int blue){//LocalsLPDIRECTDRAWSURFACE7 lpdds_off = NULL;DDSURFACEDESC2  ddsd;//Color KeyDWORD color_key  = _RGB32BIT(255,red,green,blue);//clear out ddsdDDRAW_INIT_STRUCT(ddsd);// get bitmap dimensions    int surf_width  = bitmap.bitmapinfoheader.biWidth;    int surf_height = bitmap.bitmapinfoheader.biHeight;// create surface    HRESULT ddrval;   ZeroMemory(&ddsd,sizeof(ddsd));    ddsd.dwSize = sizeof(DDSURFACEDESC2);    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CKSRCBLT;    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;    ddsd.dwWidth = surf_width;    ddsd.dwHeight = surf_height;// attempt to create surface    ddrval=lpdd->CreateSurface(&ddsd,&lpdds_off,NULL);if (ddrval!=DD_OK) {   //If failure, Show MB    MessageBox(main_window_handle,    "FATAL ERROR:UNABLE TO CREATE OFFSCREEN SURFACE","DirectX Error Message", MB_OK);    lpdds_off= NULL;} //end if// copy the bitmap image to lpdds_off line by line    // lock the primary surface    lpdds_off->Lock(NULL,&ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);    // get video pointer to primary surfce    DWORD *primary_buffer = (DWORD *)ddsd.lpSurface; // process each line and copy it into the primary buffer    for (int index_y = 0; index_y < surf_height; index_y++){for (int index_x = 0; index_x < surf_width; index_x++){// get BGR values  UCHAR blue  = (bitmap.buffer[index_y*SCREEN_WIDTH*3 + index_x*3 + 0]),   green = (bitmap.buffer[index_y*SCREEN_WIDTH*3 + index_x*3 + 1]),   red   = (bitmap.buffer[index_y*SCREEN_WIDTH*3 + index_x*3 + 2]);  // this builds a 32 bit color value in A.8.8.8 format (8-bit alpha mode)  DWORD pixel = _RGB32BIT(0,red,green,blue);  // write the pixel  primary_buffer[index_x + (index_y*ddsd.lPitch >> 2)] = pixel;} // end for index_x    } // end for index_y    // now unlock the primary surface    if (FAILED(lpdds_off->Unlock(NULL)))    return(0);// set up the color key    DDCOLORKEY key;key.dwColorSpaceLowValue = color_key;    key.dwColorSpaceHighValue= color_key;    lpdds_off->SetColorKey(DDCKEY_SRCBLT,&key); return(lpdds_off);}///////////////////////////////End LoadBitmapOnSurface()//////////////////////////////////////////////////Blit_Object()///////////////////inline int Blit_Object(LPDIRECTDRAWSURFACE7 bmp_surface,   int dx, int dy, int dx2, int dy2,   HWND main_window_handle){ DDSURFACEDESC2 ddsd;RECT    blit_rect_dest,blit_rect_source;//Initialize ddsd   DDRAW_INIT_STRUCT(ddsd);   //gets surf desc bmp_surface->GetSurfaceDesc(&ddsd);//Dest rect is coord are passed to functionblit_rect_dest.left   = dx;blit_rect_dest.top    = dy;blit_rect_dest.right  = dx2 -1;    blit_rect_dest.bottom = dy2 -1;   //source is taken care of by the//BITMAP_INFO structblit_rect_source.left   = 0;    blit_rect_source.top    = 0;    blit_rect_source.right  = ddsd.dwWidth;    blit_rect_source.bottom = ddsd.dwHeight;    //Blt image to backbufferif(FAILED(lpddsback->Blt(&blit_rect_dest, bmp_surface, &blit_rect_source, (DDBLT_WAIT | DDBLT_KEYSRC),NULL))){MessageBox(main_window_handle,    "FATAL ERROR:UNABLE TO DRAW OBJECT","DirectX Error Message", MB_OK);return(0);} //end ifreturn(1);}///////////////////////End Blit_Object()/////////////////////////////////////////////Attach_Clipper()//////////////////////LPDIRECTDRAWCLIPPER Attach_Clipper(LPDIRECTDRAWSURFACE7 lpdds,int num_rects,LPRECT clip_list){//This function creates a clipper from the sent clip list and attaches    //it to the sent surface.    int index;// looping var    LPDIRECTDRAWCLIPPER lpddclipper;   // pointer to the newly created dd clipper    LPRGNDATA region_data;   // pointer to the region data that contains// the header and clip list    // first create the direct draw clipper    if (FAILED(lpdd->CreateClipper(0,&lpddclipper,NULL)))   return(NULL);    //Create the clip list from the sent data    //Allocate memory for region data    region_data = (LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+num_rects*sizeof(RECT));    //Copy the rects into region data    memcpy(region_data->Buffer, clip_list, sizeof(RECT)*num_rects);    //Set up fields of header    region_data->rdh.dwSize= sizeof(RGNDATAHEADER);    region_data->rdh.iType = RDH_RECTANGLES;    region_data->rdh.nCount= num_rects;    region_data->rdh.nRgnSize   = num_rects*sizeof(RECT);    region_data->rdh.rcBound.left    =  64000;    region_data->rdh.rcBound.top=  64000;    region_data->rdh.rcBound.right   = -64000;    region_data->rdh.rcBound.bottom  = -64000;    //Find bounds of all clipping regions    for (index=0; index<num_rects; index++){    // test if the next rectangle unioned with the current bound is larger    if (clip_list[index].left < region_data->rdh.rcBound.left)  region_data->rdh.rcBound.left = clip_list[index].left;    if (clip_list[index].right > region_data->rdh.rcBound.right)  region_data->rdh.rcBound.right = clip_list[index].right;    if (clip_list[index].top < region_data->rdh.rcBound.top)  region_data->rdh.rcBound.top = clip_list[index].top;    if (clip_list[index].bottom > region_data->rdh.rcBound.bottom)  region_data->rdh.rcBound.bottom = clip_list[index].bottom;    } // end for index   //Set the clipping list    if (FAILED(lpddclipper->SetClipList(region_data, 0)))    {    // release memory and return error    free(region_data);    return(NULL);    } // end if    //Attach the clipper to the surface    if (FAILED(lpdds->SetClipper(lpddclipper)))    {    // release memory and return error    free(region_data);    return(NULL);    } // end if    //Release memory and send back the pointer to the new clipper    free(region_data);return(lpddclipper);}//////////////////////////End Attach_Clipper()//////////////////////////
  You''ve got to bear in mind that there is an upper limit on what you can load in - it has to fit in video memory, after all, otherwise you can''t use it. So what video card do you have?I''d also recommend you not use malloc/free for very large memory objects. Look into VirtualAlloc/VirtualFree for your LoadBitmapFile function. ;  If your bitmaps are too big, either because of limited video memory or some DirectDraw restriction, then you''ll have to break them up.Load them into system memory, then create several smaller directdraw surfaces, each of which will contain a subset of the big image. Then when you''re drawing the bitmap, make sure that you draw each subset surface in the correct place.I had to do similar things for loading large textures into video memory on 4 mb graphics cards. ;  I believe that the size of your surfaces can''t be larger than the size of your backbuffer. I''m not a DirectDraw person, but I remember hearing that somewhere. ;  "I believe that the size of your surfaces can''t be larger than the size of your backbuffer. I''m not a DirectDraw person, but I remember hearing that somewhere." I can load 7 meg files. I think at 1024x768,32bpp- it takes up 2.2 megs for the back buffer. I think thats right. Correct me if Im wrong."If your bitmaps are too big, either because of limited video memory or some DirectDraw restriction, then you''ll have to break them up.Load them into system memory, then create several smaller directdraw surfaces, each of which will contain a subset of the big image. Then when you''re drawing the bitmap, make sure that you draw each subset surface in the correct place.I had to do similar things for loading large textures into video memory on 4 mb graphics cards." Interesting idea, I went the other way for my large program. I am creating and deleting surfaces as needed, but that leaves me wanting better performance. I will try your idea, though."You''ve got to bear in mind that there is an upper limit on what you can load in - it has to fit in video memory, after all, otherwise you can''t use it. So what video card do you have?I''d also recommend you not use malloc/free for very large memory objects. Look into VirtualAlloc/VirtualFree for your LoadBitmapFile function." Yes, I do know that much  I have a 64 meg video card. The above program is just something a threw together, I have not tuned it at all, memory wise. I will put large bitmaps on the heap. The problem with DirectDraw is not too many people actively use it   When I ask for advice, people have to search their memories. Nonetheless, thanks for the advice all. Any other input would be very much welcome.   ;  There IS a limit per card. And it varies between cards. Isn''t there a CAPS element for DirectDraw surfaces, just like there is for D3D textures? If not, just use the D3D texture values as hints for what might work on the card you''re running on. ;  Yeah even worse some cards (S3 notably, pretty much across all their cards) claim they can load (ie the create succeeds) large surfaces but when you try they actually give you a surface that''s 1024 wide. So You have to test a wide/tall surface once at startup to see if they are actually as wide/tall as they claim. I allocate one, populate it all black, then draw exactly one white row, if any white bleeds onto the next line then I know that the driver is lying to me. In general I would limit surfaces to less than 1024x1024 at the very most, however I saw something in the DirectDraw documentation stating that not all cards support surfaces wider than the primary surface.To answer your original question though is that in my particular case the way my engine deals with it is to mostly use its own renderer which doesnt put anything in video memory.This is the only way to get alpha effects (the ddbltfx struct options are mostly unimplemented) with DirectDraw and in general has more consistent performance. What you must absolutely not do though is switch back and forth between hardware and software, there is a huge stall when you do so.;  "What you must absolutely not do though is switch back and forth between hardware and software, there is a huge stall when you do so." Ill give you some background as to what Im doing. I started out with a map that was about 75 megs large. I broke it into 50 parts and was loading and deleting parts as needed. That gave very clunky performance, Im a big newb  Someone suggested earlier in the thread that I load the parts into RAM instead of video RAM. I coded for several hours this evening and got it to work without a hitch, and it is much smoother. I am happy, but at the same time my framerate hits a smooth, but low ceiling of 18fps. Is that what you mean by switching between hardware and software? It seems I have little choice with such a large map. Even funnier than that, messing around, I set my program to wait for 50ms at the end of end loop- heh, the framerate didnt change. It only starts to drop when I make it wait for 90ms. Is the CPU just waiting around for the RAM to get its business done?