nickbabcock / Pfim

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

Load dds file without uncompressing it #1

Closed feliwir closed 6 years ago

feliwir commented 9 years ago

Hello, first of all this is a very nice library (exactly what i was looking for). But would it be possible to add loading of dds images without uncompressing them, so i can do that on the gpu? Would be a really neat feature for developing with opentk and stuff

nickbabcock commented 9 years ago

Sure I see no reason why this feature wouldn't be possible. I myself might be interested in this feature too, I just lack the know how. Since I don't have sufficient knowledge, I have a couple questions:

How do you envision the resulting API? Right now it is a single call to Load, but it sounds like to support the GPU this will probably change.

Is it possible that to support a generic interface, so that opencl, cuda, etc, can use it? Maybe some image formats this is possible, while others it is not?

Let me know what you're thinking

nickbabcock commented 9 years ago

I suppose it is also possible to create specialized subprojects like Pfim.OpenCL or Pfim.Cuda

feliwir commented 9 years ago

I was attempting to use OpenTK, since gpu's these days have fixed functions to decode dds compressed data. The call for this is glCompressedImage2D (see here: http://users.telenet.be/tfautre/softdev/ddsload/explanation.htm). So what does need to be exposed to the user:

A project which does this really well (in C++) is gli: https://github.com/g-truc/gli/blob/master/gli/core/load_dds.inl

I think opentk has an example for this aswell somewhere. A general note: writing a decoder in Cuda/OpenCL is slower than using the OpenGL function. All it needs as parameters is the compressed data and format

nickbabcock commented 9 years ago

So, would the optimal solution be a C# interface on GLI? :smile:

feliwir commented 9 years ago

Nah, it would be optimal if I could just access the compressed data :)

Krakean commented 6 years ago

@nickbabcock Curious, was this issue solved?

nickbabcock commented 6 years ago

@Krakean, no this issue is still outstanding. If you have an example or resources on how to decode dds or tga images on the gpu (from compressed texture data) in C#, I may take a look so I can properly test an implementation.

Krakean commented 6 years ago

@nickbabcock Take a look here please - https://github.com/OpenSAGE/OpenSAGE/blob/master/src/OpenSage.Game/Data/Dds/DdsFile.cs This is how it used - https://github.com/OpenSAGE/OpenSAGE/blob/master/src/OpenSage.Game/Content/TextureLoader.cs

Not sure, but may be it can help you a bit

nickbabcock commented 6 years ago

Thanks for the links! It looks like OpenSAGE is using veldrid. So I'll have to check that project out.

feliwir commented 6 years ago

hey @nickbabcock I am a member of OpenSage. There is no need for you to implement the gpu decoding of in Pfim. Since there are multiple graphics backends that can dds decoding it’s the best approach if you make the compressed dds data available (so the user of Pfim can upload that to the gpu in whichever manner he likes). Since you already have the software dds decoder in place it shouldn’t be too much effort to turn off the decoding (if specified) and access the compressed data.

nickbabcock commented 6 years ago

Right, right -- yeah my wording came off a bit wrong. Pfim wouldn't touch the body, but I needed to see how OpenSAGE used veldrid so that I can take make sure the interop is good (eg. so I can add an example to docs, etc)

tgjones commented 6 years ago

I think if the compressed data is exposed as a simple byte[], then we can use “fixed” to copy it to a Veldrid (or whatever) texture in a reasonably performant manner.

nickbabcock commented 6 years ago

So I was playing around with veldrid and veldrid.ImageSharp to get a feel for the APIs. I wanted to display a jpg in a window and I'm ashamed to say that I haven't been able to figure it out 😊

I set everything up

Sdl2Window window = VeldridStartup.CreateWindow(ref windowCI);
GraphicsDevice gd = VeldridStartup.CreateGraphicsDevice(window);
ImageSharpTexture sharpTexture = new ImageSharpTexture(@"my.jpg", false);
Texture texture = sharpTexture.CreateDeviceTexture(gd, gd.ResourceFactory);
CommandList commandList = gd.ResourceFactory.CreateCommandList();

and have a draw function

private static void Draw(GraphicsDevice gd, CommandList cl, Texture texture)
{
    // But where to use texture?
    cl.Begin();
    cl.SetFramebuffer(gd.SwapchainFramebuffer);
    cl.SetFullViewports();
    cl.End();

    gd.SubmitCommands(cl);
    gd.SwapBuffers();
    gd.WaitForIdle();
}

But since I can't figure out to send the texture to the screen, it's blank!

I tried following OpenSage's DrawingContext2D down to SpriteBatch but I couldn't tell how it's rendered onscreen. If anyone knows what I'm missing, it'd be greatly appreciated 😄

mellinoe commented 6 years ago

@nickbabcock Veldrid is a very low-level API, so you have to set up quite a few things in order to draw a textured object. There is a sample project that shows how to draw a textured cube. Drawing a 2D textured square is a little simpler. Feel free to reach out if you try it and get stuck.

nickbabcock commented 6 years ago

Yeah maybe I'm trying to bite off more than I can chew, as I have very limited prior experience with 3D graphics. My end goal is to demonstrate loading a dds image and give the user a choice of decoding on the gpu / cpu. Technically nothing needs to be displayed, but I would like to verify the sample code's correct! I don't have to use veldrid -- and I wouldn't want veldrid to hand hold me from 0 to 60. However I show a sample of gpu image decoding would be a win in my book.

I really should look up the difference between vertex and index buffers 😝

nickbabcock commented 6 years ago

It's been a long time waiting, but below is an example of loading DDS without decompressing the block compressed images:

var data = File.ReadAllBytes(path);
var image = Dds.Create(data, new PfimConfig());
var image2 = Dds.Create(data, new PfimConfig(decompress: false));

Assert.False(image.Compressed);
Assert.True(image2.Compressed);
Assert.NotEqual(image.Data, image2.Data);
Assert.Equal(image.Format, image2.Format);
image2.Decompress();
Assert.Equal(image.Data, image2.Data);

If you don't want the cpu decompression, you can figure out the BC algo with

if (image2.Header.PixelFormat.FourCC == CompressionAlgorithm.D3DFMT_DXT3)
{
}

This functionality will be in the next release (TBD), and I'm assuming that sooner rather than later is preferred.

nickbabcock commented 6 years ago

This feature has been included as part of 0.5.1, feel free to try it and suggest improvements.