Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vertex Texture Fetch Not Supported #2602

Closed
DissidentDan opened this issue May 21, 2014 · 31 comments

Comments

Projects
None yet
5 participants
@DissidentDan
Copy link
Contributor

commented May 21, 2014

Vertex Texture Fetch is not currently supported by Monogame. It would be great to have support for it. High-priority platforms for me are Windows (DirectX) and PS4.

@tomspilman

This comment has been minimized.

Copy link
Member

commented May 21, 2014

I'll look into this in the next few days. I'm sure I can make it work pretty quickly.

@DissidentDan

This comment has been minimized.

Copy link
Contributor Author

commented Jul 11, 2014

In the latest development branch, this is still not working for Windows (DirectX). The texture parameters show up in the list of the effect's parameters, but their Data members are all null.

@DissidentDan

This comment has been minimized.

Copy link
Contributor Author

commented Jul 15, 2014

If this is low on your priority list, I might take a crack at it...provided you can provide me with a bit of info to get started. What data structures are involved and how are they used? What parallel code for pixel shader textures could I reference?

@tomspilman

This comment has been minimized.

Copy link
Member

commented Jul 15, 2014

provided you can provide me with a bit of info to get started

Well first question... if you were going to set the texture on the vertex shader, how would you do it? Like this...

Device.Textures[0] = myVertexTexture;

But then how do we know if that should be set on the pixel or vertex shader? There are seperate texture registers for each stage including the vertex and pixel stages. Do we set them to both? That is then unnecessary work in 99% of the cases.

XNA avoided this by never allowing you to directly set a texture on the vertex stage. It depended on the FX system to do this for you. This sucks and hides functionality away from the user.

@KonajuGames

This comment has been minimized.

Copy link
Contributor

commented Jul 15, 2014

For backwards compatibility, we could assume GraphicsDevice.Textures[] is
for pixel shader only and add GraphicsDevice.VertexTextures[] to set
textures on the vertex shader.​

I'm open to other suggestions as well.

@tomspilman

This comment has been minimized.

Copy link
Member

commented Jul 15, 2014

add GraphicsDevice.VertexTextures[] to set textures on the vertex shader.

Yea... that is probably the right path moving forward. As we add other shader stages this will only get more complex. This would mean a bigger refactor of TextureCollection and SamplerStateCollection.

But first... how does this work on OpenGL? Are vertex texture/sampler stages separate or "unified" or something?

@KonajuGames

This comment has been minimized.

Copy link
Contributor

commented Jul 15, 2014

But first... how does this work on OpenGL? Are vertex texture/sampler
stages separate or "unified" or something?

It gets messy.

On Android, support is spotty. Some GPU/OS combinations support it, some
don't.

On iOS, it appears that the texture must be referenced​ in the fragment
shader in order for it to be accessible in the vertex shader.
http://blog.angusforbes.com/texture-lookups-in-a-vertex-shader/

GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS reports how many textures can be set on
the vertex shader. Apparently ATI/AMD cards supporting SM3 report 16, but
don't actually support vertex texture fetch.

Some texture slots are used for both vertex and fragment shaders. Some
texture slots are for fragment shader only.
http://www.opengl.org/wiki/Vertex_Texture_Fetch

@tomspilman

This comment has been minimized.

Copy link
Member

commented Jul 15, 2014

Some texture slots are used for both vertex and fragment
shaders. Some texture slots are for fragment shader only.

So how do we manage this? It would mean that...

GraphicsDevice.Textures[0] = firstTexture;
GraphicsDevice.VertexTextures[0] = secondTexture;

... would have very different behavior on DirectX and OpenGL platforms.

Is this mess something we just have to leave in the users lap? Just tell them to ensure their texture/sampler states don't overlap between stages to ensure best capability? Or can we do something better with either the API or in the effect compiler?

@DissidentDan

This comment has been minimized.

Copy link
Contributor Author

commented Jul 15, 2014

Konaju,

The ATI cards not supporting vertex texture fetch were the first generation of SM3 cards from ATI, the X1000 series, which is now 8-9 years old. X2000 and onward support VTF properly.

@DissidentDan

This comment has been minimized.

Copy link
Contributor Author

commented Jul 18, 2014

Supporting all the platforms seems like it will be a significant undertaking. Personally, I am interested only in Windows (DX or GL) and PS4 at the moment. I can understand if you want to take the "all-or-nothing" approach. That's one reason why I wouldn't mind just implementing this in my own fork for the platforms for which I need it.

If you think this can come online within 2 weeks, I can wait. Otherwise, I would appreciate any direction on where to look for implementing this.

@tomspilman

This comment has been minimized.

Copy link
Member

commented Jul 18, 2014

Supporting all the platforms seems like it will be a significant undertaking.

Realize this discussion here is only about coming up with a good API. We don't have to implement it across all the platforms to start.

Personally, I am interested only in Windows (DX or GL) and PS4 at the moment.

I understand... unfortunately we have to think ahead a little before we jump in and code.

If you think this can come online within 2 weeks,

It depends. The code work itself for DX and PS4 is pretty easy. We just need to decide on the API design.

@DissidentDan

This comment has been minimized.

Copy link
Contributor Author

commented Jul 20, 2014

Thanks for responding. I hope this doesn't come off as peevish, but I am working on a quite tight schedule. As this sounds like it might take a while to decide upon, I think I'll have to dig in myself. I would really appreciate some pointers (pun not intended) on the parts of the framework that I'll have to deal with.

I assume there's some stuff in MGFX that I'll need to change to make sure that the data structures associated with the Effect are set up correctly, and then I'll need to store the data in the Device somewhere, and then ultimately send the data through SharpDX.

@tomspilman

This comment has been minimized.

Copy link
Member

commented Jul 23, 2014

I assume there's some stuff in MGFX that I'll need to change

Maybe... maybe not.

I think the 2MGFX code already can handle a sampler/texture reference in the vertex shader. You can simply try processing the effect with a vertex texture fetch, then set a breakpoint in ShaderData.Write() ...

https://github.com/mono/MonoGame/blob/develop/Tools/2MGFX/ShaderData.writer.cs#L7

... and be sure the samplers are being written.

I am 90% certain it already works.

I'll need to store the data in the Device somewhere,

I think this is already handled as well. You can see in the Shader constructor that similar to 2MGFX it reads in the sampler information even for vertex shaders.

https://github.com/mono/MonoGame/blob/develop/MonoGame.Framework/Graphics/Shader/Shader.cs#L55

It is almost like I planned things this way when I wrote the code originally. :)

(I probably did)

then ultimately send the data through SharpDX

For the quickest possible hack I would simply add this to TextureCollection.SetTextures:

var vertexShaderStage = device._d3dContext.VertexShader;

if (_textures[i] == null || _textures[i].IsDisposed)
   vertexShaderStage .SetShaderResource(i, null);
else
   vertexShaderStage .SetShaderResource(i, _textures[i].GetShaderResourceView());

... just along side what we already do for the pixel shader. This will just make it set the textures on both the pixel and vertex shaders. Not optimal, but will work if you are not render state bound.

A similar change would need to be done to SamplerStateCollection.PlatformSetSamplers().

@tomspilman

This comment has been minimized.

Copy link
Member

commented Jul 23, 2014

One more thing....

In EffectPass.Apply you'll need to set the textures from the vertex shader to the graphics device:

https://github.com/mono/MonoGame/blob/develop/MonoGame.Framework/Graphics/Effect/EffectPass.cs#L111

This would basically be the same as what it does below for the pixel shader. Not all this (the TextureCollection.SetTextures, SamplerStateCollection.PlatformSetSamplers() technique) ould depend on you manually setting the sampler/texture registers to be sure the vertex and pixel shaders don't assign different textures to the same registers.

The alternative implementation here could be to not change TextureCollection.SetTextures or SamplerStateCollection.PlatformSetSamplers at all. Then simply directly set the vertex textures/samplers in the EffectPass.Apply code.

@DissidentDan

This comment has been minimized.

Copy link
Contributor Author

commented Jul 24, 2014

Thanks, Tom. I'm looking into this now. I'll let you know how it goes.

It turns out that MGFX writes out the the data correctly. (I had an issue with the MonoGame 3.0 binaries naming some texture parameters after the sampler instead of the texture, but rebuilding the binaries with latest source code fixes that.)

The MG content processor also doesn't include FX parameters for texture/samplers that aren't used by the shader, which is different behavior from XNA. It's easy enough to handle, but perhaps it should be documented.

@tomspilman

This comment has been minimized.

Copy link
Member

commented Jul 24, 2014

doesn't include FX parameters for texture/samplers
that aren't used by the shader, which is different
behavior from XNA

We are aware of that.

We depend on the results of the DirectX shader compiler. We gather all the parameters it says are used by each shader compiled and use that to build the list of all the properties to put into the final Effect. The benefit is that we only include what is actually used meaning smaller effect files, no unused properties in system memory, simple to tell when a parameter isn't working, etc.

I am unsure how the Microsoft FX compiler (which MGFX tries to mimic) handles this. I guess it is independently parsing all the FX parameters out itself and not depending on the shader compiler results. The benefit of this is that you can quickly comment out some HLSL code and not need to change your C# code to match.

It seems better to me not to include "fake" parameters.

@DissidentDan

This comment has been minimized.

Copy link
Contributor Author

commented Jul 24, 2014

It appears that I basically have it working. RenderDoc shows the textures being bound to the vertex stage. However, the data in my textures is borked. It might be a texture format swizzling thing.

@DissidentDan

This comment has been minimized.

Copy link
Contributor Author

commented Jul 24, 2014

I have vertex texture fetching working for DX11. Based on Konaju's comments, it could possibly work for OpenGL, but I have not tested it.

Here is the commit:
DissidentDan@dabb941

There is one snafu I've run into: I cannot set the data on more than 16384 16-byte vertices. Anything beyond that is garbage data. Everything that I've tracked as far as looking at the SharpDX data structure for the vertex buffer and looking at the arguments supplied to SharpDX calls looks fine, so I'm not sure what the deal with that is.

@tomspilman

This comment has been minimized.

Copy link
Member

commented Jul 24, 2014

I cannot set the data on more than 16384 16-byte vertices

That isn't a 16bit index value... a 16bit index can address up to 65,535 verts.

Still could be some sort of feature level limitation. See...

http://stackoverflow.com/a/24811074

@DissidentDan

This comment has been minimized.

Copy link
Contributor Author

commented Aug 9, 2014

Yes, I understand that. Sorry if there was any confusion...I was indicating the size of my vertices (4 floats).

@tgjones

This comment has been minimized.

Copy link
Contributor

commented Feb 15, 2015

Just thought I'd mention, because I don't see it in the thread above, that XNA, right back to v1, did have GraphicsDevice.VertexSamplerStates and GraphicsDevice.VertexTextures. (docs here and here)

However, as per the discussion in #3471, any decision we make on this now probably needs to take Direct3D 12 / Metal into account.

@tgjones

This comment has been minimized.

Copy link
Contributor

commented Mar 6, 2015

@tomspilman @KonajuGames would you accept a pull request implementing GraphicsDevice.VertexTextures and GraphicsDevice.VertexSamplerStates (i.e. matching XNA) for Direct3D 11?

I found #2998 - I guess it hasn't been merged because it also includes a number of unrelated changes? Between dabb941 and 2406faa, most of the necessary code seems to be there. Maybe they could be cherry-picked into a new PR. I'm happy to do that.

Since this is just matching an existing XNA API, I'm hoping we can add it now, even if we need to revisit the broader GraphicsDevice API again in the future, when we look at Metal / Direct3D 12 / Vulkan.

(As a motivating example: several terrain algorithms - geoclipmapping, CDLOD, even sometimes geomipmapping - rely on sampling a heightmap in the vertex shader. That's what I'd like to use it for. It's something I previously had working in XNA.)

@DissidentDan

This comment has been minimized.

Copy link
Contributor Author

commented Mar 6, 2015

Let me know if there's anything I can do to help.

@tgjones

This comment has been minimized.

Copy link
Contributor

commented Mar 7, 2015

Cool, thanks @DissidentDan. Let's see what @tomspilman and @KonajuGames think.

@tgjones

This comment has been minimized.

Copy link
Contributor

commented Mar 9, 2015

I think I'm going to go ahead and implement this, because it's holding me up, and I'll optimistically hope that it will be accepted. Obviously I'll be happy to change it after discussion.

@KonajuGames

This comment has been minimized.

Copy link
Contributor

commented Mar 9, 2015

Sure @tgjones . Sorry for the delay in responding. Lots of other things happening, and unfortunately some threads get missed in the process.

@tomspilman

This comment has been minimized.

Copy link
Member

commented Mar 9, 2015

would you accept a pull request implementing GraphicsDevice.VertexTextures and GraphicsDevice.VertexSamplerStates (i.e. matching XNA) for Direct3D 11?

Sure.... I totally didn't realize XNA already had that feature in this way.

Still doesn't change the questions about OpenGL support, but it can be stubbed out for now.

I found #2998 - I guess it hasn't been merged because it also includes a number of unrelated changes?

Yes... that is exactly why that didn't get quickly merged. Cherry picking from it would be a good place to start.

when we look at Metal / Direct3D 12 / Vulkan.

Yeah... no worries about that for now.

@tgjones

This comment has been minimized.

Copy link
Contributor

commented Mar 11, 2015

Great, thanks @KonajuGames and @tomspilman. I'll hopefully submit a PR later today.

I'll stub out OpenGL support for now. I am interested in getting it working on OpenGL, but that can be done separately.

@DissidentDan

This comment has been minimized.

Copy link
Contributor Author

commented Mar 11, 2015

The biggest roadblock with OpenGL is that the version of MojoShader (the tool that converts the MS Effect framework shaders into OpenGL shaders) is pretty old and doesn't support texture sampling in vertex shaders.

@tomspilman

This comment has been minimized.

Copy link
Member

commented Mar 11, 2015

MojoShader (the tool that converts the MS Effect framework shaders into OpenGL shaders) is pretty old and doesn't support texture sampling in vertex shaders.

That will just have to wait for our removal of MojoShader then.

@flibitijibibo

This comment has been minimized.

Copy link
Contributor

commented May 27, 2015

Some work regarding vertex textures in OpenGL (because MojoShader or not it's going to be really fun for the author):

The way vertex textures are done in XNA4 is that is basically just takes the last 4 sampler slots available for the D3D9 graphics device, and calls those "vertex" textures. Those samplers then get sent to the vertex shader's sampler registers with modified indices (so if you use register 0 in the shader, the new register is now maxSamplers - 4 + 0).

Whoever implements this will need to both send the vs_s? samplers those new uniform values as well as ensure that VertexTexture/VertexSamplerState applications will apply to the right texture image unit. The relevant work for this in FNA can be nabbed from here:

flibitijibibo@2f52bd8
flibitijibibo@15a9c7b

The FNA Effect now depends on MojoShader even at runtime, so the shader-specific changes are found here:

flibitijibibo/MojoShader@eca4c73...af2d6e1

Also note that vertex sampler state changes also need to be applied in the right place, so you'll need to check which shaders the samplers are used in, and it might be both vertex and pixel!

Other MojoShader work related to vertex texture/sampler parsing can be found in the gigantic MojoShader-FNA patch (though the good news is you only care about the diffs in mojoshader.c, the rest is either Effect support or FNA-specific changes like glProgramViewportFlip):

http://flibitijibibo.com/mojoshader-fna.patch

It's a lot of junk, but the result is there! Using the vertex texture visual test code:

http://www.flibitijibibo.com/images/vtexgl.png

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.