问题
I'm trying to draw on the screen pixel-by-pixel using XNA, but am having problems with resources. I thought the best way would be to have 1 texture that updates every frame, but I'm having trouble updating it. Here's what I've got so far, just as a test:
Texture2D canvas;
Rectangle tracedSize;
UInt32[] pixels;
protected override void Initialize()
{
tracedSize = GraphicsDevice.PresentationParameters.Bounds;
canvas = new Texture2D(GraphicsDevice, tracedSize.Width, tracedSize.Height, false, SurfaceFormat.Color);
pixels = new UInt32[tracedSize.Width * tracedSize.Height];
base.Initialize();
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
pixels[100] = 0xFF00FF00;
canvas.SetData<UInt32>(pixels, 0, tracedSize.Width * tracedSize.Height);
spriteBatch.Begin();
spriteBatch.Draw(canvas, new Rectangle(0, 0, tracedSize.Width, tracedSize.Height), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
When Draw() is called the second time, I get the following error:
"The operation was aborted. You may not modify a resource that has been set on a device, or after it has been used within a tiling bracket."
If I try to make a new Texture2D in Draw(), I quickly get an out of memory error. This is for Windows Phone. It seems like I'm trying to do it the wrong way, what other options do I have to make it work?
回答1:
Try setting GraphicsDevice.Textures[0] = null
before you call SetData. Depending on the effect you're after there may be a more performant method, you could also consider Silverlights WriteableBitmap.
Edit: This is the code I tested in the emulator:
Texture2D canvas;
Rectangle tracedSize;
UInt32[] pixels;
protected override void Initialize()
{
tracedSize = GraphicsDevice.PresentationParameters.Bounds;
canvas = new Texture2D(GraphicsDevice, tracedSize.Width, tracedSize.Height, false, SurfaceFormat.Color);
pixels = new UInt32[tracedSize.Width * tracedSize.Height];
base.Initialize();
}
Random rnd = new Random();
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
GraphicsDevice.Textures[0] = null;
pixels[rnd.Next(pixels.Length)] = 0xFF00FF00;
canvas.SetData<UInt32>(pixels, 0, tracedSize.Width * tracedSize.Height);
spriteBatch.Begin();
spriteBatch.Draw(canvas, new Rectangle(0, 0, tracedSize.Width, tracedSize.Height), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
回答2:
You basically need to do as it asks in the exception:
To ensure that the texture is not set on the graphics device, put this at the end of Draw
:
GraphicsDevice.Textures[0] = null;
To ensure you are not drawing inside a tiling bracket, do not use SetData
inside of Draw
at all. Move the call to SetData
into Update
.
Bonus info: Your out-of-memory error is because you are not releasing the unmanaged resources that Texture2D
allocates (the garbage collector can't track them, so it doesn't know you're running out of memory). You need to call Dispose
on the texture. However making a new texture each frame is a bad idea anyway (there's no way to avoid the performance and memory fragmentation problems it causes).
来源:https://stackoverflow.com/questions/4837471/how-to-draw-2d-pixel-by-pixel-in-xna