UltravioletFramework / ultraviolet

The Ultraviolet Framework is a .NET game development framework written in C#.
https://github.com/UltravioletFramework/ultraviolet/wiki
MIT License
542 stars 46 forks source link

Draw Rendertarget2D #72

Closed schn4v1d closed 6 years ago

schn4v1d commented 6 years ago

Is there a way to directly draw a Rendertarget2D via spriteBatch? In my current solution I create a texture2D from the data of the rendertarget which utterly destroys my framerate :/

tlgkccampbell commented 6 years ago

A RenderTarget2D is made from one or more instances of RenderBuffer2D, at least one of which is usually a color buffer. You can use these render buffers directly as textures; they inherit from the Texture2D class.

tlgkccampbell commented 6 years ago

Just make sure that the target isn't bound for writing when you try to read from it, or bound for reading when you try to write to it.

schn4v1d commented 6 years ago

How do I ensure that? EDIT: or rather how do I change that?

tlgkccampbell commented 6 years ago

Render buffers are "bound for writing" when the target which owns them is bound for writing, i.e. when it's set as the current render target. You can therefore unbind them by reverting to the back buffer, or to a different render target, using SetRenderTarget().

Textures are "bound for reading" when they're attached to one of the samplers. You can forcibly unbind a sampler by using the SetTexture() method on IUltravioletGraphics -- the latest version of Ultraviolet should ensure that SpriteBatch always uses sampler 0.

schn4v1d commented 6 years ago

Okay So it is bound for writing when assigned as the current render target and bound for reading when "unassigned". But how do I assign it again? Because that's what's producing

"An unhandled exception of type 'System.InvalidOperationException' occurred in Ultraviolet.Core.dll The resource cannot be written because it is currently bound for reading."

for me right now.

tlgkccampbell commented 6 years ago

It's not bound for reading when it's "unassigned." It's possible that the render target isn't bound to anything at all. It becomes bound for reading when it's being used as a texture.

So basically, imagine the following situation:

gfx.SetRenderTarget(mytarget); // <--- mytarget becomes bound for writing
// ... draw the render target ...
gfx.SetRenderTarget(null); // <--- mytarget becomes unbound

spriteBatch.Begin(SpriteSortMode.Deferred);
spriteBatch.Draw(colorbuffer, ...); 
spriteBatch.End(); // <--- colorbuffer becomes bound for reading

The SpriteBatch binds colorbuffer to sampler 0 so that it can render it. If you don't do anything else, then when the next frame comes around, it's still going to be bound to that sampler, which will cause SetRenderTarget() to throw the exception you're seeing.

So you need to explicitly tell the graphics subsystem that you're done rendering to the texture:

spriteBatch.Begin(SpriteSortMode.Deferred);
spriteBatch.Draw(colorbuffer, ...); 
spriteBatch.End(); // <--- colorbuffer becomes bound for reading
gfx.SetTexture(0, null); // <--- colorbuffer becomes unbound

Binding another texture to the same sampler will also unbind the first texture, but this makes it explicit.

tlgkccampbell commented 6 years ago

There's also an UnbindAllTextures() method on IUltravioletGraphics, which will forcibly unbind all of the textures from all of the samplers. This may be useful in some circumstances but is probably overkill if you know, as you do, that you're using one sampler in particular.

tlgkccampbell commented 6 years ago

And actually -- wow, it's been a while since I've looked at this code -- there's also an UnbindTexture() method which will unbind the specified texture from all samplers that it's currently bound to.

schn4v1d commented 6 years ago

THANK YOU SO MUCH IT FINALLY WORKS

tlgkccampbell commented 6 years ago

You're welcome. 😄