12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193 |
- //
- // The graphics engine GLXEngine. The unit of GXScene for Delphi
- //
- unit GXS.WinContext;
- (* Cross-platform context. *)
- interface
- {$I Stage.Defines.inc}
- uses
- Winapi.Windows,
- Winapi.Messages,
- System.SysUtils,
- System.Classes,
- FMX.Forms,
- FMX.Dialogs,
- FMX.Platform.Win,
- GXS.Context,
- GXS.State,
- Stage.OpenGL4,
- Stage.Strings,
- Stage.VectorGeometry;
- type
- // A context driver for standard Windows OpenGL
- TgxWinContext = class(TgxContext)
- protected
- FDC: HDC;
- FRC: HGLRC;
- FShareContext: TgxWinContext;
- FHPBUFFER: Integer;
- FiAttribs: packed array of Integer;
- FfAttribs: packed array of Single;
- FLegacyContextsOnly: Boolean;
- FSwapBufferSupported: Boolean;
- procedure SpawnLegacyContext(aDC: HDC); // used for WGL_pixel_format soup
- procedure CreateOldContext(aDC: HDC); virtual;
- procedure CreateNewContext(aDC: HDC); virtual;
- procedure ClearIAttribs;
- procedure AddIAttrib(attrib, value: Integer);
- procedure ChangeIAttrib(attrib, newValue: Integer);
- procedure DropIAttrib(attrib: Integer);
- procedure ClearFAttribs;
- procedure AddFAttrib(attrib, value: Single);
- procedure DestructionEarlyWarning(sender: TObject);
- procedure ChooseWGLFormat(DC: HDC; nMaxFormats: Cardinal; piFormats: PInteger; var nNumFormats: Integer;
- BufferCount: Integer = 1);
- procedure DoCreateContext(ADeviceHandle: THandle); override;
- procedure DoCreateMemoryContext(OutputDevice: THandle; Width, Height: Integer; BufferCount: Integer); override;
- function DoShareLists(aContext: TgxContext): Boolean; override;
- procedure DoDestroyContext; override;
- procedure DoActivate; override;
- procedure DoDeactivate; override;
- (* DoGetHandles must be implemented in child classes,
- and return the display + window *)
- public
- constructor Create; override;
- destructor Destroy; override;
- function IsValid: Boolean; override;
- procedure SwapBuffers; override;
- function RenderOutputDevice: Pointer; override;
- property DC: HDC read FDC;
- property RC: HGLRC read FRC;
- end;
- function CreateTempWnd: HWND;
- var
- (* This boolean controls a hook-based tracking of top-level forms destruction,
- with the purpose of being able to properly release OpenGL contexts before
- they are (improperly) released by some drivers upon top-level form
- destruction. *)
- vUseWindowTrackingHook: Boolean = True;
- implementation // ------------------------------------------------------------
- var
- vTrackingCount: Integer;
- vTrackedHwnd: array of HWND;
- vTrackedEvents: array of TNotifyEvent;
- vTrackingHook: HHOOK;
- function TrackHookProc(nCode: Integer; wParam: wParam; lParam: lParam): Integer; stdcall;
- var
- i: Integer;
- p: PCWPStruct;
- begin
- if nCode = HC_ACTION then
- begin
- p := PCWPStruct(lParam);
- // if (p.message=WM_DESTROY) or (p.message=WM_CLOSE) then begin // destroy & close variant
- if p.message = WM_DESTROY then
- begin
- // special care must be taken by this loop, items may go away unexpectedly
- i := vTrackingCount - 1;
- while i >= 0 do
- begin
- if IsChild(p.HWND, vTrackedHwnd[i]) then
- begin
- // got one, send notification
- vTrackedEvents[i](nil);
- end;
- Dec(i);
- while i >= vTrackingCount do
- Dec(i);
- end;
- end;
- CallNextHookEx(vTrackingHook, nCode, wParam, lParam);
- Result := 0;
- end
- else
- Result := CallNextHookEx(vTrackingHook, nCode, wParam, lParam);
- end;
- procedure TrackWindow(h: HWND; notifyEvent: TNotifyEvent);
- begin
- if not IsWindow(h) then
- Exit;
- if vTrackingCount = 0 then
- vTrackingHook := SetWindowsHookEx(WH_CALLWNDPROC, @TrackHookProc, 0, GetCurrentThreadID);
- Inc(vTrackingCount);
- SetLength(vTrackedHwnd, vTrackingCount);
- vTrackedHwnd[vTrackingCount - 1] := h;
- SetLength(vTrackedEvents, vTrackingCount);
- vTrackedEvents[vTrackingCount - 1] := notifyEvent;
- end;
- procedure UnTrackWindow(h: HWND);
- var
- i, k: Integer;
- begin
- if not IsWindow(h) then
- Exit;
- if vTrackingCount = 0 then
- Exit;
- k := 0;
- for i := 0 to MinInteger(vTrackingCount, Length(vTrackedHwnd)) - 1 do
- begin
- if vTrackedHwnd[i] <> h then
- begin
- if (k <> i) then
- begin
- vTrackedHwnd[k] := vTrackedHwnd[i];
- vTrackedEvents[k] := vTrackedEvents[i];
- end;
- Inc(k);
- end
- end;
- if (k >= vTrackingCount) then
- Exit;
- Dec(vTrackingCount);
- SetLength(vTrackedHwnd, vTrackingCount);
- SetLength(vTrackedEvents, vTrackingCount);
- if vTrackingCount = 0 then
- UnhookWindowsHookEx(vTrackingHook);
- end;
- var
- vUtilWindowClass: TWndClass = (style: 0; lpfnWndProc: @DefWindowProc;
- cbClsExtra: 0; cbWndExtra: 0; hInstance: 0; hIcon: 0;
- hCursor: 0; hbrBackground: 0; lpszMenuName: nil; lpszClassName: 'GXSUtilWindow');
- function CreateTempWnd: HWND;
- var
- classRegistered: Boolean;
- tempClass: TWndClass;
- begin
- vUtilWindowClass.hInstance := hInstance;
- classRegistered := GetClassInfo(hInstance, vUtilWindowClass.lpszClassName, tempClass);
- if not classRegistered then
- /// RegisterClass(vUtilWindowClass) - to do for FMX ;
- Result := CreateWindowEx(WS_EX_TOOLWINDOW, vUtilWindowClass.lpszClassName, '', WS_POPUP, 0, 0, 0, 0, 0, 0, hInstance, nil);
- end;
- // ------------------
- // ------------------ TgxSceneContext ------------------
- // ------------------
- constructor TgxWinContext.Create;
- begin
- inherited Create;
- ClearIAttribs;
- ClearFAttribs;
- end;
- destructor TgxWinContext.Destroy;
- begin
- inherited Destroy;
- end;
- function SetupPalette(DC: HDC; PFD: TPixelFormatDescriptor): HPalette;
- var
- nColors, i: Integer;
- LogPalette: TMaxLogPalette;
- RedMask, GreenMask, BlueMask: Byte;
- begin
- nColors := 1 shl PFD.cColorBits;
- LogPalette.palVersion := $300;
- LogPalette.palNumEntries := nColors;
- RedMask := (1 shl PFD.cRedBits) - 1;
- GreenMask := (1 shl PFD.cGreenBits) - 1;
- BlueMask := (1 shl PFD.cBlueBits) - 1;
- with LogPalette, PFD do
- for i := 0 to nColors - 1 do
- begin
- palPalEntry[i].peRed := (((i shr cRedShift) and RedMask) * 255) div RedMask;
- palPalEntry[i].peGreen := (((i shr cGreenShift) and GreenMask) * 255) div GreenMask;
- palPalEntry[i].peBlue := (((i shr cBlueShift) and BlueMask) * 255) div BlueMask;
- palPalEntry[i].peFlags := 0;
- end;
- Result := CreatePalette(PLogPalette(@LogPalette)^);
- if Result <> 0 then
- begin
- SelectPalette(DC, Result, False);
- RealizePalette(DC);
- end
- else
- RaiseLastOSError;
- end;
- procedure TgxWinContext.ClearIAttribs;
- begin
- SetLength(FiAttribs, 1);
- FiAttribs[0] := 0;
- end;
- procedure TgxWinContext.AddIAttrib(attrib, value: Integer);
- var
- n: Integer;
- begin
- n := Length(FiAttribs);
- SetLength(FiAttribs, n + 2);
- FiAttribs[n - 1] := attrib;
- FiAttribs[n] := value;
- FiAttribs[n + 1] := 0;
- end;
- procedure TgxWinContext.ChangeIAttrib(attrib, newValue: Integer);
- var
- i: Integer;
- begin
- i := 0;
- while i < Length(FiAttribs) do
- begin
- if FiAttribs[i] = attrib then
- begin
- FiAttribs[i + 1] := newValue;
- Exit;
- end;
- Inc(i, 2);
- end;
- AddIAttrib(attrib, newValue);
- end;
- procedure TgxWinContext.DropIAttrib(attrib: Integer);
- var
- i: Integer;
- begin
- i := 0;
- while i < Length(FiAttribs) do
- begin
- if FiAttribs[i] = attrib then
- begin
- Inc(i, 2);
- while i < Length(FiAttribs) do
- begin
- FiAttribs[i - 2] := FiAttribs[i];
- Inc(i);
- end;
- SetLength(FiAttribs, Length(FiAttribs) - 2);
- Exit;
- end;
- Inc(i, 2);
- end;
- end;
- procedure TgxWinContext.ClearFAttribs;
- begin
- SetLength(FfAttribs, 1);
- FfAttribs[0] := 0;
- end;
- procedure TgxWinContext.AddFAttrib(attrib, value: Single);
- var
- n: Integer;
- begin
- n := Length(FfAttribs);
- SetLength(FfAttribs, n + 2);
- FfAttribs[n - 1] := attrib;
- FfAttribs[n] := value;
- FfAttribs[n + 1] := 0;
- end;
- procedure TgxWinContext.DestructionEarlyWarning(sender: TObject);
- begin
- if IsValid then
- DestroyContext;
- end;
- procedure TgxWinContext.ChooseWGLFormat(DC: HDC; nMaxFormats: Cardinal; piFormats: PInteger; var nNumFormats: Integer;
- BufferCount: Integer);
- const
- cAAToSamples: array [aaNone .. csa16xHQ] of Integer = (1, 2, 2, 4, 4, 6, 8, 16, 8, 8, 16, 16);
- cCSAAToSamples: array [csa8x .. csa16xHQ] of Integer = (4, 8, 4, 8);
- procedure ChoosePixelFormat;
- begin
- if not wglChoosePixelFormatARB(DC, @FiAttribs[0], @FfAttribs[0], 32, PGLint(piFormats), @nNumFormats) then
- nNumFormats := 0;
- end;
- var
- float: Boolean;
- aa: TgxAntiAliasing;
- begin
- // request hardware acceleration
- case FAcceleration of
- chaUnknown:
- AddIAttrib(WGL_ACCELERATION_ARB, WGL_GENERIC_ACCELERATION_ARB);
- chaHardware:
- AddIAttrib(WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB);
- chaSoftware:
- AddIAttrib(WGL_ACCELERATION_ARB, WGL_NO_ACCELERATION_ARB);
- end;
- float := (ColorBits = 64) or (ColorBits = 128); // float_type
- if float then
- begin // float_type
- if WGL_ATI_pixel_format_float then
- begin // NV40 uses ATI_float, with linear filtering
- AddIAttrib(WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_FLOAT_ATI);
- end
- else
- begin
- AddIAttrib(WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB);
- AddIAttrib(WGL_FLOAT_COMPONENTS_NV, GL_TRUE);
- end;
- end;
- if BufferCount > 1 then
- // 1 front buffer + (BufferCount-1) aux buffers
- AddIAttrib(WGL_AUX_BUFFERS_ARB, BufferCount - 1);
- AddIAttrib(WGL_COLOR_BITS_ARB, ColorBits);
- if AlphaBits > 0 then
- AddIAttrib(WGL_ALPHA_BITS_ARB, AlphaBits);
- AddIAttrib(WGL_DEPTH_BITS_ARB, DepthBits);
- if StencilBits > 0 then
- AddIAttrib(WGL_STENCIL_BITS_ARB, StencilBits);
- if AccumBits > 0 then
- AddIAttrib(WGL_ACCUM_BITS_ARB, AccumBits);
- if AuxBuffers > 0 then
- AddIAttrib(WGL_AUX_BUFFERS_ARB, AuxBuffers);
- if (AntiAliasing <> aaDefault) and WGL_ARB_multisample then
- begin
- if AntiAliasing = aaNone then
- AddIAttrib(WGL_SAMPLE_BUFFERS_ARB, GL_FALSE)
- else
- begin
- AddIAttrib(WGL_SAMPLE_BUFFERS_ARB, GL_TRUE);
- AddIAttrib(WGL_SAMPLES_ARB, cAAToSamples[AntiAliasing]);
- if (AntiAliasing >= csa8x) and (AntiAliasing <= csa16xHQ) then
- AddIAttrib(WGL_COLOR_SAMPLES_NV, cCSAAToSamples[AntiAliasing]);
- end;
- end;
- ClearFAttribs;
- ChoosePixelFormat;
- if (nNumFormats = 0) and (DepthBits >= 32) then
- begin
- // couldn't find 32+ bits depth buffer, 24 bits one available?
- ChangeIAttrib(WGL_DEPTH_BITS_ARB, 24);
- ChoosePixelFormat;
- end;
- if (nNumFormats = 0) and (DepthBits >= 24) then
- begin
- // couldn't find 24+ bits depth buffer, 16 bits one available?
- ChangeIAttrib(WGL_DEPTH_BITS_ARB, 16);
- ChoosePixelFormat;
- end;
- if (nNumFormats = 0) and (ColorBits >= 24) then
- begin
- // couldn't find 24+ bits color buffer, 16 bits one available?
- ChangeIAttrib(WGL_COLOR_BITS_ARB, 16);
- ChoosePixelFormat;
- end;
- if (nNumFormats = 0) and (AntiAliasing <> aaDefault) then
- begin
- // Restore DepthBits
- ChangeIAttrib(WGL_DEPTH_BITS_ARB, DepthBits);
- if (AntiAliasing >= csa8x) and (AntiAliasing <= csa16xHQ) then
- begin
- DropIAttrib(WGL_COLOR_SAMPLES_NV);
- case AntiAliasing of
- csa8x, csa8xHQ:
- AntiAliasing := aa8x;
- csa16x, csa16xHQ:
- AntiAliasing := aa16x;
- end;
- ChangeIAttrib(WGL_SAMPLES_ARB, cAAToSamples[AntiAliasing]);
- end;
- ChoosePixelFormat;
- if nNumFormats = 0 then
- begin
- aa := AntiAliasing;
- repeat
- Dec(aa);
- if aa = aaNone then
- begin
- // couldn't find AA buffer, try without
- DropIAttrib(WGL_SAMPLE_BUFFERS_ARB);
- DropIAttrib(WGL_SAMPLES_ARB);
- ChoosePixelFormat;
- break;
- end;
- ChangeIAttrib(WGL_SAMPLES_ARB, cAAToSamples[aa]);
- ChoosePixelFormat;
- until nNumFormats <> 0;
- AntiAliasing := aa;
- end;
- end;
- // Check DepthBits again
- if (nNumFormats = 0) and (DepthBits >= 32) then
- begin
- // couldn't find 32+ bits depth buffer, 24 bits one available?
- ChangeIAttrib(WGL_DEPTH_BITS_ARB, 24);
- ChoosePixelFormat;
- end;
- if (nNumFormats = 0) and (DepthBits >= 24) then
- begin
- // couldn't find 24+ bits depth buffer, 16 bits one available?
- ChangeIAttrib(WGL_DEPTH_BITS_ARB, 16);
- ChoosePixelFormat;
- end;
- if (nNumFormats = 0) and (ColorBits >= 24) then
- begin
- // couldn't find 24+ bits color buffer, 16 bits one available?
- ChangeIAttrib(WGL_COLOR_BITS_ARB, 16);
- ChoosePixelFormat;
- end;
- if nNumFormats = 0 then
- begin
- // ok, last attempt: no AA, restored depth and color,
- // relaxed hardware-acceleration request
- ChangeIAttrib(WGL_COLOR_BITS_ARB, ColorBits);
- ChangeIAttrib(WGL_DEPTH_BITS_ARB, DepthBits);
- DropIAttrib(WGL_ACCELERATION_ARB);
- ChoosePixelFormat;
- end;
- end;
- procedure TgxWinContext.CreateOldContext(aDC: HDC);
- begin
- if not FLegacyContextsOnly then
- begin
- case Layer of
- clUnderlay2: FRC := wglCreateLayerContext(aDC, -2);
- clUnderlay1: FRC := wglCreateLayerContext(aDC, -1);
- clMainPlane: FRC := wglCreateContext(aDC);
- clOverlay1: FRC := wglCreateLayerContext(aDC, 1);
- clOverlay2: FRC := wglCreateLayerContext(aDC, 2);
- end;
- end
- else
- FRC := wglCreateContext(aDC);
- if FRC = 0 then
- RaiseLastOSError;
- FDC := aDC;
- if not wglMakeCurrent(FDC, FRC) then
- raise EVXContext.Create(Format(strContextActivationFailed, [GetLastError, SysErrorMessage(GetLastError)]));
- if not FLegacyContextsOnly then
- begin
- if Assigned(FShareContext) and (FShareContext.RC <> 0) then
- begin
- if not wglShareLists(FShareContext.RC, FRC) then
- {$IFDEF USE_LOGGING}
- GLSLogger.LogWarning(strFailedToShare)
- {$ENDIF}
- else
- begin
- FSharedContexts.Add(FShareContext);
- PropagateSharedContext;
- end;
- end;
- //DebugMode := False;
- ReadExtensions(); //FGL.Initialize;
- MakeGLCurrent;
- // If we are using AntiAliasing, adjust filtering hints
- if AntiAliasing in [aa2xHQ, aa4xHQ, csa8xHQ, csa16xHQ] then
- // Hint for nVidia HQ modes (Quincunx etc.)
- gxStates.MultisampleFilterHint := hintNicest
- else
- gxStates.MultisampleFilterHint := hintDontCare;
- if rcoDebug in Options then
- ShowMessage(strDriverNotSupportDebugRC);
- if rcoOGL_ES in Options then
- ShowMessage(strDriverNotSupportOESRC);
- if gxStates.ForwardContext then
- ShowMessage(strDriverNotSupportFRC);
- gxStates.ForwardContext := False;
- end
- else
- ShowMessage(strTmpRC_Created);
- end;
- procedure TgxWinContext.CreateNewContext(aDC: HDC);
- var
- bSuccess, bOES: Boolean;
- begin
- bSuccess := False;
- bOES := False;
- try
- ClearIAttribs;
- // Initialize forward context
- if False { gxStates.ForwardContext } then
- begin
- if GL_VERSION_4_2 then
- begin
- AddIAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, 4);
- AddIAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, 2);
- end
- else if GL_VERSION_4_1 then
- begin
- AddIAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, 4);
- AddIAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, 1);
- end
- else if GL_VERSION_4_0 then
- begin
- AddIAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, 4);
- AddIAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, 0);
- end
- else
- Abort;
- AddIAttrib(WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB);
- if rcoOGL_ES in Options then
- ShowMessage(strOESvsForwardRC);
- end
- else if rcoOGL_ES in Options then
- begin
- if WGL_EXT_create_context_es2_profile then
- begin
- AddIAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, 2);
- AddIAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, 0);
- AddIAttrib(WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_ES2_PROFILE_BIT_EXT);
- bOES := True;
- end
- else
- ShowMessage(strDriverNotSupportOESRC);
- end;
- if rcoDebug in Options then
- begin
- AddIAttrib(WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB);
- ///DebugMode := True;
- end;
- case Layer of
- clUnderlay2: AddIAttrib(WGL_CONTEXT_LAYER_PLANE_ARB, -2);
- clUnderlay1: AddIAttrib(WGL_CONTEXT_LAYER_PLANE_ARB, -1);
- clOverlay1: AddIAttrib(WGL_CONTEXT_LAYER_PLANE_ARB, 1);
- clOverlay2: AddIAttrib(WGL_CONTEXT_LAYER_PLANE_ARB, 2);
- end;
- FRC := 0;
- if Assigned(FShareContext) then
- begin
- FRC := wglCreateContextAttribsARB(aDC, FShareContext.RC, @FiAttribs[0]);
- if FRC <> 0 then
- begin
- FSharedContexts.Add(FShareContext);
- PropagateSharedContext;
- end
- else
- ShowMessage(strFailedToShare)
- end;
- if FRC = 0 then
- begin
- FRC := wglCreateContextAttribsARB(aDC, 0, @FiAttribs[0]);
- if FRC = 0 then
- begin
- if gxStates.ForwardContext then
- ShowMessage(Format(strForwardContextFailed,
- [GetLastError, SysErrorMessage(GetLastError)]))
- else
- ShowMessage(Format(strBackwardContextFailed,
- [GetLastError, SysErrorMessage(GetLastError)]));
- Abort;
- end;
- end;
- FDC := aDC;
- if not wglMakeCurrent(FDC, FRC) then
- begin
- ShowMessage(Format(strContextActivationFailed, [GetLastError, SysErrorMessage(GetLastError)]));
- Abort;
- end;
- InitOpenGL; ///FGL.Initialize;
- MakeGLCurrent;
- // If we are using AntiAliasing, adjust filtering hints
- if AntiAliasing in [aa2xHQ, aa4xHQ, csa8xHQ, csa16xHQ] then
- // Hint for nVidia HQ modes (Quincunx etc.)
- gxStates.MultisampleFilterHint := hintNicest
- else
- gxStates.MultisampleFilterHint := hintDontCare;
- if gxStates.ForwardContext then
- ShowMessage(strFRC_created);
- if bOES then
- ShowMessage(strOESRC_created);
- bSuccess := True;
- finally
- gxStates.ForwardContext := gxStates.ForwardContext and bSuccess;
- PipelineTransformation.LoadMatricesEnabled := not gxStates.ForwardContext;
- end;
- end;
- procedure TgxWinContext.DoCreateContext(ADeviceHandle: THandle);
- const
- cMemoryDCs = [OBJ_MEMDC, OBJ_METADC, OBJ_ENHMETADC];
- cBoolToInt: array [False .. True] of Integer = (GL_FALSE, GL_TRUE);
- cLayerToSet: array [TgxContextLayer] of Byte = (32, 16, 0, 1, 2);
- var
- pfDescriptor: TPixelFormatDescriptor;
- pixelFormat, nbFormats, softwarePixelFormat: Integer;
- aType: DWORD;
- iFormats: array [0 .. 31] of Integer;
- tempWnd: HWND;
- tempDC: HDC;
- localDC: HDC;
- localRC: HGLRC;
- sharedRC: TgxWinContext;
- function CurrentPixelFormatIsHardwareAccelerated: Boolean;
- var
- localPFD: TPixelFormatDescriptor;
- begin
- Result := False;
- if pixelFormat = 0 then
- Exit;
- with localPFD do
- begin
- nSize := SizeOf(localPFD);
- nVersion := 1;
- end;
- DescribePixelFormat(ADeviceHandle, pixelFormat, SizeOf(localPFD), localPFD);
- Result := ((localPFD.dwFlags and PFD_GENERIC_FORMAT) = 0);
- end;
- var
- i, iAttrib, iValue: Integer;
- begin
- if vUseWindowTrackingHook and not FLegacyContextsOnly then
- TrackWindow(WindowFromDC(ADeviceHandle), DestructionEarlyWarning);
- // Just in case it didn't happen already.
- if not InitOpenGL then
- RaiseLastOSError;
- // Prepare PFD
- FillChar(pfDescriptor, SizeOf(pfDescriptor), 0);
- with pfDescriptor do
- begin
- nSize := SizeOf(pfDescriptor);
- nVersion := 1;
- dwFlags := PFD_SUPPORT_OPENGL;
- aType := GetObjectType(ADeviceHandle);
- if aType = 0 then
- RaiseLastOSError;
- if aType in cMemoryDCs then
- dwFlags := dwFlags or PFD_DRAW_TO_BITMAP
- else
- dwFlags := dwFlags or PFD_DRAW_TO_WINDOW;
- if rcoDoubleBuffered in Options then
- dwFlags := dwFlags or PFD_DOUBLEBUFFER;
- if rcoStereo in Options then
- dwFlags := dwFlags or PFD_STEREO;
- iPixelType := PFD_TYPE_RGBA;
- cColorBits := ColorBits;
- cDepthBits := DepthBits;
- cStencilBits := StencilBits;
- cAccumBits := AccumBits;
- cAlphaBits := AlphaBits;
- cAuxBuffers := AuxBuffers;
- case Layer of
- clUnderlay2, clUnderlay1:
- iLayerType := Byte(PFD_UNDERLAY_PLANE);
- clMainPlane:
- iLayerType := PFD_MAIN_PLANE;
- clOverlay1, clOverlay2:
- iLayerType := PFD_OVERLAY_PLANE;
- end;
- bReserved := cLayerToSet[Layer];
- if Layer <> clMainPlane then
- dwFlags := dwFlags or PFD_SWAP_LAYER_BUFFERS;
- end;
- pixelFormat := 0;
- // WGL_ARB_pixel_format is used if available
- //
- if not(IsMesaGL or FLegacyContextsOnly or (aType in cMemoryDCs)) then
- begin
- // the WGL mechanism is a little awkward: we first create a dummy context
- // on the TOP-level DC (ie. screen), to retrieve our pixelformat, create
- // our stuff, etc.
- tempWnd := CreateTempWnd;
- tempDC := GetDC(tempWnd);
- localDC := 0;
- localRC := 0;
- try
- SpawnLegacyContext(tempDC);
- try
- DoActivate;
- try
- ClearGLError;
- if WGL_ARB_pixel_format then
- begin
- // New pixel format selection via wglChoosePixelFormatARB
- ClearIAttribs;
- AddIAttrib(WGL_DRAW_TO_WINDOW_ARB, GL_TRUE);
- AddIAttrib(WGL_STEREO_ARB, cBoolToInt[rcoStereo in Options]);
- AddIAttrib(WGL_DOUBLE_BUFFER_ARB, cBoolToInt[rcoDoubleBuffered in Options]);
- ChooseWGLFormat(ADeviceHandle, 32, @iFormats, nbFormats);
- if nbFormats > 0 then
- begin
- if WGL_ARB_multisample and (AntiAliasing in [aaNone, aaDefault])
- then
- begin
- // Pick first non AntiAliased for aaDefault and aaNone modes
- iAttrib := WGL_SAMPLE_BUFFERS_ARB;
- for i := 0 to nbFormats - 1 do
- begin
- pixelFormat := iFormats[i];
- iValue := GL_FALSE;
- wglGetPixelFormatAttribivARB(ADeviceHandle, pixelFormat, 0, 1, @iAttrib, @iValue);
- if iValue = GL_FALSE then
- break;
- end;
- end
- else
- pixelFormat := iFormats[0];
- if GetPixelFormat(ADeviceHandle) <> pixelFormat then
- begin
- if not SetPixelFormat(ADeviceHandle, pixelFormat, @pfDescriptor)
- then
- RaiseLastOSError;
- end;
- end;
- end;
- finally
- DoDeactivate;
- end;
- finally
- sharedRC := FShareContext;
- DoDestroyContext;
- FShareContext := sharedRC;
- ShowMessage('Temporary rendering context destroyed');
- end;
- finally
- ReleaseDC(0, tempDC);
- DestroyWindow(tempWnd);
- FDC := localDC;
- FRC := localRC;
- end;
- end;
- if pixelFormat = 0 then
- begin
- // Legacy pixel format selection
- pixelFormat := ChoosePixelFormat(ADeviceHandle, @pfDescriptor);
- if (not(aType in cMemoryDCs)) and (not CurrentPixelFormatIsHardwareAccelerated) then
- begin
- softwarePixelFormat := pixelFormat;
- pixelFormat := 0;
- end
- else
- softwarePixelFormat := 0;
- if pixelFormat = 0 then
- begin
- // Failed on default params, try with 16 bits depth buffer
- pfDescriptor.cDepthBits := 16;
- pixelFormat := ChoosePixelFormat(ADeviceHandle, @pfDescriptor);
- if not CurrentPixelFormatIsHardwareAccelerated then
- pixelFormat := 0;
- if pixelFormat = 0 then
- begin
- // Failed, try with 16 bits color buffer
- pfDescriptor.cColorBits := 16;
- pixelFormat := ChoosePixelFormat(ADeviceHandle, @pfDescriptor);
- end;
- if not CurrentPixelFormatIsHardwareAccelerated then
- begin
- // Fallback to original, should be supported by software
- pixelFormat := softwarePixelFormat;
- end;
- if pixelFormat = 0 then
- RaiseLastOSError;
- end;
- end;
- if GetPixelFormat(ADeviceHandle) <> pixelFormat then
- begin
- if not SetPixelFormat(ADeviceHandle, pixelFormat, @pfDescriptor) then
- RaiseLastOSError;
- end;
- // Check the properties we just set.
- DescribePixelFormat(ADeviceHandle, pixelFormat, SizeOf(pfDescriptor), pfDescriptor);
- with pfDescriptor do
- begin
- if (dwFlags and PFD_NEED_PALETTE) <> 0 then
- SetupPalette(ADeviceHandle, pfDescriptor);
- FSwapBufferSupported := (dwFlags and PFD_SWAP_LAYER_BUFFERS) <> 0;
- if bReserved = 0 then
- FLayer := clMainPlane;
- end;
- if not FLegacyContextsOnly then
- begin
- if ((pfDescriptor.dwFlags and PFD_GENERIC_FORMAT) > 0) and (FAcceleration = chaHardware) then
- begin
- FAcceleration := chaSoftware;
- ShowMessage(strFailHWRC);
- end;
- end;
- if not FLegacyContextsOnly and WGL_ARB_create_context and (FAcceleration = chaHardware) then
- CreateNewContext(ADeviceHandle)
- else
- CreateOldContext(ADeviceHandle);
- if not FLegacyContextsOnly then
- begin
- // Share identifiers with other context if it deffined
- if (ServiceContext <> nil) and (Self <> ServiceContext) then
- begin
- if wglShareLists(TgxWinContext(ServiceContext).FRC, FRC) then
- begin
- FSharedContexts.Add(ServiceContext);
- PropagateSharedContext;
- end
- else
- ShowMessage('DoCreateContext - Failed to share contexts with resource context');
- end;
- end;
- end;
- procedure TgxWinContext.SpawnLegacyContext(aDC: HDC);
- begin
- try
- FLegacyContextsOnly := True;
- try
- DoCreateContext(aDC);
- finally
- FLegacyContextsOnly := False;
- end;
- except
- on E: Exception do
- begin
- raise Exception.Create(strUnableToCreateLegacyContext + #13#10 + E.ClassName + ': ' + E.message);
- end;
- end;
- end;
- procedure TgxWinContext.DoCreateMemoryContext(OutputDevice: THandle; Width, Height: Integer; BufferCount: Integer);
- var
- nbFormats: Integer;
- iFormats: array [0 .. 31] of Integer;
- iPBufferAttribs: array [0 .. 0] of Integer;
- localHPBuffer: Integer;
- localRC: HGLRC;
- localDC, tempDC: HDC;
- tempWnd: HWND;
- shareRC: TgxWinContext;
- pfDescriptor: TPixelFormatDescriptor;
- bOES: Boolean;
- begin
- localHPBuffer := 0;
- localDC := 0;
- localRC := 0;
- bOES := False;
- // the WGL mechanism is a little awkward: we first create a dummy context
- // on the TOP-level DC (ie. screen), to retrieve our pixelformat, create
- // our stuff, etc.
- tempWnd := CreateTempWnd;
- tempDC := GetDC(tempWnd);
- try
- SpawnLegacyContext(tempDC);
- try
- DoActivate;
- try
- ClearGLError;
- if WGL_ARB_pixel_format and WGL_ARB_pbuffer then
- begin
- ClearIAttribs;
- AddIAttrib(WGL_DRAW_TO_PBUFFER_ARB, 1);
- ChooseWGLFormat(tempDC, 32, @iFormats, nbFormats, BufferCount);
- if nbFormats = 0 then
- raise EPBuffer.Create
- ('Format not supported for pbuffer operation.');
- iPBufferAttribs[0] := 0;
- localHPBuffer := wglCreatePbufferARB(tempDC, iFormats[0], Width,
- Height, @iPBufferAttribs[0]);
- if localHPBuffer = 0 then
- raise EPBuffer.Create('Unabled to create pbuffer.');
- try
- localDC := wglGetPbufferDCARB(localHPBuffer);
- if localDC = 0 then
- raise EPBuffer.Create('Unabled to create pbuffer''s DC.');
- try
- if WGL_ARB_create_context then
- begin
- // Modern creation style
- ClearIAttribs;
- // Initialize forward context
- if gxStates.ForwardContext then
- begin
- if GL_VERSION_4_2 then
- begin
- AddIAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, 4);
- AddIAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, 2);
- end
- else if GL_VERSION_4_1 then
- begin
- AddIAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, 4);
- AddIAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, 1);
- end
- else if GL_VERSION_4_0 then
- begin
- AddIAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, 4);
- AddIAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, 0);
- end
- else
- Abort;
- AddIAttrib(WGL_CONTEXT_FLAGS_ARB,
- WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB);
- if rcoOGL_ES in Options then
- ShowMessage(strOESvsForwardRC);
- end
- else if rcoOGL_ES in Options then
- begin
- if WGL_EXT_create_context_es2_profile then
- begin
- AddIAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, 2);
- AddIAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, 0);
- AddIAttrib(WGL_CONTEXT_FLAGS_ARB,
- WGL_CONTEXT_ES2_PROFILE_BIT_EXT);
- end
- else
- ShowMessage(strDriverNotSupportOESRC);
- end;
- if rcoDebug in Options then
- begin
- AddIAttrib(WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB);
- ///DebugMode := True;
- end;
- case Layer of
- clUnderlay2:
- AddIAttrib(WGL_CONTEXT_LAYER_PLANE_ARB, -2);
- clUnderlay1:
- AddIAttrib(WGL_CONTEXT_LAYER_PLANE_ARB, -1);
- clOverlay1:
- AddIAttrib(WGL_CONTEXT_LAYER_PLANE_ARB, 1);
- clOverlay2:
- AddIAttrib(WGL_CONTEXT_LAYER_PLANE_ARB, 2);
- end;
- localRC := wglCreateContextAttribsARB(localDC, 0,
- @FiAttribs[0]);
- if localRC = 0 then
- {$IFDEF USE_LOGGING}
- begin
- if gxStates.ForwardContext then
- GLSLogger.LogErrorFmt(cForwardContextFailed,
- [GetLastError, SysErrorMessage(GetLastError)])
- else
- GLSLogger.LogErrorFmt(cBackwardContextFailed,
- [GetLastError, SysErrorMessage(GetLastError)]);
- Abort;
- end;
- {$ELSE}
- raise Exception.Create('Unabled to create pbuffer''s RC.');
- {$ENDIF}
- end
- else
- begin
- // Old creation style
- localRC := wglCreateContext(localDC);
- if localRC = 0 then
- begin
- ShowMessage(Format(strBackwardContextFailed,
- [GetLastError, SysErrorMessage(GetLastError)]));
- Abort;
- end;
- end;
- except
- wglReleasePBufferDCARB(localHPBuffer, localDC);
- raise;
- end;
- except
- wglDestroyPBufferARB(localHPBuffer);
- raise;
- end;
- end
- else
- raise EPBuffer.Create('WGL_ARB_pbuffer support required.');
- CheckOpenGLError;
- finally
- DoDeactivate;
- end;
- finally
- shareRC := FShareContext;
- DoDestroyContext;
- FShareContext := shareRC;
- end;
- finally
- ReleaseDC(0, tempDC);
- DestroyWindow(tempWnd);
- FHPBUFFER := localHPBuffer;
- FDC := localDC;
- FRC := localRC;
- end;
- DescribePixelFormat(FDC, GetPixelFormat(FDC), SizeOf(pfDescriptor),
- pfDescriptor);
- if ((pfDescriptor.dwFlags and PFD_GENERIC_FORMAT) > 0) and
- (FAcceleration = chaHardware) then
- begin
- FAcceleration := chaSoftware;
- ShowMessage(strFailHWRC);
- end;
- Activate;
- InitOpenGL; ///FGL.Initialize;
- // If we are using AntiAliasing, adjust filtering hints
- if AntiAliasing in [aa2xHQ, aa4xHQ, csa8xHQ, csa16xHQ] then
- gxStates.MultisampleFilterHint := hintNicest
- else if AntiAliasing in [aa2x, aa4x, csa8x, csa16x] then
- gxStates.MultisampleFilterHint := hintFastest
- else
- gxStates.MultisampleFilterHint := hintDontCare;
- // Specific which color buffers are to be drawn into
- if BufferCount > 1 then
- glDrawBuffers(BufferCount, @MRT_BUFFERS);
- if (ServiceContext <> nil) and (Self <> ServiceContext) then
- begin
- if wglShareLists(TgxWinContext(ServiceContext).FRC, FRC) then
- begin
- FSharedContexts.Add(ServiceContext);
- PropagateSharedContext;
- end
- else
- ShowMessage('DoCreateContext - Failed to share contexts with resource context');
- end;
- if Assigned(FShareContext) and (FShareContext.RC <> 0) then
- begin
- if not wglShareLists(FShareContext.RC, FRC) then
- ShowMessage(strFailedToShare)
- else
- begin
- FSharedContexts.Add(FShareContext);
- PropagateSharedContext;
- end;
- end;
- Deactivate;
- if gxStates.ForwardContext then
- ShowMessage('PBuffer ' + strFRC_created);
- if bOES then
- ShowMessage('PBuffer ' + strOESRC_created);
- if not(gxStates.ForwardContext or bOES) then
- ShowMessage(strPBufferRC_created);
- end;
- function TgxWinContext.DoShareLists(aContext: TgxContext): Boolean;
- begin
- if aContext is TgxWinContext then
- begin
- FShareContext := TgxWinContext(aContext);
- if FShareContext.RC <> 0 then
- Result := wglShareLists(FShareContext.RC, RC)
- else
- Result := False;
- end
- else
- raise Exception.Create(strIncompatibleContexts);
- end;
- procedure TgxWinContext.DoDestroyContext;
- begin
- if vUseWindowTrackingHook then
- UnTrackWindow(WindowFromDC(FDC));
- if FHPBUFFER <> 0 then
- begin
- wglReleasePBufferDCARB(FHPBUFFER, FDC);
- wglDestroyPBufferARB(FHPBUFFER);
- FHPBUFFER := 0;
- end;
- if FRC <> 0 then
- if not wglDeleteContext(FRC) then
- ShowMessage(Format(strDeleteContextFailed,
- [GetLastError, SysErrorMessage(GetLastError)]));
- FRC := 0;
- FDC := 0;
- FShareContext := nil;
- end;
- procedure TgxWinContext.DoActivate;
- begin
- if not wglMakeCurrent(FDC, FRC) then
- begin
- ShowMessage(Format(strContextActivationFailed,
- [GetLastError, SysErrorMessage(GetLastError)]));
- Abort;
- end;
- if not LoadOpenGL then
- InitOpenGL; ///FGL.Initialize(CurrentVXContext = nil);
- end;
- procedure TgxWinContext.DoDeactivate;
- begin
- if not wglMakeCurrent(0, 0) then
- begin
- ShowMessage(Format(strContextDeactivationFailed,
- [GetLastError, SysErrorMessage(GetLastError)]));
- Abort;
- end;
- end;
- function TgxWinContext.IsValid: Boolean;
- begin
- Result := (FRC <> 0);
- end;
- procedure TgxWinContext.SwapBuffers;
- begin
- if (FDC <> 0) and (rcoDoubleBuffered in Options) then
- if FSwapBufferSupported then
- begin
- case Layer of
- clUnderlay2:
- wglSwapLayerBuffers(FDC, WGL_SWAP_UNDERLAY2);
- clUnderlay1:
- wglSwapLayerBuffers(FDC, WGL_SWAP_UNDERLAY1);
- clMainPlane: SwapBuffers(); /// Vcl - SwapBuffers(FDC)
- clOverlay1:
- wglSwapLayerBuffers(FDC, WGL_SWAP_OVERLAY1);
- clOverlay2:
- wglSwapLayerBuffers(FDC, WGL_SWAP_OVERLAY2);
- end;
- end
- else
- SwapBuffers(); /// Vcl - SwapBuffers(FDC);
- end;
- function TgxWinContext.RenderOutputDevice: Pointer;
- begin
- Result := Pointer(FDC);
- end;
- initialization // ------------------------------------------------------------
- RegisterContextClass(TgxWinContext);
- end.
|