nickbabcock / Pfim

.NET Standard targa (.tga) and direct draw surface (.dds) image decoder
https://nickbabcock.github.io/Pfim/
MIT License
108 stars 18 forks source link

DDS: BC6H/BC7 support #16

Open Krakean opened 6 years ago

Krakean commented 6 years ago

https://nofile.io/f/Oa1YSoHmwqX/BC7files.rar (BC7 files only)

If you need more, here you can download Compressonator (https://github.com/GPUOpen-Tools/Compressonator/releases) and produce BC7/BC6H files by yourself. Also, useful command line examples (since GUI is kinda sux) - https://github.com/GPUOpen-Tools/Compressonator/blob/master/Compressonator/RunTime/example.bat

Hopefully not too much issues for one day :)

P.S. Didn't saw any C# dds reader that support BC6H/BC7. Plenty in C++, but none in C# :( Hopefully Pfim will be first one :) P.P.S BC6/7 specification:

  1. https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt
  2. https://msdn.microsoft.com/en-us/library/hh308953.aspx
  3. https://msdn.microsoft.com/en-us/library/hh308952.aspx
Krakean commented 6 years ago

@nickbabcock May be you can find this reading interesting/helpful - http://www.reedbeta.com/blog/understanding-bcn-texture-compression-formats/

nickbabcock commented 6 years ago

Thank you for the good read!

Krakean commented 6 years ago

@nickbabcock https://github.com/richgel999/bc7enc16 - may be you can find this interesting. At least its decomp part.

nickbabcock commented 6 years ago

I think I'm going to have to put this issue on hold. I've tried integrating CSharpImageLibrary's BC6/7, but I haven't been able to do it cleanly. I'm sure it's possible, but it does rely on APIs not available to .NET Standard in decoding. Also the first BC7 image I found did not load (but it is certainly impressive that it loaded BC6 nicely). Other libraries that you've found as well (I see you've asked for support in them too 😄 ) don't support BC6/7 -- BC6/7 is difficult. There's obviously a demand, but I feel like if we want a good portable C# implementation, there needs to be a company backing the development. If only Unity open sourced their implementation (afaik they support it)! To complete this issue would take someone with considerably more determism and knowledge in this space, and I fear that I'll easily burn out if given to me.

Related, I shudder at what ASTC must take to implement.

Krakean commented 5 years ago

@nickbabcock May be this might help you: https://github.com/xdanieldzd/Scarlet/tree/master/Scarlet/Drawing/Compression There is BC7(BPTC.cs) and BC6H(BPTCFloat.cs) implementations that are based on C's library "detex". May be you can took this already-ported code and integrate into Pfim?

nickbabcock commented 5 years ago

Thanks for the tip, I'm bookmarking those!

Krakean commented 5 years ago

@nickbabcock Seems like no progress so far? Anyway, there is another library - https://bitbucket.org/Starnick/teximpnet/src - that implements BC7/BC6H, code specifically here - https://bitbucket.org/Starnick/teximpnet/src/acf2d0a8d7f635d11bd47345cfc9a6e6b22cecff/TeximpNet/DDS/?at=master, good thing that content of DDS folder doesn't depend on entire TeximpNet library and can be easily cutted of for Pfim purposes.

nickbabcock commented 5 years ago

Seems like no progress so far?

Yeah, time constrained. A lot of projects I maintain.

https://bitbucket.org/Starnick/teximpnet/src

Nice link. I may be wrong, but all the heavy lifting is done through freeimage and nvidia text tools, so I don't know how applicable it is.

Krakean commented 5 years ago

@nickbabcock

I may be wrong, but all the heavy lifting is done through freeimage and nvidia text tools, so I don't know how applicable it is.

DDS component is standalone, doesn't rely on any element from library. The only connection on DDS side to library - is the Surface class, which is used only when writing DDS to file. But there also Write methods that accept plain stream, so this Write() method which takes library's Surface class as input also can be safety removed. And DDS importer/exporter completely written in C#, so no any depend on nvtt/freeimage at all

Krakean commented 5 years ago

@nickbabcock One last thing - you need to have "hardware" example, as opposite to Pfim.Viewer, using MonoGame (which is really simple) to display dds & targas, because: a) Only this way you can display BC6H/BC7, because Pfim.Viewer[Forms] does not support drawing compressed GPU formats, you need to use MonoGame which provide rendering api. b) Since you "optimization-maniac", and like to write fast code, and according to Pfim's benchmarks which shows really good speeds in compare with competitors, Pfim can be really interesting for gamedev needs (and, considering, that dds & tga are more than enough for textures needs) for those who want fast fully managed C# solution without using C++ dlls to keep project structure clean. So, hardware Pfim.Viewer would be really nice as test case to check how quickly Pfim load dds/tga as textures and how Pfim display it and check stability / different formats in general. By the way, to help you a bit, made minimal MonoGame & NET Core example for you which loads dds (when you Left or Right click using mouse) from dds subfolder. Uses Pfim, by the way. Download link: https://nofile.io/f/WwtcUXH7GOE/MyGame.zip, so hopefully you will extend it as needed (+ need to add support for tga, I tested only on dds) and upload it as Pfim.Viewer.MonoGame or whatever name you will choice, all up to you :) So, to sum up, it really nice to have just one solution for loading dds/tga, with good support of this formats (and specifically DX10-level compressions like BC6H/BC7)

nickbabcock commented 5 years ago

Download link: https://nofile.io/f/WwtcUXH7GOE/MyGame.zip, so hopefully you will extend it as needed (+ need to add support for tga, I tested only on dds) and upload it as Pfim.Viewer.MonoGame or whatever name you will choice, all up to you :)

Thank you for your example. I had been thinking that a MonoGame example would be tough, but your example shows that it is easy enough. But then why use Pfim at all when MonoGame supports more formats? (Is MonoGame missing DX10 dds?)

Krakean commented 5 years ago

@nickbabcock

But then why use Pfim at all when MonoGame supports more formats?

Because I don't use MonoGame. I writing my own rendering engine :) So Pfim is useful to those, who working on their own game/rendering solutions like me.

Krakean commented 5 years ago

@nickbabcock Just in case, not sure whether I gave you it or not, but some time ago I found another image library that implemented BC6/BC7 - https://github.com/KFreon/CSharpImageLibrary (https://github.com/KFreon/CSharpImageLibrary/tree/master/CSharpImageLibrary/DDS), and seems like its working. But I guess TexImpNet is more preferred solution, because at least author is still supporting it and available for contact, in compare to CSharpImageLibrary which is abandoned. But, you have now at least three projects to choice from, and all MIT, so there will no problem for you to grab needed code from those projects :)

nickbabcock commented 5 years ago

Right, I'll need to see how each library does the matrix / vector operations (like how DirectXTex uses DirectXMath). Creating an IPfimMath interface extension point, that you've mentioned before, seems like a recipe for a lot of work 😄

nickbabcock commented 5 years ago

Originally posted by @Krakean in https://github.com/nickbabcock/Pfim/issues/26#issuecomment-478330800 (contents copied to keep everything in the main thread)

I need to figure out a game plan for how I want to tackle it

Let me try to help you a bit :) First of all, you need easy to use tool to get BC6H/BC7 files. There is two popular choices - AMD Compressonator (https://github.com/GPUOpen-Tools/Compressonator) and DirectXTex tools (https://github.com/Microsoft/DirectXTex/wiki), last one seems much easier to me. You can download Texconv utility from DirectXTex releases section (there is also handy one - texdiag utility, to display extended info about image for example), and use this command line to get BC7 files for example: texconv -dx10 -y -ft DDS -f BC7_UNORM -o C:\path\where\to\save C:\path\to\source\image.tga You will get image.dds file in result. Then, you need reference viewer. DdsView from DirectXTex is good to go. Usage is simple: ddsview.exe C:\path\to\dds\file.dds If you won't download DirectXTex and compile DdsView by yourself, here is compiled from latest master for you - https://nofile.io/f/8RNaV0hfF06/DDSView.exe A few already made samples for you - https://nofile.io/f/quWjeAr4xh4/BC6-7-samples.rar (they made using true-24.tga from your Tests images folder, but guess for BC6 need to use source image with alpha because BC6 is all about alpha after all, and BC7.dds is separated image with a motocycle found somewhere on the internet)

Second, reference library to start with. :) Well, I guess its always best to start with DirectXTex's BC6/7 as reference source, but its in C++. In case of C#, despite the fact I advised you here at least three libraries already, my suggestion to start with https://github.com/KFreon/CSharpImageLibrary (_once you compile it, you will have UIProject.exe as demo application, also take attention on small note below), BC6/7 code of this library is adapted from BC6/7 DirectXTex (sadly author not noted which revision of DirectXTex he used) Its abandoned, but its working (tested on BC7.dds from samples archive above): https://i.imgur.com/kwbNOKt.png (here you can see UI bug - BC7 bike image loaded, but UI consider that its still loading, not sure on which side bug is - on library side, or on UI demo side, but anyway we got image), it also load fine (though, with the same UI bug which is not seen if you feed DXT5 for example) BC6H_UF16.dds (https://i.imgur.com/5Wq5VtB.png), though it cannot load BC6H_SF16.dds, but still its better than nothing :)

** - small note about compiling. Its cannot resolve UsefulThings package, so just open 'Manage Nuget Package', uninstall UsefulCsharpThings package, and just type it in 'Browse' and install again.


Made a few changes to CSharpImageLibrary, may be it will help you just a bit: https://nofile.io/f/oMfpVdSXqT5/CSharpImageLibrary.zip a. Should compile fine, with UsefuLCsharpThings package included. b. Fixed (https://i.imgur.com/jg9jGDc.png) "Loading" UI bug as seen in my screenshots above, author incorrectly disabled preview generation for BC6/7 dds files :) c. Removed all save-related & encoders methods for DDS files, since Pfim is just decoding library and thus you interested only in decoding, not in encoding DDS files :) DDS code went from 260kb to 159kb as result

nickbabcock commented 5 years ago

@Krakean, if you want, you can try integrating the BC6/BC7 logic into Pfim and I can test it out along the way. It seems that if DirectXTex is continuously updated, then there'll need to be a long term BC6/BC7 champion in Pfim in order to keep up with the updates.

Krakean commented 5 years ago

@nickbabcock

if you want, you can try integrating the BC6/BC7 logic into Pfim

All I can do is just take CsharpImageLibrary's DDS sources, place it somewhere in Pfim, and use its dds loading function for BC6H/BC7. It will be very rough and unpleasant approach. So to be honest better you as library author decide how you would like to integrate it. As-is for beginning, or more smoothly integrate it into current Pfim structures/logic/architecture (which you know better than I do).

It seems that if DirectXTex is continuously updated

Yes, it is. But translating from C++ to C# will take much more time, than integrating already working solution in case with CSharpImageLibrary (CSIL, for short). Which one is better to go with is up to you, but to be honest translating DirectXTexture's BC6H/BC7 code to C# is way more better approach (just like you did with FarmHash, which I also use), but it will require from you much more time. So, what ways we have: a) Integrate CSIL's BC6H/BC7 code into Pfim, with respect/necessary-changes to Pfim structures and architecture (thus, avoiding duplicated code that I guess both CSIL and Pfim have regarding to DDS/DXT/BC*). And once it is working, leave it as is, release Pfim 1.0 and forget about it. :) b) a + see ways optimize it. This is why I like your Pfim and Farmhash. For consistency and very optimized code. Though, you frequently lacks comments in code :) c) Translate DXTex BC6/7 to C#. Its just one BC6HBC7.cpp 150kb, which also contains encoder code so I guess in reality just decoding code will be not more than ~80kb. And somewhere in between don't forget about b). :) Though, if to look at update history - https://github.com/Microsoft/DirectXTex/commits/master/DirectXTex/BC6HBC7.cpp - not much changes these years, and mostly cosmetics refactoring and encoder optimizations, so I guess a) is still easy way to go and more likely CSIL's BC6H/7 code is pretty close to original...

For you to get as fast working result as possible - a) is preferred. In long-play c) is better (may be)

P.S. Dont forget to bring MonoGame-based example to Pfim samples [instead of or in addition to WinForms-based sample], so at least BC6/7 can be tested in their "natural" environment which is gfx hardware :) But even for DXT-based dds it will be good too, for consistency.

nickbabcock commented 5 years ago

I think you are being modest. It would be a huge boon if you could integrate CSIL and verify BC6H / BC7 images work. Even if the code isn't perfect, we can iteratively massage it to fit.

Ah yes, MonoGame, I'll put it on my todo list (thanks for the example again)

Krakean commented 5 years ago

@nickbabcock

and verify BC6H / BC7 images work

Well, if you will upload MonoGame-based example adapted to Pfim needs, then I'll have testbed for testing them (because BC6H/BC7 cant be displayed in current Pfim.Viewer), and then I can try to make initial dirty, but careful, work on integrating CSIL's DDS into Pfim :)

nickbabcock commented 5 years ago

(because BC6H/BC7 cant be displayed in current Pfim.Viewer)

For my curiosity, why is that? I figured if other dds formats can be displayed with Pfim.Viewer, why can't BC6H and BC7?

Krakean commented 5 years ago

It does not support drawing compressed GPU formats, since it uses a System.Drawing-like API not a rendering API like D3D11, so a block compressed format would have to be decompressed before drawn.

nickbabcock commented 5 years ago

so a block compressed format would have to be decompressed before drawn

Right. DXT 1/3/5 are block compressed and are decompressed before displaying in Pfim.Viewer -- or am I missing something?

Krakean commented 5 years ago

@nickbabcock Well, good news I suppose. It working (see right side of screenshot): https://i.imgur.com/bx7P6ZS.png (BC7-UNorm) Though, somehow R & B channels are mixed. Same problem for BC6. So, both are working, but need to find out how R/B channels became mixed... either its due to WPF/DX (in case of CSIL) and OpenGL (in case of mine Pfim.Viewer3D using MonoGame.OpenGL), or CSIL's author do some special channel mixing on UI side (for WPF?), not sure, need to find out, because I didn't touch any decoding algorithms.

Loading currently made in very hacky way: https://i.imgur.com/7WJW0Tb.png But I guess once I find out why R/B are mixed, I'll make some cleanup here and there to give out code to you clean as possible. And remove CSIL's BC1-5 decoders :) And then will give it to you to make it beautiful and incorporate into Pfim structure, because currently there is a lot of Pfim/CSIL general DDS code intersection which you will need to cleanup as who knows Pfim better :)

Or, in my case better is to give you current state of work as it-is (at least, it is working), and you can finish the rest and impart all of this the final form within Pfim?

kotn3l commented 1 year ago

Is there any update on this? Thank you.

nickbabcock commented 1 year ago

There already is some support via #66 #63. Have those not met your needs?