MonoGame / MonoGame

One framework for creating powerful cross-platform games.
http://www.monogame.net
Other
11.1k stars 2.86k forks source link

Texture2d GetData throws Not implemented exception #644

Closed rsolberg1 closed 9 years ago

rsolberg1 commented 11 years ago

Issue is in the 3d branch. I am currently porting a game from WP7 XNA to WIndows 8 Metro using MonoGame With SharpDX.

Exception is thrown by the following line: graphicsDevice._d3dContext.CopySubresourceRegion(_texture, level, null, stagingTex, 0, 0, 0, 0);

Seems like the implementation of CopySubresourceRegion is missing in the SharpDX 2.2.0.7 build implementation (SharpDX.Direct3D11.dll) and not in the MonoGame framework itself. Strange, because whoever did the job first time would have the SharpDX implementation correct.

I am using the MonoGame GetData Method to pick a texture area from a sprite: Texture2DSpriteSheet.GetData(0, rec1, col1, 0, scoreNumber.Width * scoreNumber.Height);

tomspilman commented 11 years ago

Interesting.

Well the API does work with the version of SharpDX in the official MonoGame 3rd-party libs... I know because our game uses it to grab screenshots. Can you give that version a try...

https://github.com/kungfubanana/MonoGame-Dependencies/tree/master/SharpDX/Windows%208%20Metro

I guess i'll see about updating to the latest SharpDX release and looking for this error.

rsolberg1 commented 11 years ago

Thanks Tom!

I swapped the dll's with the ones from the url you passed. Still no success. The spritesheet is a png image on 310x28px loaded as Resource from an XNB file. The loading works fine. I am using GetData to pick a rectangle area of 21x28px starting at position (0,0) in the png image. Should not be rocket science. Here is a screenshot:

https://fbcdn-sphotos-a.akamaihd.net/hphotos-ak-ash4/486942_10151111895170700_1540960638_n.jpg

rsolberg1 commented 11 years ago

My mistake here Tom. I was a bit too fast when stepping through the lines. Ofcourse, the rect.HasValue property is true in the if check above the marked line - casting the not implemented exception causing the Compiler to enter the else-statement. I Guess this will be work in progress?

tomspilman commented 11 years ago

Ah... makes sense. I only implemented the full copy path when I wrote it.

If you get a chance to implement the sub region copy submit a pull request... if not i'll get to it before 3.0 ships. I have a ton of things on my plate right now so I cannot make any promises as to exactly when.

rsolberg1 commented 11 years ago

I have extended the GetData function on the DirectX part to support sprite-textures by getting a rectangular area from inside the sourceTexture:

        var desc = new SharpDX.Direct3D11.Texture2DDescription();

        if (rect.HasValue)
        {
            desc.Width = rect.Value.Width;
            desc.Height = rect.Value.Height;
        }
        else
        {
            desc.Width = width;
            desc.Height = height;
        }
        desc.MipLevels = 1;
        desc.ArraySize = 1;
        desc.Format = SharpDXHelper.ToFormat(format);
        desc.BindFlags = SharpDX.Direct3D11.BindFlags.None;
        desc.CpuAccessFlags = SharpDX.Direct3D11.CpuAccessFlags.Read;
        desc.SampleDescription.Count = 1;
        desc.SampleDescription.Quality = 0;
        desc.Usage = SharpDX.Direct3D11.ResourceUsage.Staging;
        desc.OptionFlags = SharpDX.Direct3D11.ResourceOptionFlags.None;

        using (var stagingTex = new SharpDX.Direct3D11.Texture2D(graphicsDevice._d3dDevice, desc))
        lock (graphicsDevice._d3dContext)
        {
            // Copy the data from the GPU to the staging texture.
            if (rect.HasValue)
            {
                var sourceRegion = new SharpDX.Direct3D11.ResourceRegion()
                {
                    Top = rect.Value.Top,
                    Left = rect.Value.Left,
                    Bottom = rect.Value.Bottom,
                    Right = rect.Value.Right,
                    Front = 0,
                    Back = 1,
                };

                graphicsDevice._d3dContext.CopySubresourceRegion(_texture, level, sourceRegion, stagingTex, 0, 0, 0, 0);

            }
            else
                graphicsDevice._d3dContext.CopySubresourceRegion(_texture, level, null, stagingTex, 0, 0, 0, 0);

            // Copy the data to the array.
            SharpDX.DataStream stream;
            graphicsDevice._d3dContext.MapSubresource(stagingTex, 0, SharpDX.Direct3D11.MapMode.Read, SharpDX.Direct3D11.MapFlags.None, out stream);
            stream.ReadRange(data, startIndex, elementCount);
            stream.Dispose();
        }
Voll3r commented 11 years ago

Hi Guys,

not sure to what extent the issue tracker on codeplex is being used, but this seems to be the same issue as this one here: http://monogame.codeplex.com/workitem/7010

I'm not using SharpDX, only Mono and OpenTK and I get the same exception. This is on Linux with both 2.5.1 as well as develop3d.

Any news would be appreciated :)

Cheers, Matt

rsolberg1 commented 11 years ago

Hi Matt!

Yes, it's the same issue as presented on codeplex. I did a test-implementation of the sub-region rect extraction which I never checked in about 4 months ago. Looked like the code-sample above. Unfortunately it does not seem to work any more. The extracted textures gets all wrong now - the color byte array returned contains the wrong values and I am not sure if it is SharpDX which plays me a trick here. Would be Nice to know if you could manage to make the if-clause work on Linux With OpenTK

rsolberg1 commented 11 years ago

tomspilman: Would you be able to assist on subregion extraction in MonoGame from a Texture2D where the code today is marked with "Throw not implementedException"? Line 563 in the current develop3d branch: https://github.com/mono/MonoGame/blob/develop3d/MonoGame.Framework/Graphics/Texture2D.cs

tomspilman commented 11 years ago

I haven't looked into this... your code above seems like it should work. Should be just some debugging needed to figure out the issue.

Also make sure your not trying to read a DXT compressed texture... those are compressed in memory and you will get what seems like garbage back.

rsolberg1 commented 11 years ago

The content processor for the xnb image Resources has the Texture Format set to Color. I have tried to compile them as both Color and DxtCompressed with the same result. The colors in the array looks to be within the correct range of colors, but as you say the image looks like Garbage. The Texture2D constructor seems to wire up the surface format as a variable which also will be used from the GetData method and I start thinking it might be worth trying to initialize every instance of Texture2D and pass in the surface format with the constructor before calling GetData or SetData just to avoid re-usage of invalid declarations. or old Texture2D References in memory. This became a hard one to debug :-s

totallyeviljake commented 11 years ago

I hijacked Ray's issue: https://github.com/mono/MonoGame/issues/1091 with a discussion of this very topic. Per @slygamer advice, I enabled the Android GetData() methods and I was able to get SantaShooter working, somewhat. I found thusfar that I could not create RenderTarget2D objects outside of the draw loop. In cocos2d-xna we do this when we create CCLabelTTF objects (true type labels). Once I removed the construction of the labels (not just adding them to the component tree), I was able to get to the actual game play. During our sprite collision code, we GetData() on the sprites to test of alpha collisions. This worked once and then the second time it appeared to fail. See the last error I posted on Ray's OpenTK issue post.

So displaying textures from PNG -> XNB content processed images works just fine. RenderTarget2D appears to have issues, but I have not investigated this further.

Chaosus commented 9 years ago

@tomspilman I guess this issue is obsolete and should be closed. SharpDX is about 3.0.0 version today, and I have not problems with GetData on Windows 8.