Closed schn4v1d closed 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.
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.
How do I ensure that? EDIT: or rather how do I change that?
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.
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.
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.
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.
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.
THANK YOU SO MUCH IT FINALLY WORKS
You're welcome. 😄
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 :/