有没有办法检查Texture2D当前是否未被使用,所以我可以对它执行SetData()?

时间:2010-08-12 11:48:52

标签: c# vb.net xna

尝试在最近使用SpriteBatch的Draw() - n的Texture2D上执行SetData()会导致以下异常:

操作已中止。您不能修改已在设备上设置的资源,也不能修改在平铺括号中使用的资源。

我可以事先确定执行SetData()是否会抛出此异常吗?

3 个答案:

答案 0 :(得分:1)

基本上,您有三种选择:

1)看看SpriteBatch是否完成了它的操作,然后调用了SetData()。绘图方法通常是异步的。这意味着,它们只是被添加到please-render-me队列中,并且该方法立即返回。您需要的是绘图完成时的回调通知或Draw()的同步调用。

2)避免SetData()被中断。你可以把它放到一个我不推荐的关键部分。应该可以锁定纹理数据。它在Direct3D中称为LockRect(),它在XNA中应该类似。

3)应该有一些像Flush()这样的方法,等待所有与图形相关的操作完成。

对于相当含糊的帮助感到抱歉,但您应该能够从XNA文档中找到方法名称。

答案 1 :(得分:1)

基本上没有。

最简单的方法是只在SetData方法中拨打Update

SetData方法中使用Draw是不好的做法,因为该设备可能会使用旧数据执行各种巫毒魔法。详细解释了in the "Caution" box on its MSDN page

现在,直到XNA 3.1,您可以将SetDataOptionsTexture2D.SetData一起使用。但看起来纹理的功能已经removed in XNA 4.0

Shawn Hargreaves explains here如何使用SetDataOptions告诉GPU“实际上是的,我想要覆盖您可能正在使用的数据,不要抱怨”。为什么很难做对。

答案 2 :(得分:1)

我通过创建两个纹理并在活动的纹理之间切换来解决这样的问题,基本上是双缓冲:

void CreateTextures()
{

  depth_1 = new Texture2D(this.GraphicsDevice, width, height, false, SurfaceFormat.Single);
  depth_2 = new Texture2D(this.GraphicsDevice, width, height, false, SurfaceFormat.Single);

  depth_current = depth_1;

  ...

}

void Draw(GameTime gt)
{
  depth_current = depth_current == depth_1 ? depth_2 : depth_1;
  Depth.SetData(this.DepthBuffer);

  ...

}

在我的情况下,无法将SetData移到Draw之外,但我认为这是最好的方法。