PDA

View Full Version : Trying to create overlays with DirectX



sekelsenmat
21-06-2007, 11:19 AM
Hello,

I am trying to create a surface to draw overlays with DirectX, but it always fails on the CreateSurface function with the error $88760091, that according to my google search means Invalid Pixel Format.

But I tested lot's of different pixel formats and I can't find one that works. Any ideas? here is my code, thanks



function InitOverlays(vPluginData: TPluginData; var DebugInfo: Cardinal): Cardinal;
var
ddsd, ddsdOverlay: DDSURFACEDESC2;
ddrval: HRESULT;
capsDrv: TDDCaps;
pixelFormat: DDPIXELFORMAT;
begin
Result := VMG_DXFUNCTIONFAILED;
DebugInfo := 0;

{ Init DirectDraw }

ddrval := DirectDrawCreateEx(nil, g_lpdd, IID_IDirectDraw7, nil);
if ddrval <> DD_OK then
begin
DebugInfo &#58;= $1;
Exit;
end;

&#123; For NORMAL cooperative level we no longer need to provide an HWND &#125;

ddrval &#58;= g_lpdd.SetCooperativeLevel&#40;0, DDSCL_NORMAL&#41;;
if ddrval <> DD_OK then
begin
DebugInfo &#58;= $2;
Exit;
end;

if g_lpdd = nil then
begin
DebugInfo &#58;= $3;
Exit;
end;

&#123; Create the primary surface &#125;

FillChar&#40;ddsd, sizeof&#40;ddsd&#41;, #0&#41;;
ddsd.dwSize &#58;= sizeof&#40;ddsd&#41;;
ddsd.dwFlags &#58;= DDSD_CAPS;
ddsd.ddsCaps.dwCaps &#58;= DDSCAPS_PRIMARYSURFACE;
ddrval &#58;= g_lpdd.CreateSurface&#40;ddsd, g_lpddsPrimary, nil&#41;;

if ddrval <> DD_OK then
begin
DebugInfo &#58;= $4;
Exit;
end;

&#123; Get driver capabilities to determine Overlay support &#125;

FillChar&#40;capsDrv, sizeof&#40;capsDrv&#41;, #0&#41;;
capsDrv.dwSize &#58;= sizeof&#40;capsDrv&#41;;
ddrval &#58;= g_lpdd.GetCaps&#40;@capsDrv, nil&#41;;

if ddrval <> DD_OK then
begin
DebugInfo &#58;= $5;
Exit;
end;

&#123; Does the driver support overlays in the current mode?
&#40;Currently the DirectDraw emulation layer does not support overlays.
Overlay related APIs will fail without hardware support&#41; &#125;

Result &#58;= VMG_NOSUPPORTFOROVERLAYS;

if &#40;capsDrv.dwCaps and DDCAPS_OVERLAY&#41; = 0 then
begin
DebugInfo &#58;= $B;
Exit;
end;

&#123; Setup the overlay surface &#125;

FillChar&#40;ddsdOverlay, sizeof&#40;ddsdOverlay&#41;, #0&#41;;
ddsdOverlay.dwSize &#58;= sizeof&#40;ddsdOverlay&#41;;
ddsdOverlay.dwFlags &#58;= DDSD_CAPS or DDSD_HEIGHT or DDSD_WIDTH or DDSD_PIXELFORMAT;
ddsdOverlay.dwBackBufferCount &#58;= 0;
ddsdOverlay.dwWidth &#58;= vPluginData.DesktopWidth;
ddsdOverlay.dwHeight &#58;= vPluginData.DesktopHeight;
ddsdOverlay.ddsCaps.dwCaps &#58;= DDSCAPS_OVERLAY or DDSCAPS_VIDEOMEMORY;

pixelFormat.dwSize &#58;= SizeOf&#40;pixelFormat&#41;;
pixelFormat.dwFlags &#58;= DDPF_RGB;
pixelFormat.dwFourCC &#58;= 0;
pixelFormat.dwRGBBitCount &#58;= 32;
pixelFormat.dwRBitMask &#58;= $00FF0000;
pixelFormat.dwGBitMask &#58;= $0000FF00;
pixelFormat.dwBBitMask &#58;= $000000FF;
pixelFormat.dwRGBAlphaBitMask &#58;= $00000000;

// TODO&#58; should match the screen output color depth
//DDPIXELFORMAT pixelFormat =
// &#123;sizeof&#40;DDPIXELFORMAT&#41;, DDPF_RGB, 0, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0&#125;;
ddsdOverlay.ddpfPixelFormat &#58;= pixelFormat;
ddrval &#58;= g_lpdd.CreateSurface&#40;ddsdOverlay, g_lpddsOverlay, nil&#41;;

if ddrval <> DD_OK then //// Will enter this block, so here is the failure
begin
DebugInfo &#58;= ddrval;
Exit;
end;

if &#40;g_lpddsOverlay = nil&#41; then
begin
DebugInfo &#58;= $D;
Exit;
end;

// mPrimaryMonitorRect &#58;= System&#58;&#58;getPrimaryMonitorRect&#40;&#41;;

Result &#58;= VMG_NOERROR;
end;

sekelsenmat
23-06-2007, 03:39 PM
After lot's and lot's of hours researching and testing and debuging I found out that my Video Card doesnt support RGB modes for overlays, only YUV modes

Here is a trvial program that works correctly with overlays:



program overlay;

&#123;$mode objfpc&#125;&#123;$H+&#125;

uses
Classes, SysUtils,
Windows, DirectDraw;

&#123; Global Variables &#125;
var
&#123; DirectX variables &#125;
g_lpdd&#58; IDirectDraw7 = nil;
g_lpddsPrimary&#58; IDirectDrawSurface7 = nil;
g_lpddsOverlay&#58; IDirectDrawSurface7 = nil;
g_lpClipper&#58; IDirectDrawClipper = nil;

mTimerID&#58; THandle = 0;

DebugLoc, DebugInfo&#58; Cardinal;

ddrval&#58; HRESULT;

&#123;************************************************* ******************
* InitOverlays &#40;&#41;
************************************************** *****************&#125;
function InitOverlays&#58; Boolean;
var
ddsd, ddsdOverlay&#58; DDSURFACEDESC2;
capsDrv&#58; TDDCaps;
pixelFormat&#58; DDPIXELFORMAT;
begin
Result &#58;= False;
DebugInfo &#58;= 0;
DebugLoc &#58;= 0;

&#123; Init DirectDraw &#125;

ddrval &#58;= DirectDrawCreateEx&#40;nil, g_lpdd, IID_IDirectDraw7, nil&#41;;
if ddrval <> DD_OK then
begin
DebugLoc &#58;= $1;
Exit;
end;

&#123; For NORMAL cooperative level we no longer need to provide an HWND &#125;

ddrval &#58;= g_lpdd.SetCooperativeLevel&#40;0, DDSCL_NORMAL&#41;;
if ddrval <> DD_OK then
begin
DebugLoc &#58;= $2;
Exit;
end;

if g_lpdd = nil then
begin
DebugLoc &#58;= $3;
Exit;
end;

&#123; Create the primary surface &#125;

FillChar&#40;ddsd, sizeof&#40;ddsd&#41;, #0&#41;;
ddsd.dwSize &#58;= sizeof&#40;ddsd&#41;;
ddsd.dwFlags &#58;= DDSD_CAPS;
ddsd.ddsCaps.dwCaps &#58;= DDSCAPS_PRIMARYSURFACE;
ddrval &#58;= g_lpdd.CreateSurface&#40;ddsd, g_lpddsPrimary, nil&#41;;

if ddrval <> DD_OK then
begin
DebugLoc &#58;= $4;
Exit;
end;

&#123; Get driver capabilities to determine Overlay support &#125;

FillChar&#40;capsDrv, sizeof&#40;capsDrv&#41;, #0&#41;;
capsDrv.dwSize &#58;= sizeof&#40;capsDrv&#41;;
ddrval &#58;= g_lpdd.GetCaps&#40;@capsDrv, nil&#41;;

if ddrval <> DD_OK then
begin
DebugLoc &#58;= $5;
Exit;
end;

&#123; Does the driver support overlays in the current mode?
&#40;Currently the DirectDraw emulation layer does not support overlays.
Overlay related APIs will fail without hardware support&#41; &#125;

if &#40;capsDrv.dwCaps and DDCAPS_OVERLAY&#41; = 0 then
begin
DebugLoc &#58;= $B;
Exit;
end;

&#123; Setup the overlay surface &#125;

&#123; Init Direct3D &#125;

FillChar&#40;ddsdOverlay, sizeof&#40;ddsdOverlay&#41;, #0&#41;;
ddsdOverlay.dwSize &#58;= sizeof&#40;ddsdOverlay&#41;;
ddsdOverlay.dwFlags &#58;= DDSD_CAPS or DDSD_HEIGHT or DDSD_WIDTH or DDSD_PIXELFORMAT;
ddsdOverlay.dwBackBufferCount &#58;= 0;
ddsdOverlay.dwWidth &#58;= 800;
ddsdOverlay.dwHeight &#58;= 720;
ddsdOverlay.ddsCaps.dwCaps &#58;= DDSCAPS_OVERLAY or DDSCAPS_VIDEOMEMORY;

pixelFormat.dwSize &#58;= SizeOf&#40;pixelFormat&#41;;
PixelFormat.dwFlags &#58;= DDPF_FOURCC;
PixelFormat.dwFourCC &#58;= DWORD&#40;Byte&#40;'U'&#41; or &#40;Byte&#40;'Y'&#41; shl 8&#41; or &#40;Byte&#40;'V'&#41; shl 16&#41; or &#40;Byte&#40;'Y'&#41; shl 24&#41;&#41;;
PixelFormat.dwYUVBitCount &#58;= 16;

&#123; pixelFormat.dwFlags &#58;= DDPF_RGBTOYUV;
pixelFormat.dwFourCC &#58;= 0; &#125;

&#123; pixelFormat.dwRGBBitCount &#58;= 16;
pixelFormat.dwRBitMask &#58;= $7C00;
pixelFormat.dwGBitMask &#58;= $03E0;
pixelFormat.dwBBitMask &#58;= $001F; &#125;

&#123; pixelFormat.dwRgbBitCount &#58;= 16;
pixelFormat.dwRBitMask &#58;= $F800;
pixelFormat.dwGBitMask &#58;= $07E0;
pixelFormat.dwBBitMask &#58;= $001F; &#125;

&#123; pixelFormat.dwRGBBitCount &#58;= 32;
pixelFormat.dwRBitMask &#58;= $000000FF;
pixelFormat.dwGBitMask &#58;= $0000FF00;
pixelFormat.dwBBitMask &#58;= $00FF0000; &#125;

// TODO&#58; should match the screen output color depth
//DDPIXELFORMAT pixelFormat =
// &#123;sizeof&#40;DDPIXELFORMAT&#41;, DDPF_RGB, 0, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0&#125;;
ddsdOverlay.ddpfPixelFormat &#58;= pixelFormat;
ddrval &#58;= g_lpdd.CreateSurface&#40;ddsdOverlay, g_lpddsOverlay, nil&#41;;

if ddrval <> DD_OK then
begin
DebugLoc &#58;= $C;
DebugInfo &#58;= ddrval;
Exit;
end;

if &#40;g_lpddsOverlay = nil&#41; then
begin
DebugLoc &#58;= $D;
Exit;
end;

&#123; Create a clipper for our window &#125;
ddrval &#58;= g_lpdd.CreateClipper&#40;0, g_lpClipper, nil&#41;;
if ddrval <> DD_OK then
begin
DebugLoc &#58;= $E;
Exit;
end;

// ddrval = IDirectDrawClipper_SetHWnd&#40;lpClipper, 0, hwnd&#41;;

Result &#58;= True;
end;

function WndProc&#40;ahWnd&#58; HWND; amessage&#58; UINT; awParam&#58; WPARAM; alParam&#58; LPARAM&#41;&#58; LResult; stdcall;
var
wmId, wmEvent&#58; Integer;
ps&#58; PAINTSTRUCT;
MyDC&#58; HDC;
ptClient&#58; POINT;
rectBlt&#58; RECT;
addbfx&#58; DDBltFX;
begin
Result &#58;= 0;

case amessage of
WM_PAINT&#58;
begin
&#123; Attach the clipper to the primary surface for this operation &#125;

// ddrval &#58;= g_lpddsPrimary.SetClipper&#40;g_lpClipper&#41;;

MyDC &#58;= BeginPaint&#40;ahWnd, @ps&#41;;

&#123; Fill the client area with colour key &#125;

ptClient.x &#58;= ps.rcPaint.left;
ptClient.y &#58;= ps.rcPaint.top;
ClientToScreen&#40;GetDesktopWindow, @ptClient&#41;;
rectBlt.left &#58;= ptClient.x;
rectBlt.top &#58;= ptClient.y;

ptClient.x &#58;= ps.rcPaint.right;
ptClient.y &#58;= ps.rcPaint.bottom;
ClientToScreen&#40;GetDesktopWindow, @ptClient&#41;;
rectBlt.right &#58;= ptClient.x;
rectBlt.bottom &#58;= ptClient.y;

addbfx.dwSize &#58;= sizeof&#40;DDBLTFX&#41;;
addbfx.dwFillColor &#58;= 0;

g_lpddsPrimary.Blt&#40;
@rectBlt, nil, @rectBlt, DDBLT_COLORFILL or DDBLT_WAIT, @addbfx&#41;;

EndPaint&#40;ahWnd, @ps&#41;;

// ddrval &#58;= g_lpddsPrimary.SetClipper&#40;nil&#41;;
end;

WM_DESTROY&#58;
PostQuitMessage&#40;0&#41;;
else
Result &#58;= DefWindowProc&#40;ahWnd, amessage, awParam, alParam&#41;;
end;
end;

procedure CreateMainWindow;
var
wcex&#58; WNDCLASSEX;
ahwnd&#58; HWND;
begin
FillChar&#40;wcex, sizeof&#40;wcex&#41;, #0&#41;;
wcex.cbSize &#58;= sizeof&#40;WNDCLASSEX&#41;;

wcex.style &#58;= CS_HREDRAW or CS_VREDRAW;
wcex.lpfnWndProc &#58;= @WndProc;
wcex.cbClsExtra &#58;= 0;
wcex.cbWndExtra &#58;= 0;
wcex.hInstance &#58;= hInstance;
// wcex.hIcon &#58;= LoadIcon&#40;hInstance, MAKEINTRESOURCE&#40;IDI_OVERLAY&#41;&#41;;
wcex.hCursor &#58;= LoadCursor&#40;0, IDC_ARROW&#41;;
wcex.hbrBackground &#58;= &#40;COLOR_WINDOW+1&#41;;
wcex.lpszClassName &#58;= 'OVERLAYS';
// wcex.hIconSm &#58;= LoadIcon&#40;wcex.hInstance, MAKEINTRESOURCE&#40;IDI_SMALL&#41;&#41;;

RegisterClassEx&#40;@wcex&#41;;

ahWnd &#58;= CreateWindow&#40;'OVERLAYS', 'Titulo', WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, 0, 0, hInstance, nil&#41;;

ShowWindow&#40;ahWnd, SW_SHOWNORMAL&#41;;
UpdateWindow&#40;ahWnd&#41;;
end;

procedure ShowError;
begin
Windows.MessageBox&#40;0, PChar&#40;'Loc&#58; ' + IntToHex&#40;DebugLoc, 8&#41; + ' Info&#58; ' + IntToHex&#40;DebugInfo, 8&#41;&#41;, 'Titulo', MB_ICONEXCLAMATION + MB_OK&#41;;
end;

var
Msg&#58; TMsg;
begin
if not InitOverlays&#40;&#41; then ShowError;

CreateMainWindow&#40;&#41;;

while Windows.GetMessage&#40;@Msg, 0, 0, 0&#41; do
begin
Windows.TranslateMessage&#40;@msg&#41;;
Windows.DispatchMessage&#40;@msg&#41;;
end;
end.

technomage
23-06-2007, 08:22 PM
Well done on solving the problem. Thanks for posting a demo app :D