Kaynağa Gözat

Merge pull request #174 from GWRon/feat_render2texture

[Max2D] Add "render image" support (render2texture)
Brucey 3 yıl önce
ebeveyn
işleme
42c3862602

+ 503 - 0
d3d9max2d.mod/d3d9max2d.bmx

@@ -242,6 +242,505 @@ Type TD3D9ImageFrame Extends TImageFrame
 
 End Type
 
+
+Type TD3D9RenderImageContext Extends TRenderImageContext
+	Field _gc:TD3D9Graphics
+	Field _d3ddev:IDirect3DDevice9
+	Field _backbuffer:IDirect3DSurface9
+	Field _matrix:Float[16]
+	Field _viewport:D3DVIEWPORT9
+	Field _renderImages:TList
+	Field _deviceok:Int = True
+
+	Method Delete()
+		ReleaseNow()
+	End Method
+	
+	Method ReleaseNow()
+		If _renderImages
+			For Local ri:TD3D9RenderImage = EachIn _renderImages
+				ri.DestroyRenderImage()
+			Next
+		EndIf
+
+		_renderImages = Null
+		_viewport = Null
+		_gc = Null
+
+		If _backbuffer
+			_backbuffer.release_
+			_backbuffer = Null
+		EndIf
+		If _d3ddev
+			_d3ddev.release_
+			_d3ddev = Null
+		EndIf
+	End Method
+
+	Method Create:TD3D9RenderimageContext(g:TGraphics, driver:TGraphicsDriver)
+		_gc = TD3D9Graphics(g)
+
+'		_gc.AddDeviceMightGetLostCallback(fnOnDeviceMightGetLost, Self)
+		_gc.AddDeviceLostCallback(fnOnDeviceLost, Self)
+		_gc.AddDeviceResetCallback(fnOnDeviceReset, Self)
+
+		_d3ddev = _gc.GetDirect3DDevice()
+		_d3ddev.AddRef()
+
+		_d3ddev.GetRenderTarget(0, _backbuffer)
+
+		_viewport = New D3DVIEWPORT9
+		_d3ddev.GetViewport(_viewport)
+		_d3ddev.GetTransform(D3DTS_PROJECTION, _matrix)
+			
+		_renderImages = New TList
+
+		Return Self
+	End Method
+	
+	Method GraphicsContext:TGraphics()
+		Return _gc
+	End Method
+	
+	Method Destroy()
+'		_gc.RemoveDeviceMightGetLostCallback(fnOnDeviceMightGetLost)
+		_gc.RemoveDeviceLostCallback(fnOnDeviceLost)
+		_gc.RemoveDeviceResetCallback(fnOnDeviceReset)
+		ReleaseNow()
+	End Method
+
+	Method CreateRenderImage:TRenderImage(width:Int, height:Int, UseImageFiltering:Int)
+		Local renderimage:TD3D9RenderImage = New TD3D9RenderImage.CreateRenderImage(width, height)
+		renderimage.Init(_d3ddev, UseImageFiltering)
+		_renderImages.AddLast(renderimage)
+
+		Return renderimage
+	End Method
+	
+	Method CreateRenderImageFromPixmap:TRenderImage(pixmap:TPixmap, UseImageFiltering:Int)
+		Local renderimage:TD3D9RenderImage = New TD3D9RenderImage.CreateRenderImage(pixmap.Width, pixmap.Height)
+		renderimage.InitFromPixmap(_d3ddev, pixmap, UseImageFiltering)
+		_renderImages.AddLast(renderimage)
+
+		Return renderimage
+	End Method
+	
+	Method DestroyRenderImage(renderImage:TRenderImage)
+		renderImage.DestroyRenderImage()
+		_renderImages.Remove(renderImage)
+	End Method
+
+	Method SetRenderImage(renderimage:TRenderimage)
+		If Not renderimage
+			_d3ddev.SetRenderTarget(0, _backbuffer)	
+			_d3ddev.SetTransform D3DTS_PROJECTION,_matrix
+			_d3ddev.SetViewport(_viewport)
+		Else
+			renderimage.SetRenderImage()
+		EndIf
+	End Method
+	
+	Method CreatePixmapFromRenderImage:TPixmap(renderImage:TRenderImage)
+		Return TD3D9RenderImage(renderImage).ToPixmap()
+	End Method
+
+rem
+	Method OnDeviceMightGetLost()
+		For Local ri:TD3D9RenderImage = EachIn _renderImages
+			ri.OnDeviceMightGetLost()
+		Next
+	End Method
+endrem
+
+	Method OnDeviceLost()
+		If _deviceok = False Then Return
+
+		For Local ri:TD3D9RenderImage = EachIn _renderImages
+			ri.OnDeviceLost()
+		Next
+		If _backbuffer
+			_backbuffer.release_
+			_backbuffer = Null
+		EndIf
+
+		_deviceok = False
+	End Method
+
+	Method OnDeviceReset()
+		If _deviceok = True Then Return
+
+		Local hr:Int = _d3ddev.GetRenderTarget(0, _backbuffer)
+		if hr = D3D_OK
+'			print "  _d3ddev.GetRenderTarget() result: D3D_OK" 
+		Elseif hr = D3DERR_INVALIDCALL
+			print "  _d3ddev.GetRenderTarget() result: D3DERR_INVALIDCALL" 
+		Elseif hr = D3DERR_NOTFOUND
+			print "  _d3ddev.GetRenderTarget() result: D3DERR_NOTFOUND"
+		Else 
+			print "  _d3ddev.GetRenderTarget() result: " + hr
+		EndIf
+		hr = _d3ddev.GetViewport(_viewport)
+
+		For Local ri:TD3D9RenderImage = EachIn _renderImages
+			ri.OnDeviceReset()
+		Next
+
+		_deviceok = True
+	End Method
+
+rem
+	Function fnOnDeviceMightGetLost(obj:Object)
+		Local ric:TD3D9RenderImageContext = TD3D9RenderImageContext(obj)
+		If Not ric Return
+		ric.OnDeviceMightGetLost()
+	EndFunction
+endrem
+
+	Function fnOnDeviceLost(obj:Object)
+		Local ric:TD3D9RenderImageContext = TD3D9RenderImageContext(obj)
+		If Not ric Return
+		ric.OnDeviceLost()
+	EndFunction
+
+	Function fnOnDeviceReset(obj:Object)
+		Local ric:TD3D9RenderImageContext = TD3D9RenderImageContext(obj)
+		If Not ric Return
+		ric.OnDeviceReset()
+	EndFunction
+EndType
+
+
+
+Type TD3D9RenderImageFrame Extends TD3D9ImageFrame
+	Field _surface:IDirect3DSurface9
+	Field _persistPixmap:TPixmap
+
+	Method Delete()
+		ReleaseNow()
+	End Method
+
+	'ensure the GPU located render image would survive a "appsuspend"
+	'by eg. reading it into a TPixmap
+	Method Persist:Int(d3ddev:IDirect3DDevice9, width:Int, height:Int)
+		_persistPixmap = ToPixmap(d3ddev, width, height)
+		Return True
+	End Method
+
+	
+	Method ReleaseNow()
+		If _surface
+			_surface.Release_
+			_surface = Null
+		EndIf
+		If _texture
+			_texture.Release_
+			_texture = Null
+		EndIf
+	End Method
+	
+	Method Clear(d3ddev:IDirect3DDevice9, r:Int=0, g:Int=0, b:Int=0, a:Float=0.0)
+		If Not d3ddev Return
+
+		Local c:Int = (int(a*255) Shl 24) | (r Shl 16) | (g Shl 8) | b
+		d3ddev.Clear(0, Null, D3DCLEAR_TARGET, c, 0.0, 0)
+	End Method
+
+	Method CreateRenderTarget:TD3D9RenderImageFrame( d3ddev:IDirect3DDevice9, width:Int,height:Int )
+		d3ddev.CreateTexture(width,height,1,D3DUSAGE_RENDERTARGET,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,_texture,Null)
+		If _texture _texture.GetSurfaceLevel 0, _surface
+		
+		_magfilter = D3DTFG_LINEAR
+		_minfilter = D3DTFG_LINEAR
+		_mipfilter = D3DTFG_LINEAR
+
+		_uscale = 1.0 / width
+		_vscale = 1.0 / height
+
+		Return Self
+	End Method
+	
+	Method DestroyRenderImage()
+		ReleaseNow()
+	End Method
+	
+rem
+	'once a device is lost we cannot simply backup a pixmap, so better
+	'do it any time we _could_ loose the device (eg. app suspend)
+	Method OnDeviceMightGetLost(d3ddev:IDirect3DDevice9, width:Int, height:Int)
+		print "TD3D9ImageFrame.OnDeviceMightGetLost(): persisting to pixmap"
+		Persist()
+	End Method
+endrem
+
+	Method OnDeviceLost(d3ddev:IDirect3DDevice9, width:Int, height:Int)
+		'only read in a new pixmap if none was created before
+		'in case of "suspend and resum" this ToPixmap() call will return
+		'an empty pixmap (because of "D3DERR_DEVICELOST")
+		If Not _persistPixmap
+			_persistPixmap = ToPixmap(d3ddev, width, height)
+		EndIf
+		ReleaseNow()
+	End Method
+
+	Method OnDeviceReset(d3ddev:IDirect3DDevice9)
+		If(_persistpixmap)
+			d3ddev.CreateTexture(_persistPixmap.width, _persistPixmap.height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, _texture, Null)
+			If _texture 
+				_texture.GetSurfaceLevel(0, _surface)
+			EndIf
+
+			FromPixmap(d3ddev, _persistPixmap)
+		EndIf
+
+		_persistPixmap = Null
+	End Method
+	
+	Method FromPixmap(d3ddev:IDirect3DDevice9, pixmap:TPixmap)
+		' use a staging surface to copy the pixmap into
+		Local stage:IDirect3DSurface9
+		d3ddev.CreateOffscreenPlainSurface(pixmap.width, pixmap.height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, stage, Null)
+
+		Local lockedrect:D3DLOCKED_RECT = New D3DLOCKED_RECT
+		stage.LockRect(lockedrect, Null, 0)
+
+		' copy the pixel data across
+		For Local y:Int = 0 Until pixmap.height
+			Local srcptr:Byte Ptr = pixmap.pixels + y * pixmap.pitch
+			Local dstptr:Byte Ptr = lockedrect.pBits + y * lockedrect.Pitch
+			MemCopy dstptr, srcptr, size_t(pixmap.width * 4)
+		Next
+		stage.UnlockRect()
+
+		' copy from the staging surface to the render surface
+		d3ddev.UpdateSurface(stage, Null, _surface, Null)
+
+		' cleanup
+		stage.release_
+	End Method
+	
+	Method ToPixmap:TPixmap(d3ddev:IDirect3DDevice9, width:Int, height:Int)
+		Local pixmap:TPixmap = CreatePixmap(width, height, PF_RGBA8888)
+
+		' use a staging surface to get the texture contents
+		Local stage:IDirect3DSurface9
+		d3ddev.CreateOffscreenPlainSurface(width, height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, stage, Null)
+
+		Local result:Int = d3ddev.GetRenderTargetData(_surface, stage)
+		If result < 0
+			If result = D3DERR_DRIVERINTERNALERROR
+				Throw "TD3D9RenderImageFrame:ToPixmap:GetRenderTargetData failed: D3DERR_DRIVERINTERNALERROR"
+			ElseIf result = D3DERR_DEVICELOST
+				'Throw "TD3D9RenderImageFrame:ToPixmap:GetRenderTargetData failed: D3DERR_DEVICELOST"
+			ElseIf result = D3DERR_INVALIDCALL
+				Throw "TD3D9RenderImageFrame:ToPixmap:GetRenderTargetData failed: D3DERR_INVALIDCALL"
+			Else
+				Throw "TD3D9RenderImageFrame:ToPixmap:GetRenderTargetData failed."
+			EndIf
+		EndIf
+
+		' copy the pixel data across
+		Local lockedrect:D3DLOCKED_RECT = New D3DLOCKED_RECT
+		If stage.LockRect(lockedrect, Null, 0) < 0 Throw "TD3D9RenderImageFrame:ToPixmap:LockRect failed"
+
+		For Local y:Int = 0 Until pixmap.height
+			For Local x:Int = 0 Until pixmap.width
+				Local srcptr:Int Ptr = Int Ptr (lockedrect.pBits + x * 4 + y * lockedrect.Pitch)
+				Local dstptr:Int Ptr = Int Ptr (pixmap.pixels + x * 4 + y * pixmap.pitch)
+				dstptr[0] = ((srcptr[0] & $ff) Shl 16) | ((srcptr[0] & $ff0000) Shr 16)| (srcptr[0] & $ff00) | (srcptr[0] & $ff000000)
+			Next
+		Next
+		
+		pixmap = ConvertPixmap(pixmap, PF_BGRA)
+		
+		' cleanup
+		stage.UnlockRect()
+		stage.release_
+		
+		Return pixmap
+	End Method
+EndType
+
+Type TD3D9RenderImage Extends TRenderImage
+	Field _d3ddev:IDirect3DDevice9
+	Field _viewport:D3DVIEWPORT9
+	Field _matrix:Float[]
+
+	Method Delete()
+		ReleaseNow()
+	End Method
+
+	'ensure the GPU located render image would survive a "appsuspend"
+	'by eg. reading it into a TPixmap
+	Method Persist:Int() Override
+		if TD3D9RenderImageFrame(frames[0])
+			Return TD3D9RenderImageFrame(frames[0]).Persist(_d3ddev, width, height)
+		EndIf
+		Return False
+	End Method
+
+	
+	Method ReleaseNow()
+		If _d3ddev
+			_d3ddev.release_
+			_d3ddev = Null
+		EndIf
+	End Method
+
+	Method CreateRenderImage:TD3D9RenderImage(width:Int ,height:Int)
+		Self.width=width	' TImage.width
+		Self.height=height	' TImage.height
+	
+		_matrix = [	2.0/width, 0.0, 0.0, 0.0,..
+					0.0, -2.0/height, 0.0, 0.0,..
+					0.0, 0.0, 1.0, 0.0,..
+					-1-(1.0/width), 1+(1.0/height), 1.0, 1.0 ]
+
+		_viewport = New D3DVIEWPORT9
+		_viewport.width = width
+		_viewport.height = height
+		_viewport.MaxZ = 1.0
+
+		Return Self
+	End Method
+	
+	Method DestroyRenderImage()
+		ReleaseNow()
+		TD3D9RenderImageFrame(frames[0]).ReleaseNow()
+	End Method
+
+	Method Init(d3ddev:IDirect3DDevice9, UseImageFiltering:Int)
+		_d3ddev = d3ddev
+		_d3ddev.AddRef()
+
+		frames = New TD3D9RenderImageFrame[1]
+		frames[0] = New TD3D9RenderImageFrame.CreateRenderTarget(_d3ddev, width, height)
+		If UseImageFiltering
+			TD3D9RenderImageFrame(frames[0])._magfilter=D3DTFG_LINEAR
+			TD3D9RenderImageFrame(frames[0])._minfilter=D3DTFG_LINEAR
+			TD3D9RenderImageFrame(frames[0])._mipfilter=D3DTFG_LINEAR
+		Else
+			TD3D9RenderImageFrame(frames[0])._magfilter=D3DTFG_POINT
+			TD3D9RenderImageFrame(frames[0])._minfilter=D3DTFG_POINT
+			TD3D9RenderImageFrame(frames[0])._mipfilter=D3DTFG_POINT
+		EndIf
+
+
+		'  clear the new render target surface
+		Local prevsurf:IDirect3DSurface9
+		Local prevmatrix:Float[16]
+		Local prevviewport:D3DVIEWPORT9 = New D3DVIEWPORT9
+		
+		' get previous
+		_d3ddev.GetRenderTarget(0, prevsurf)
+		_d3ddev.GetTransform(D3DTS_PROJECTION, prevmatrix)
+		_d3ddev.GetViewport(prevviewport)
+
+		' set and clear
+		_d3ddev.SetRenderTarget(0, TD3D9RenderImageFrame(frames[0])._surface)
+		_d3ddev.SetTransform(D3DTS_PROJECTION, _matrix)
+		_d3ddev.Clear(0, Null, D3DCLEAR_TARGET, 0, 0.0, 0)
+
+		' reset to previous
+		_d3ddev.SetRenderTarget(0, prevsurf)
+		_d3ddev.SetTransform(D3DTS_PROJECTION, prevmatrix)
+		_d3ddev.SetViewport(prevviewport)
+
+		' cleanup
+		If prevsurf Then prevsurf.release_
+	End Method
+	
+	Method InitFromPixmap(d3ddev:IDirect3DDevice9, Pixmap:TPixmap, UseImageFiltering:Int)
+		_d3ddev = d3ddev
+		_d3ddev.AddRef()
+
+		Pixmap = ConvertPixmap(pixmap, PF_BGRA)
+
+		frames = New TD3D9RenderImageFrame[1]
+		frames[0] = New TD3D9RenderImageFrame.CreateRenderTarget(d3ddev, width, height)
+		If UseImageFiltering
+			TD3D9RenderImageFrame(frames[0])._magfilter=D3DTFG_LINEAR
+			TD3D9RenderImageFrame(frames[0])._minfilter=D3DTFG_LINEAR
+			TD3D9RenderImageFrame(frames[0])._mipfilter=D3DTFG_LINEAR
+		Else
+			TD3D9RenderImageFrame(frames[0])._magfilter=D3DTFG_POINT
+			TD3D9RenderImageFrame(frames[0])._minfilter=D3DTFG_POINT
+			TD3D9RenderImageFrame(frames[0])._mipfilter=D3DTFG_POINT
+		EndIf
+
+		TD3D9RenderImageFrame(frames[0]).FromPixmap(d3ddev, Pixmap)
+	End Method	
+
+	Method Clear(r:Int=0, g:Int=0, b:Int=0, a:Float=0.0)
+		If frames[0] Then TD3D9RenderImageFrame(frames[0]).Clear(_d3ddev, r, g, b, a)
+	End Method
+
+	Method Frame:TImageFrame(index:Int=0)
+		If Not frames Return Null
+		If Not frames[0] Return Null
+		Return frames[0]
+	End Method
+	
+	Method SetRenderImage()
+		Local pTexture:IDirect3DTexture9
+		_d3ddev.GetTexture(0, pTexture)
+		
+		Local frame:TD3D9RenderImageFrame = TD3D9RenderImageFrame(frames[0])
+		If frame._texture <> pTexture
+			_d3ddev.SetTexture(0, pTexture)
+		EndIf
+		
+		If pTexture pTexture.Release_
+		
+		_d3ddev.SetRenderTarget(0, TD3D9RenderImageFrame(frames[0])._surface)
+		_d3ddev.SetTransform(D3DTS_PROJECTION,_matrix)
+		_d3ddev.SetViewport(_viewport)
+	End Method
+	
+	Method ToPixmap:TPixmap()
+		Return TD3D9RenderImageFrame(frames[0]).ToPixmap(_d3ddev, width, height)
+	End Method
+	
+	Method SetViewport(x:Int, y:Int, width:Int, height:Int)
+		If width = 0
+			width = Self.width
+			height = Self.height
+		EndIf
+
+		If x + width > Self.width
+			width:-(x + width - Self.width)
+		EndIf
+		If y + height > Self.height
+			height:-(y + height - Self.height)
+		EndIf
+
+		If x = 0 And y = 0 And width = Self.width And height = Self.height
+			_d3ddev.SetRenderState(D3DRS_SCISSORTESTENABLE, False)
+		Else
+			_d3ddev.SetRenderState(D3DRS_SCISSORTESTENABLE, True)
+			Local rect[] = [x , y, x + width, y + height]
+			_d3ddev.SetScissorRect(rect)
+		EndIf
+
+	End Method
+
+'	Method OnDeviceMightGetLost()
+'		TD3D9RenderImageFrame(frames[0]).OnDeviceMightGetLost(_d3ddev, width, height)
+'	End Method
+
+	Method OnDeviceLost()
+		'invalidate (even with existing persistPixmap!)
+		_valid = False
+
+		TD3D9RenderImageFrame(frames[0]).OnDeviceLost(_d3ddev, width, height)
+	End Method
+
+	Method OnDeviceReset()
+		TD3D9RenderImageFrame(frames[0]).OnDeviceReset(_d3ddev)
+	End Method
+EndType
+
+
+
 Type TD3D9Max2DDriver Extends TMax2dDriver
 
 	Method ToString$() Override
@@ -369,6 +868,10 @@ Type TD3D9Max2DDriver Extends TMax2dDriver
 	End Method
 
 	'***** TMax2DDriver *****
+	Method CreateRenderImageContext:Object(g:TGraphics) Override
+		Return New TD3D9RenderImageContext.Create(g, Self)
+	End Method
+
 	Method CreateFrameFromPixmap:TImageFrame( pixmap:TPixmap,flags:Int ) Override
 		Return New TD3D9ImageFrame.Create( pixmap,flags )
 	End Method

+ 120 - 2
dxgraphics.mod/d3d9graphics.bmx

@@ -46,6 +46,9 @@ Function D3D9WndProc:Byte Ptr( hwnd:Byte Ptr,msg:UInt,wp:WParam,lp:LParam) "win3
 		Return Null
 	Case WM_SYSKEYDOWN
 		If wp<>KEY_F4 Return Null
+	Case WM_ACTIVATE
+		If _graphics _graphics.OnWMActivate(wp)
+		Return 0
 	End Select
 
 	Return DefWindowProcW( hwnd,msg,wp,lp )
@@ -80,6 +83,47 @@ Function OpenD3DDevice:Int( hwnd:Byte Ptr,width:Int,height:Int,depth:Int,hertz:I
 	
 	'_d3dDev' = New IDirect3DDevice9
 
+	Function CheckDepthFormat(format:Int)
+	    Return _d3d.CheckDeviceFormat(0,D3DDEVTYPE_HAL,D3DFMT_X8R8G8B8,D3DUSAGE_DEPTHSTENCIL,D3DRTYPE_SURFACE,format)=D3D_OK
+	End Function
+
+	If flags&GRAPHICS_DEPTHBUFFER Or flags&GRAPHICS_STENCILBUFFER
+	    pp.EnableAutoDepthStencil = True
+	    If flags&GRAPHICS_STENCILBUFFER
+	        If Not CheckDepthFormat( D3DFMT_D24S8 )
+	            If Not CheckDepthFormat( D3DFMT_D24FS8 )
+	                If Not CheckDepthFormat( D3DFMT_D24X4S4 )
+	                    If Not CheckDepthFormat( D3DFMT_D15S1 )
+	                        Return False
+	                    Else
+	                        pp.AutoDepthStencilFormat = D3DFMT_D15S1
+	                    EndIf
+	                Else
+	                    pp.AutoDepthStencilFormat = D3DFMT_D24X4S4
+	                EndIf
+	            Else
+	                pp.AutoDepthStencilFormat = D3DFMT_D24FS8
+	            EndIf
+	        Else
+	            pp.AutoDepthStencilFormat = D3DFMT_D24S8
+	        EndIf
+	    Else
+	        If Not CheckDepthFormat( D3DFMT_D32 )
+	            If Not CheckDepthFormat( D3DFMT_D24X8 )
+	                If Not CheckDepthFormat( D3DFMT_D16 )
+	                    Return False
+	                Else
+	                    pp.AutoDepthStencilFormat = D3DFMT_D16
+	                EndIf
+	            Else
+	                pp.AutoDepthStencilFormat = D3DFMT_D24X8
+	            EndIf
+	        Else
+	            pp.AutoDepthStencilFormat = D3DFMT_D32
+	        EndIf
+	    EndIf
+	EndIf
+	
 	'OK, try hardware vertex processing...
 	Local tflags:Int=D3DCREATE_PUREDEVICE|D3DCREATE_HARDWARE_VERTEXPROCESSING|cflags
 	If _d3d.CreateDevice( 0,D3DDEVTYPE_HAL,hwnd,tflags,pp,_d3dDev )<0
@@ -137,17 +181,23 @@ Function CloseD3DDevice()
 End Function
 
 Function ResetD3DDevice()
+	If _graphics 
+		_graphics.OnDeviceLost()
+	EndIf
 	If _d3dOccQuery
 		_d3dOccQuery.Release_
 		_d3dOccQuery = Null
 	Else
 		'_d3dOccQuery' = New IDirect3DQuery9
-	End If
+	EndIf
 	
 	If _d3dDev.Reset( _presentParams)<0
 		Throw "_d3dDev.Reset failed"
 	EndIf
 
+	If _graphics 
+		_graphics.OnDeviceReset()
+	EndIf
 	If _d3ddev.CreateQuery(9,_d3dOccQuery)<0
 		_d3dOccQuery = Null
 		DebugLog "Cannot create Occlussion Query!"
@@ -160,7 +210,24 @@ Public
 
 Global UseDX9RenderLagFix:Int = 0
 
+Type TD3D9DeviceStateCallback
+	Field _fnCallback(obj:Object)
+	Field _obj:Object
+	
+	Method Create:TD3D9DeviceStateCallback(fnCallback(obj:Object), obj:Object)
+		_fnCallback = fnCallback
+		_obj = obj
+
+		Return Self
+	EndMethod
+EndType
+
+
 Type TD3D9Graphics Extends TGraphics
+	Method New()
+		_onDeviceLostCallbacks = New TList
+		_onDeviceResetCallbacks = New TList
+	EndMethod
 
 	Method Attach:TD3D9Graphics( hwnd:Byte Ptr,flags:Long )
 		Local rect:Int[4]
@@ -240,6 +307,56 @@ Type TD3D9Graphics Extends TGraphics
 		Return Self
 	End Method
 	
+	Method OnWMActivate(wp:WParam)
+		' this covers the alt-tab issue for render-texture management
+		Local activate:Short = wp & $FFFF
+		Local state:Short = (wp Shr 16) & $FFFF
+		
+		' only release when fullscreen
+		If activate = 0 And _depth <> 0
+			OnDeviceLost()
+		EndIf
+		' the Flip(sync) method will call into ResetD3DDevice where OnDeviceReset will be called
+	EndMethod
+
+	Method AddDeviceLostCallback(fnOnDeviceLostCallback(obj:Object), obj:Object)
+		_onDeviceLostCallbacks.AddLast(New TD3D9DeviceStateCallback.Create(fnOnDeviceLostCallback, obj))
+	EndMethod
+	
+	Method AddDeviceResetCallback(fnOnDeviceResetCallback(obj:Object), obj:Object)
+		_onDeviceResetCallbacks.AddLast(New TD3D9DeviceStateCallback.Create(fnOnDeviceResetCallback, obj))
+	EndMethod
+	
+	Method RemoveDeviceLostCallback(fnOnDeviceLostCallback(obj:Object))
+		For Local statecallback:TD3D9DeviceStateCallback = EachIn _onDeviceLostCallbacks
+			If statecallback._fnCallback = fnOnDeviceLostCallback
+				_onDeviceLostCallbacks.Remove(statecallback)
+				Exit
+			EndIf
+		Next
+	EndMethod
+
+	Method RemoveDeviceResetCallback(fnOnDeviceResetCallback(obj:Object))
+		For Local statecallback:TD3D9DeviceStateCallback = EachIn _onDeviceResetCallbacks
+			If statecallback._fnCallback = fnOnDeviceResetCallback
+				_onDeviceResetCallbacks.Remove(statecallback)
+				Exit
+			EndIf
+		Next
+	EndMethod
+
+	Method OnDeviceLost()
+		For Local callback:TD3D9DeviceStateCallback = EachIn _onDeviceLostCallbacks
+			callback._fnCallback(callback._obj)
+		Next
+	EndMethod
+	
+	Method OnDeviceReset()
+		For Local callback:TD3D9DeviceStateCallback = EachIn _onDeviceResetCallbacks
+			callback._fnCallback(callback._obj)
+		Next
+	EndMethod
+	
 	Method GetDirect3DDevice:IDirect3DDevice9()
 		Return _d3dDev
 	End Method
@@ -347,7 +464,8 @@ Type TD3D9Graphics Extends TGraphics
 	Field _hertz:Int
 	Field _flags:Int
 	Field _attached:Int
-
+	Field _onDeviceLostCallbacks:TList
+	Field _onDeviceResetCallbacks:TList
 End Type
 
 Type TD3D9GraphicsDriver Extends TGraphicsDriver

+ 248 - 3
glmax2d.mod/glmax2d.bmx

@@ -247,6 +247,249 @@ Type TDynamicArray
 	
 End Type
 
+
+
+
+Global glewIsInit:Int
+
+Type TGLRenderImageContext Extends TRenderImageContext
+	Field _gc:TGLGraphics
+	Field _backbuffer:Int
+	Field _width:Int
+	Field _height:Int
+	Field _renderimages:TList
+	
+	Field _matrix:Float[16]
+
+	Method Delete()
+		Destroy()
+	EndMethod
+
+	Method Destroy()
+		_gc = Null
+		If _renderimages
+			For Local ri:TGLRenderImage = EachIn _renderimages
+				ri.DestroyRenderImage()
+			Next
+		EndIf
+	EndMethod
+
+	Method Create:TGLRenderimageContext(gc:TGraphics, driver:TGraphicsDriver)
+		If Not glewIsInit
+			glewInit()
+			glewIsInit = True
+		EndIf
+
+		_renderimages = New TList
+		_gc = TGLGraphics(gc)
+		_width = GraphicsWidth()
+		_height = GraphicsHeight()
+
+		' get the backbuffer - usually 0
+		glGetIntegerv(GL_FRAMEBUFFER_BINDING, Varptr _backbuffer)
+		glGetFloatv(GL_PROJECTION_MATRIX, _matrix)
+		
+		Return Self
+	EndMethod
+
+	Method GraphicsContext:TGraphics()
+		Return _gc
+	EndMethod
+
+	Method CreateRenderImage:TRenderImage(width:Int, height:Int, UseImageFiltering:Int)
+		Local renderimage:TGLRenderImage = New TGLRenderImage.CreateRenderImage(width, height)
+		renderimage.Init(UseImageFiltering, Null)
+		Return  renderimage
+	EndMethod
+	
+	Method CreateRenderImageFromPixmap:TRenderImage(pixmap:TPixmap, UseImageFiltering:Int)
+		Local renderimage:TGLRenderImage = New TGLRenderImage.CreateRenderImage(pixmap.width, pixmap.height)
+		renderimage.Init(UseImageFiltering, pixmap)
+		Return  renderimage
+	EndMethod
+	
+	Method DestroyRenderImage(renderImage:TRenderImage)
+		renderImage.DestroyRenderImage()
+		_renderImages.Remove(renderImage)
+	EndMethod
+
+	Method SetRenderImage(renderimage:TRenderimage)
+		If Not renderimage
+			glBindFramebuffer(GL_FRAMEBUFFER,_backbuffer)
+		
+			glMatrixMode(GL_PROJECTION)
+			glLoadMatrixf(_matrix)
+			
+			glViewport(0,0,_width,_height)
+		Else
+			renderimage.SetRenderImage()
+		EndIf
+	EndMethod
+	
+	Method CreatePixmapFromRenderImage:TPixmap(renderImage:TRenderImage)
+		Return TGLRenderImage(renderImage).ToPixmap()
+	EndMethod
+End Type
+
+
+Type TGLRenderImageFrame Extends TGLImageFrame
+	Field _fbo:Int
+	
+	Method Delete()
+		DeleteFramebuffer
+	EndMethod
+	
+	Method DeleteFramebuffer()
+		If _fbo
+			glDeleteFramebuffers(1, Varptr _fbo)
+			_fbo = -1 '???
+		EndIf
+	EndMethod
+	
+	Method Clear(r:Int=0, g:Int=0, b:Int=0, a:Float=0.0)
+		'backup current
+		Local c:Float[4]
+		glGetFloatv(GL_COLOR_CLEAR_VALUE, c)		
+
+		glClearColor(r/255.0, g/255.0, b/255.0, a)
+		glClear(GL_COLOR_BUFFER_BIT)
+
+		glClearColor(c[0], c[1], c[2], c[3])
+	End Method
+
+	Method CreateRenderTarget:TGLRenderImageFrame(width:Int, height:Int, UseImageFiltering:Int, pixmap:TPixmap)
+		If pixmap pixmap = ConvertPixmap(pixmap, PF_RGBA)
+		
+		glDisable(GL_SCISSOR_TEST)
+
+		glGenTextures(1, Varptr name)
+		glBindTexture(GL_TEXTURE_2D, name)
+		If pixmap
+			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixmap.pixels)
+		Else
+			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null)
+		EndIf
+
+		If UseImageFiltering
+			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR
+			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR
+		Else
+			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST
+			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST
+		EndIf
+		
+		glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE
+		glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE
+		
+		glGenFramebuffers(1,Varptr _fbo)
+		glBindFramebuffer GL_FRAMEBUFFER,_fbo
+
+		glBindTexture GL_TEXTURE_2D,name
+		glFramebufferTexture2D GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,name,0
+
+		If Not pixmap
+			Clear()
+			' set and clear to a default colour
+			'glClearColor 0, 0, 0, 0
+			'glClear(GL_COLOR_BUFFER_BIT)
+		EndIf
+
+		uscale = 1.0 / width
+		vscale = 1.0 / height
+
+		Return Self
+	EndMethod
+	
+	Method DestroyRenderTarget()
+		DeleteFramebuffer()
+	EndMethod
+	
+	Method ToPixmap:TPixmap(width:Int, height:Int)
+		Local prevTexture:Int
+		Local prevFBO:Int
+		
+		glGetIntegerv(GL_TEXTURE_BINDING_2D,Varptr prevTexture)
+		glBindTexture(GL_TEXTURE_2D,name)
+
+		Local pixmap:TPixmap = CreatePixmap(width, height, PF_RGBA8888)		
+		glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixmap.pixels)
+		
+		glBindTexture(GL_TEXTURE_2D,prevTexture)
+				
+		Return pixmap
+	EndMethod
+EndType
+
+Type TGLRenderImage Extends TRenderImage
+	Field _matrix:Float[16]
+
+	Method CreateRenderImage:TGLRenderImage(width:Int, height:Int)
+		Self.width = width		' TImage.width
+		Self.height = height	' TImage.height
+
+		_matrix = [	2.0/width, 0.0, 0.0, 0.0,..
+					0.0, 2.0/height, 0.0, 0.0,..
+					0.0, 0.0, 1.0, 0.0,..
+					-1-(1.0/width), -1-(1.0/height), 1.0, 1.0 ]
+
+		Return Self
+	EndMethod
+	
+	Method DestroyRenderImage()
+		TGLRenderImageFrame(frames[0]).DestroyRenderTarget()
+	EndMethod
+	
+	Method Init(UseImageFiltering:Int, pixmap:TPixmap)
+		Local prevFBO:Int
+		Local prevTexture:Int
+		Local prevScissorTest:Int
+
+		glGetIntegerv(GL_FRAMEBUFFER_BINDING, Varptr prevFBO)
+		glGetIntegerv(GL_TEXTURE_BINDING_2D,Varptr prevTexture)
+		glGetIntegerv(GL_SCISSOR_TEST, Varptr prevScissorTest)
+		
+		frames = New TGLRenderImageFrame[1]
+		frames[0] = New TGLRenderImageFrame.CreateRenderTarget(width, height, UseImageFiltering, pixmap)
+		
+		If prevScissorTest glEnable(GL_SCISSOR_TEST)
+		glBindTexture GL_TEXTURE_2D,prevTexture
+		glBindFramebuffer GL_FRAMEBUFFER,prevFBO
+	EndMethod
+	
+	Method Clear(r:Int=0, g:Int=0, b:Int=0, a:Float=0.0)
+		If frames[0] Then TGLRenderImageFrame(frames[0]).Clear(r, g, b, a)
+	End Method
+
+	Method Frame:TImageFrame(index:Int=0)
+		Return frames[0]
+	EndMethod
+	
+	Method SetRenderImage()
+		glBindFrameBuffer(GL_FRAMEBUFFER, TGLRenderImageFrame(frames[0])._fbo)
+
+		glMatrixMode(GL_PROJECTION)
+		glLoadMatrixf(_matrix)
+	
+		glViewport 0,0,width,height 
+	EndMethod
+	
+	Method ToPixmap:TPixmap()
+		Return TGLRenderImageFrame(frames[0]).ToPixmap(width, height)
+	EndMethod
+	
+	Method SetViewport(x:Int, y:Int, width:Int, height:Int)
+		If x = 0 And y = 0 And width = Self.width And height = Self.height
+			glDisable GL_SCISSOR_TEST
+		Else
+			glEnable GL_SCISSOR_TEST
+			glScissor x, y, width, height
+		EndIf
+	EndMethod
+EndType
+
+
+
+
 Public
 
 Type TGLImageFrame Extends TImageFrame
@@ -402,10 +645,12 @@ Type TGLMax2DDriver Extends TMax2DDriver
 		Return "OpenGL"
 	End Method
 
+	Method CreateRenderImageContext:Object(g:TGraphics) Override
+		Return new TGLRenderImageContext.Create(g, self)
+	End Method
+	
 	Method CreateFrameFromPixmap:TGLImageFrame( pixmap:TPixmap,flags:Int ) Override
-		Local frame:TGLImageFrame
-		frame=TGLImageFrame.CreateFromPixmap( pixmap,flags )
-		Return frame
+		Return TGLImageFrame.CreateFromPixmap( pixmap,flags )
 	End Method
 
 	Method SetBlend( blend:Int ) Override

+ 7 - 0
max2d.mod/driver.bmx

@@ -28,6 +28,13 @@ End Type
 
 Type TMax2DDriver Extends TGraphicsDriver
 
+	'Backend specific!
+	'implement this function in each TMax2D-extending type (OpenGL, DX, ..)
+	Method CreateRenderImageContext:Object(g:TGraphics)
+		Throw "Feature ~qRender2Texture~q not yet implemented in this graphics driver (" + ToString() + ")." 
+		Return Null
+	End Method
+
 	Method CreateFrameFromPixmap:TImageFrame( pixmap:TPixmap,flags:Int ) Abstract
 	
 	Method SetBlend( blend:Int ) Abstract

+ 231 - 0
max2d.mod/max2d.bmx

@@ -64,6 +64,7 @@ Import BRL.LinkedList
 Import BRL.Hook
 
 Import "image.bmx"
+Import "renderimage.bmx"
 Import "driver.bmx"
 Import "imagefont.bmx"
 
@@ -110,6 +111,7 @@ Type TMax2DGraphics Extends TGraphics
 	Global auto_imageflags:Int=MASKEDIMAGE|FILTEREDIMAGE
 
 	Field _graphics:TGraphics,_driver:TMax2DDriver,_setup:Int
+	Field _ric:TRenderImageContext
 	
 	Method Driver:TMax2DDriver() Override
 		Return _driver
@@ -231,6 +233,104 @@ Type TMax2DGraphics Extends TGraphics
 	Method Position(x:Int, y:Int) Override
 		_graphics.Position(x, y)
 	End Method
+
+
+	Method CreateRenderImage:TRenderImage(width:Int, height:Int, UseLinearFlitering:Int = True, max2DGraphics:TGraphics = Null)
+		If Not max2DGraphics Then max2DGraphics = self
+		Local max2D:TMax2DGraphics = TMax2DGraphics(max2DGraphics)
+		If Not max2D Then Return Null 'only supporting Max2D graphics
+		
+		If _ric And _ric.GraphicsContext() <> max2D._graphics
+			_ric.Destroy()
+			_ric = Null
+		EndIf
+		
+		If Not _ric	
+			_ric = TRenderImageContext(max2D._driver.CreateRenderImageContext(max2D._graphics))
+		EndIf
+		
+		'sanity check
+		?debug
+		Assert _ric <> Null, "The code for the current TGraphics instance doesn't exist yet for rendering to a texture, feel free to write one."
+		?
+
+		Return _ric.CreateRenderImage(width, height, UseLinearFlitering)
+	End Method
+
+	
+	Method DestroyRenderImage(renderImage:TRenderImage)
+		' sanity check
+		?debug
+		Assert _ric <> Null, "No TRenderImage instances have been created"
+		?
+
+		_ric.DestroyRenderImage(renderImage)
+	End Method
+
+
+	Method SetRenderImage(renderimage:TRenderImage)
+		' sanity check
+		?debug
+		Assert _ric <> Null, "No TRenderImage instances have been created"
+		?
+
+		_ric.SetRenderImage(renderimage)
+	End Method
+
+
+	Method CreatePixmapFromRenderImage:TPixmap(renderimage:TRenderImage)
+		' sanity check
+		?debug
+		Assert _ric <> Null, "No TRenderImage instances have been created"
+		?
+
+		Return _ric.CreatePixmapFromRenderImage(renderimage)
+	End Method
+
+
+	Method SetRenderImageViewport(renderimage:TRenderimage, x:Int, y:Int, width:Int, height:Int)
+		' sanity check
+		?debug
+		Assert _ric <> Null, "No TRenderImage instances have been created"
+		?
+
+		renderimage.SetViewport(x, y, width, height)
+	End Method
+
+
+	Method ClearRenderImage(renderimage:TRenderimage, r:Int=0, g:Int=0, b:Int=0, a:Float=0.0)
+		' sanity check
+		?debug
+		Assert _ric <> Null, "No TRenderImage instances have been created"
+		?
+
+		renderimage.Clear(r,g,b,a)
+	End Method
+
+
+	Method CreateRenderImageFromPixmap:TRenderImage(Pixmap:TPixmap, UseLinearFlitering:Int = True, max2DGraphics:TGraphics = Null)
+		If Not max2DGraphics then max2DGraphics = self
+		Local max2d:TMax2DGraphics = TMax2DGraphics(max2DGraphics)
+		If Not max2d Then Return Null ' only supports Max2D
+	
+		If _ric And _ric.GraphicsContext() <> max2d._graphics
+			_ric.Destroy()
+			_ric = Null
+		EndIf
+		
+		If Not _ric 
+			_ric = TRenderImageContext(max2D._driver.CreateRenderImageContext(max2D._graphics))
+		EndIf
+		
+		'sanity check
+		?debug
+		Assert _ric <> Null, "The code for the current TGraphics instance doesn't exist yet for rendering to a texture, feel free to write one."
+		Assert Pixmap <> Null, "Invalid pixmap"
+		Assert Pixmap.Width <> 0 And Pixmap.Height <> 0, "Invalid pixmap"
+		?
+
+		Return _ric.CreateRenderImageFromPixmap(Pixmap, UseLinearFlitering)
+	End Method
 End Type
 
 Rem
@@ -1049,6 +1149,137 @@ Function GrabPixmap:TPixmap( x:Int,y:Int,width:Int,height:Int )
 	Return _max2dDriver.GrabPixmap( x,y,width,height )
 End Function
 
+
+Rem
+bbdoc: Create a new render image
+about:
+@width, @height specify the dimensions of the render image.
+
+@useLinearFlitering defines the image flag to filter images when scaling.
+
+@max2DGraphics is an optional parameter to pass a custom Max2DGraphics context.
+
+returns: #TRenderImage with the given dimension
+End Rem
+Function CreateRenderImage:TRenderImage(width:Int, height:Int, useLinearFlitering:Int = True, max2DGraphics:TMax2DGraphics = Null)
+	Return gc.CreateRenderImage(width, height, useLinearFlitering, max2DGraphics)
+End Function
+
+Rem
+bbdoc: Create a render image from a given #TPixmap
+about:
+@pixmap defines the #TPixmap to create a new #TRenderImage from.
+
+@useLinearFlitering defines the image flag to filter images when scaling.
+
+@max2DGraphics is an optional parameter to pass a custom Max2DGraphics context.
+
+returns: #TRenderImage with the content of the passed #TPixmap
+End Rem
+Function CreateRenderImageFromPixmap:TRenderImage(pixmap:TPixmap, useLinearFlitering:Int = True, max2DGraphics:TMax2DGraphics = Null)
+	Return gc.CreateRenderImageFromPixmap(pixmap, useLinearFlitering, max2DGraphics)
+EndFunction
+
+Rem
+bbdoc: Destroy a no longer needed render image
+End Rem
+Function DestroyRenderImage(renderImage:TRenderImage)
+	gc.DestroyRenderImage(renderImage)
+End Function
+
+Rem
+bbdoc: Set a render image as currently active render target
+about:
+@renderImage defines the render image to use as target. Set to Null to render on the default graphics buffer again.
+End Rem
+Function SetRenderImage(renderImage:TRenderImage)
+	gc.SetRenderImage(renderImage)
+End Function
+
+Rem
+bbdoc: Clear content of the passed render image
+about:
+@renderImage defines the render image to clear.
+
+@r, @g, @b define the red, green and blue components of the clear color. Range is 0 - 255.
+
+@a defines the alpha value and is ranged 0.0 to 1.0.
+End Rem
+Function ClearRenderImage(renderImage:TRenderImage, r:Int=0, g:Int=0, b:Int=0, a:Float=0.0)
+	gc.ClearRenderImage(renderImage, r,g,b,a)
+End Function
+
+Rem
+bbdoc: Create a #TPixmap from a render image
+about:
+@renderImage defines the render image from where the #TPixmap is to generate
+
+returns: #TPixmap of the render image
+End Rem
+Function CreatePixmapFromRenderImage:TPixmap(renderImage:TRenderImage)
+	Return gc.CreatePixmapFromRenderImage(renderImage)
+End Function
+
+Rem
+bbdoc: Set the viewport of the given render image
+about:
+@renderImage defines the render image to set the viewport for
+
+@x, @y, @width, @height define the dimension of the viewport
+End Rem
+Function SetRenderImageViewport(renderImage:TRenderImage, x:Int, y:Int, width:Int, height:Int)
+	gc.SetRenderImageViewport(renderImage, x, y, width, height)
+End Function
+
+Rem
+bbdoc: Backup the render image (from GPU to RAM)
+about:
+When a running application is suspended (eg user logs out from the OS or hibernation) 
+then Direct3D-graphics loose their context ("D3DERR_DEVICELOST").
+To enable restoration an render image needs to "persist" as else after resume the texture
+will be blank.
+Use this for dynamically created render image content which you do not re-draw each frame.
+Also use #RenderImageValid() to check if content needs to be recreated.
+
+@renderImage defines the render image to backup
+End Rem
+Function PersistRenderImage:Int(renderImage:TRenderImage)
+	If renderImage Then Return renderImage.Persist()
+	Return False
+End Function
+
+Rem
+bbdoc: Check if render image content is still valid
+about:
+When a running application is suspended (eg user logs out from the OS or hibernation) 
+then Direct3D-graphics loose their context ("D3DERR_DEVICELOST") and so the textures.
+If that happens, the render image is flagged to no longer be valid.
+
+@renderImage defines the render image to backup
+
+returns: False if content the render image needs to be recreated
+End Rem
+Function RenderImageValid:Int(renderImage:TRenderImage)
+	If renderImage Then Return renderImage.Valid()
+	Return False
+End Function
+
+Rem
+bbdoc: Mark a render image (in-)valid
+about:
+When a running application is suspended (eg user logs out from the OS or hibernation) 
+then Direct3D-graphics loose their context ("D3DERR_DEVICELOST") and so the textures.
+Once you restored/recreated the content of your render image you can set it
+to be valid again.
+
+@renderImage defines the render image to backup
+
+@bool defines the new state of the valid flag (True or False)
+End Rem
+Function SetRenderImageValid(renderImage:TRenderImage, bool:Int = True)
+	If renderImage Then renderImage.SetValid(bool)
+End Function
+
 Const COLLISION_LAYER_ALL:Int=0
 Const COLLISION_LAYER_1:Int=$0001
 Const COLLISION_LAYER_2:Int=$0002

+ 44 - 0
max2d.mod/renderimage.bmx

@@ -0,0 +1,44 @@
+SuperStrict
+
+Import "driver.bmx"
+Import "image.bmx"
+
+
+Type TRenderImage Extends TImage
+	Field _valid:Int = 1
+
+	'returns wether the content is still valid. Might be blanked
+	'on "appsuspend" if no content persisting happened before
+	Method Valid:Int()
+		Return _valid
+	End Method
+
+	Method SetValid(bool:Int)
+		_valid = bool
+	End Method
+	
+	'ensure the GPU located render image would survive a "appsuspend"
+	'by eg. reading it into a TPixmap
+	Method Persist:Int()
+		Return False
+	End Method
+	
+	Method CreateRenderImage:TRenderImage(width:Int, height:Int) Abstract
+	Method DestroyRenderImage() Abstract
+	Method SetRenderImage() Abstract
+	Method Clear(r:Int=0, g:Int=0, b:Int=0, a:Float=0.0) Abstract
+	Method SetViewport(x:Int, y:Int, width:Int, height:Int) Abstract
+End Type
+
+
+Type TRenderImageContext
+	Method Create:TRenderimageContext(gc:TGraphics, driver:TGraphicsDriver) Abstract
+	Method Destroy() Abstract
+	Method GraphicsContext:TGraphics() Abstract
+
+	Method CreateRenderImage:TRenderImage(width:Int, height:Int, UseImageFiltering:Int) Abstract
+	Method DestroyRenderImage(renderImage:TRenderImage) Abstract
+	Method SetRenderImage(renderimage:TRenderImage) Abstract
+	Method CreatePixmapFromRenderImage:TPixmap(renderImage:TRenderImage) Abstract
+	Method CreateRenderImageFromPixmap:TRenderImage(pixmap:TPixmap, UseImageFiltering:Int) Abstract
+End Type