Render to Texture

BlitzMax Forums/BlitzMax Programming/Render to Texture

col(Posted 2016) [#1]
Source code: Render 2 Texture

Hi all,

As a result of a request for a 'render to texture' feature for BlitzMax I've made an initial effort just to get the ball rolling to see how it develops. Consider this an early alpha test just to get some initial feedback on if it works for your setup, and if you like the code that you need to write to get it working, or if anything drastic needs to be changed etc then to know at this stage would be better to know now than later.


The main goals behind this effort are...
1. Create a unified single command set to allow creating and rendering to a texture for the GLMax2D, D3D9Max2D and D3D11Max2D graphics drivers. This is to aid keeping the underlying technique as transparent to the user as possible. D3D7Max2D is considered too old for todays current hardware so there will be little interest in writing code for this driver. Other drivers, for example the SDL driver for MaxNG, will be considered when the time arises.

2. The command set should be as small as possible, down to some simple create and use functions. The less the coder does means it will be easier and less confusing to use.

3. Operate seemlessly with all of the current Max2D drawing commands with as little impact on any code changes as possible.

4. Work with both the legacy BlitzMax compiler and Bruceys MaxNG compiler.



Current development will be using the legacy compiler before writing the code for the MaxNG compiler.

There are some module tweaks that I know will be needed for this to be finalised but just for now I'll save them for later. I'd prefer at this early stage for people not to mess with modules just yet and they are only a small tweaks, but do have a major impact on functionality. As it is things are working on my set up but YMMV.


Issues that will be fixed with the module updates are...
1. Currently, for Dx9 you will get EAVs if you switch from full screen to windowed and visa-versa. Fixed with a modification to d3d9graphics.bmx
2. The Dx11 driver Cls isn't working. I know why this is and have a fix, but again it will need a module tweak. Fixed with a modification to d3d11max2d.bmx and d3d11graphics.bmx
3. Switching graphics drivers... I haven't tested this just yet however I'm pretty much 100% certain will not work properly at this stage. Updated and fixed.

So all in if you wouldn't mind having an initial play that would great just to see how things are initially.

Cheers!

ps In the source code there are some example files. These are little demo apps just to get something up and running on screen. Feel free to change the Max2DDriver to see if its initially working on your setup. All feedback is very welcome.


GW(Posted 2016) [#2]
A working 'render to texture' in Blitzmax has existed for almost a decade btw. Searching the forums and code archives will yield working versions.


Derron(Posted 2016) [#3]
There existed solutions but they were only OGL or DX...with different commsndsets and no interchangeability


Also it is good to have this done by someone who did a dx11 mod...


Will try to test the code tomorrow when at my computer again.

Bye
Ron


col(Posted 2016) [#4]
Yes, I should have outlined the main reasons behind why this little project popped up, thanks Derron.

I've edited the first post accordingly.


Derron(Posted 2016) [#5]
Here is a another simple sample:


Strict

Import "renderimage.bmx"

SetGraphicsDriver GLMax2DDriver()
'SetGraphicsDriver D3D9Max2DDriver()
Local gc:TGraphics = Graphics(800, 600)

SetBlend AlphaBlend

Local rt:TRenderImage = CreateRenderImage(gc, 800, 600)
SetRenderImage(rt)
Cls
SetRenderImage(Null)

MidHandleImage(rt)

local currentRotation:int = 0
While Not KeyDown(KEY_ESCAPE)
	' render into the texture
	SetRenderImage(rt)
		SetRotation currentRotation
		SetScale 0.90, 0.90
		DrawImage(rt, GraphicsWidth()/2, GraphicsHeight()/2)
		currentRotation = (currentRotation + 5) mod 360
		SetScale 1.0, 1.0

		SetRotation 0
		DrawOval(0,0, 10,10)

	' switch back to render to the original backbuffer
	SetRenderImage(Null)
	Cls
	SetColor 255,255,255
	DrawImage(rt, GraphicsWidth()/2, GraphicsHeight()/2)

	DrawText "Render 2 texture: " + GetGraphicsDriver().ToString(), 0, 0
	Flip
Wend
End



PS: wonder why your
DrawImage(rt), MouseX(), MouseY()
works (see main.bmx) ... I mean the closing bracket after "(rt".


Maybe "DW" could come up with some nice samples (as he enjoys the single-buffer-approaches).


bye
Ron


col(Posted 2016) [#6]
PS: wonder why your
DrawImage(rt), MouseX(), MouseY()
works (see main.bmx) ... I mean the closing bracket after "(rt".


That's actually a typo and should have been DrawImage(rt, MouseX(), MouseY())
I'm in a transitional period of putting parenthesis around the outer function parameters for all functions, not the individual parameters themselves but in the same way as a C language variant requires them.

The reason it works in that each of the parameters are expressions so (rt) is just a normal expression. All blitz languages have the feature of only requiring the outer most parenthesis when you want the value returned from the function, if you don't want the return value then you don't need them. In this case it works according to that feature.


Derron(Posted 2016) [#7]
Regarding DX7

Is it that much "work" or just a slight lazyness (its weekend!)? Just asking because DX7 is an "official module" of BlitzMax.

So if one wants to "support" DX7 they could not just use that r2t.


But I assume this would be the same for some kind of generic "shader support" (which is another "wish" - for some effects many casual games have - like blurred/desaturated backgrounds when a menu is open).

So if no means no ... I will accept that ;-)


bye
Ron


col(Posted 2016) [#8]
So if no means no ... I will accept that ;-)

Heh, It's open source feel free to implement Dx7 if you want to and we'll include it in but yeah I personally can't be bothered to support it at this time due to a number of reasons. I never say 'never' though :D

A similar style of functions for a unified shader set could be created in due course.


Derron(Posted 2016) [#9]
Seeing this does not really look similar to yours.

Maybe DX7 needs a bit more "done" to make it work.

According to that gamasutra article there are multiple ways to achieve that render-to-texture functionality with DX7.


I dumbfully thought of an easy transition (replacing D3D9*** with D3D7***) ... but hey if that was so easy, you would already have done it :-)


bye
Ron


col(Posted 2016) [#10]
What's your thoughts on handling this scenario?

The Dx9 render targets need to be destroyed and recreated when transitioning using alt-tab when in fullscreen mode.

The problem is that any data that's in a render texture will be lost when the texture is destroyed. The destruction and recreation code is done and automatic but what's on my mind is handling any existing texture data.

So I was thinking of having these 2 options

1. to have a callback function that will allow the coder to put texture data back into the image if they want any specific data in it at that time of the transition.
2. have a convenience function that when called would take a 'snapshot' of the current texture data, this would be used to automatically recreate the texture so that it survives the destruction and reconstruction phase. A side effect of this would require another function if a coder then wanted to change their mind and send the texture to option 1.

The 'snapshot' feature may turn out slow and may not be suitable for every frame due to the nature of pulling data from the gpu being an inherently slow process anyway.

What's your thoughts on this?

EDIT
As it happens I think I have a way to handle this completely automatically so that the texture survives the transition every time... time for some sleep though.


Derron(Posted 2016) [#11]
Re Scenario
If you talk about the multiple approaches: I would try to use the most simple one even if it wont work on all HW.


@ Destroying textures
How do you intend to inform each texture about the "onDestroy" and "onRecreate" (or similar?
Shouldn't this need some kind of event system or "texture manager" which knows every texture?

Without that I can only imagine a "if myG <> GetGraphics() then RecreateMyself()"-approach.


bye
Ron


col(Posted 2016) [#12]
.double post


col(Posted 2016) [#13]
@Texture management
One of the reasons I created the TRenderImageContext was in case any kind of regular 'boiler-plate' code crept in, which it did almost immediately. It also serves as a nice place for texture management :O)

I've updated the repo to include the dx9 render-texture persistance through the alt-tab scenario.

If you wouldn't mind testing when you get some time, that would be cool.
Cheers.

Still more to do for dx11 :p


col(Posted 2016) [#14]
I've upped the modifications required for dx11 to the repo in my sig.

I noticed that in your example you're binding a render target and then rendering the texture of the render target into itself. I know that this is a No-No in Dx11 and will not work.


col(Posted 2016) [#15]
Also just upped a fix to allow changing graphics drivers while the code is running.


Derron(Posted 2016) [#16]
@ drawing rt into rt

How to tackle this then?
How to have something like that "Mirror in a mirror in a mirror ..." thing?

With defeault you have to copy an image first because you else modify the source when writing to the target. Another classic approach (single buffer) is
Draw
- grabpixmap
- draw grabbed
Flip
Draw
...


PS: did not have had time for DX9-tests, preparing next main-release of my game and some users brought up "need!!!"-features ;-)


bye
Ron


col(Posted 2016) [#17]
How to tackle this then?

You would normally have 2 textures. The one that you want to render, and the one that you want to render into, except that don't clear the render-texture between frames?


Derron(Posted 2016) [#18]
But this would add another draw each loop (the one of the "non-render-target-texture")?!

switchActiveTex(tex1, tex2)
drawOnActiveTex( inactiveTex )
drawOnActiveTex( the added stuff )
flip


Hmm, that should work. Glad I would use it more for bringing together "components" of an composite image (eg. skinnable GUI-widgets) .


Wonder where DW is once we need him to test this properly with his effect-demos :-)


bye
Ron


Bobysait(Posted 2016) [#19]
You can swap the textures between two renders (the one to happen and the one to render to)

CurT = T1; T1 = T2; T2=CurT
Render on T1 buffer with T2 drawn inside
CurT = T1; T1 = T2; T2=CurT
Render on T1 buffer with T2 drawn inside
etc ...

You'll maybe notice the current frame showing the previous frame so it may feel laggy or not.


col(Posted 2016) [#20]
Glad I would use it more for bringing together "components" of an composite image

That's the main idea behind it with the ability to do that in the main loop if you choose to.

'render-to-texture' came about initially for reasons such as rendering a scene into car mirrors, rendering a video to a texture that's used for a tv screen, viewing through a 'warp portal' and other fun stuff :o)

There will always be 1 extra draw call to draw the texture itself after rendering into it.


dw817(Posted 2016) [#21]
Hello. Yep, I'm still here. With questions - always. :)

I just need a simple example, preferably, without calling a library.

I have the working code for the example HERE:

http://www.blitzbasic.com/Community/posts.php?topic=107224

Which is almost perfect. I just need to be able to have BLACK $000000 show through as transparent instead of opaque as it is now, and anything brighter than $000000 such as $010101 to show as black opaque.

If I can get someone to make a fix in the code 107224 to do that, then that will be fine for me, answers my question, and opens up the easy ability to write directly to TIMAGES as screen objects.