Jump to content

Rick Brewster

Administrator
  • Posts

    20,644
  • Joined

  • Last visited

  • Days Won

    376

Posts posted by Rick Brewster

  1. Basically it's like this,

    1. Paint.NET is placing a correctly formed DIBV5 on the clipboard. I'm going to assume this unless proven otherwise, such as via an in-depth technical discussion by experts here at https://forums.getpaint.net/topic/122848-pasting-dibv5-image/)
    2. Apps have varying degrees of buggy ways of copying and pasting DIBV5s
    3. DIBV5 is supposed to be a simple format, but it isn't due to how it's evolved over the last ~30 years and its poor documentation/specification
    4. This led to DIBV5 essentially being an ambiguously defined format due to both its buggy specification and inconsistent implementations across many, many apps
    5. PNG does not have any of these issues and is far superior in all ways except for encoding performance (i.o.w. how long it takes to copy it to the clipboard). This could probably be rectified if we got a PNG library with a "super fast compression" mode (which may already exist, although WIC certainly doesn't support that unfortunately).
    6. Therefore, if a PNG is on the clipboard alongside the DIBv5, just use the PNG. All this pain would be avoided if Firefox and Paint Tool SAI would just do that.

     

    DIBV5 should be considered a legacy clipboard format at this point, only included for the sake of apps that don't (yet) handle PNG. No matter what changes I make to the DIBV5 clipboard copy/paste code, it's guaranteed that a bunch of other apps will either 1) not copy its data to the clipboard correctly such that PDN will handle it, or 2) not read PDN's DIBV5 from the clipboard correctly. This is what happens Every. Single. Time. I. Have. Ever. Changed. The. Clipboard. Code. It is not possible to get 100% compatibility between all apps. At this point you need the equivalent of winning a case at the US Supreme Court to get me to change this code (which I considered that discussion linked in #1 to be an example of). It's not worth the trouble otherwise.

    • Like 1
    • Upvote 1
  2. 10 hours ago, Tactilis said:

    I'm not sure in v5.x to what extent the GPU handles this

    This is unchanged in 5.0. Layer composition still happens on the CPU and that is unlikely to change because of how much GPU VRAM would be required to hold all your layers. I tried it in the early days of 4.0’s development and it was a disaster. And you’d still have linear performance with respect to layer count.

     

    Nowadays we have quite decent float32 performance on the CPU and I’m not too worried about it for the next engine upgrade.

     

    It would work fine on a pro/workstation class card with lots of memory (up to 48GB!). These cards, such as the NVIDIA RTX 5000 Ada, have twice the RAM but cost 4x as much compared to the equivalent consumer card. So you get 32GB for $4000 versus a GeForce 4080 Super with 16GB for $1000. Not worth it!

    • Thanks 1
  3. I've been using your original code as a means of experimenting/researching into compute shaders in the PDN v5.1 code base. It would be easy for me to add compute shader support for the next servicing release of 5.0, which would be 5.0.13, as it's just exposing the necessary interfaces and methods in the Direct2D wrappers. There's still no support in ComputeSharp.D2D1 for this.

     

    So I've converted it over to a compute shader. It gets much trickier when doing this as you have to manage your own scheduling (numthread and thread groups). I've implemented it such that each "thread" (one invocation of Execute()) writes an 8x4 block of pixels (pixel shader always writes out 1x1 per invocation). I use a resource texture to supply all of the sampling offsets, along with a bitmask indicating which pixel will use that sample. This lets me, for an 8x4 region anyway, only read each input pixel once instead of 8 times.

     

    The performance speedup isn't dramatic: on a large 8192 x 4500 px image, at radius=100 and Full sampling, your original code takes ~13.5 seconds to render, while mine takes ~8.5 seconds. When I bump it up to 12 iterations of HiLo() -- which is necessary to get the right amount of precision to avoid banding artifacts -- it runs in about ~12.5 seconds. So, not really any performance gain but there is a really good quality gain. Oh, and this was on a GeForce 4090!

     

  4. On 2/3/2024 at 8:50 AM, _koh_ said:

    What will happen if I DrawImage() straight alpha data to Pbgra32? I'm doing this.

    If you're just drawing without any blending -- which means either 1) first drawing call after Clear(), or 2) using CompositingMode.SourceCopy, then it's basically just memcpy()

  5. On 1/30/2024 at 12:38 PM, lynxster4 said:

    I've been playing around with your plugin also. I think it's great. I'm getting some very nice 'watercolor' effects.

    Then add Sharpen+, or Emboss/Relif+, or TGMagnitude and things really start to 'pop'. I think it should be in the 'Artistic' menu. Great job! 😊

     

    Did you know about Effects -> Noise -> Median? That's what this new plugin is replicating, but running it on the GPU :) The CPU version (the built-in Median) is actually faster, too -- as it turns out, doing a median calculation is very expensive to do on the GPU!

    • Upvote 1
  6. 13 hours ago, _koh_ said:

    What you are suggesting is intentionally use D2DInputComplex to prevent shader linking and split them up?

    No -- shader linking can only link a simple shader to another simple shader. I was just linking to D2D's documentation as a side note.

     

    Do you mind if I take this code and run with it? I might be able to turn it into a more fleshed out plugin, or even incorporate it into Paint.NET itself. I know @BoltBait has been asking me for a Median effect he can use in his plugins, and this might do the trick better than the median approximation algorithm in Median Sketch.

     

     

  7. 55 minutes ago, _koh_ said:

    So linked shader and shader function work differently? interesting.

    With shader linking, they should be equivalent (there are restrictions on this). But that's mostly a performance thing and I'm not sure that's what you mean.

     

    What I'm saying is that you can think of a shader's simple inputs as being equivalent to function parameters, e.g. float4 Execute(float4 simpleInput1, float4 simpleInput2). (You can't write the code like that, but like I said it's conceptually equivalent/isomorphic.)

     

    The shader's Execute() method would only call HiLo() once. The value for d would just be plugged in as a shader const (a private readonly field). Input 0 would stay the same and would be complex (D2DInputComplex), but Input 1 would be hooked up to the previous instance's output and would be simple (D2DInputSimple).

     

    So instead of:

     

    input -> Shader(call HiLo 8 times) = output

     

    You'd have:

     

                     SourceImage              
                         |
                         +---------------------------+-------------...-------------+
                         |                           |                             |
                         v                           v                             v
    Flood(0.5f) -> Shader(call HiLo once)-> Shader(call HiLo once) ... -> Shader(call HiLo once) = output
                         d=0.5                     d=0.25                       d=...

     

    Flood is used to provide the initial value for c.

     

    This would calculate the same thing, and it might even be slightly slower, but it would either eliminate or greatly reduce the lag imposed on the rest of the system because the GPU can "take a break" between each HiLo() call. Shaders can't be pre-emptively paused/resumed like CPU threads, IIUC, they must run to completion and can lock up the GPU or the whole system.

  8. 3 hours ago, worker404 said:

    I wanted very much to have a version of Paint Net for mobile phones.

    You're asking for a completely different app. Paint.NET can't just be "ported to mobile phone." That's like asking to add a bed to your life raft because you can't always use your yacht. Yes, they're two superficially similar things, but they're also just ... not similar.

     

    3 hours ago, worker404 said:

    all photo editing applications for Android are, in the strictest sense, programs for “adding filters to images” and lack basic features

    Because that's all you can really fit onto a mobile device's screen

     

    4 hours ago, worker404 said:

    I really hope you think about making a version of pdn for Android that contains all the features of the desktop version.

    Never going to happen, and this has been communicated clearly since PDN's inception almost 20 years ago.

     

    If you need Paint.NET, then use your PC. If you can't use your PC, then that's just a completely different issue? I can't solve all of your problems.

  9. Are there strings that you edited that got missed? That's possible, it's happened before, and unintentional. Just point them out to me and I'll make sure they get picked up for the next update.

     

    It is not necessary to "create an issue" in Crowdin (for Paint.NET anyway) -- that actually just adds a ton of noise. I go through every change in the activity log, which catches most things, and then I do search queries for things like "translation added but not yet approved" or "translation changed since approval", etc.

     

    Sometimes when there are two translators making edits (which I'm not sure is the case for Corsican), it can be difficult to figure out which translation to use.

  10. I played around with this a bit and it's really interesting! It definitely has some performance problems, but I think that could be improved -- I believe each invocation of HiLo() could be put into its own node in the shader graph, which would help avoid bogging down the GPU scheduler (pre-emptive scheduling does not seem to be a thing) as it appears to need to fully execute a shader before it can task-switch out to something else. This "temporal separability" is a major advantage of the algorithm you've devised here. So the shader would take two inputs, the first being the source image and the second being the output of the previous shader. Then chain it 8 times.

     

    Where did you come across this algorithm? Searching for "hi-lo algorithm" gives me a bunch of discussion about ... databases?

  11. There is nothing official for this, and I won't be providing it.

     

    However, for an upcoming major release (let's call it 6.0) I am planning on redoing/revamping the .PDN file format. I am hoping to include with this a public specification of the file format to better enable interoperability.

     

    The new versions of Paint.NET will be able to open both the old and new .PDN format files, but old versions of Paint.NET will obviously not be able to open the new format.

     

    This format revamp will then open the door for new features, e.g. higher bit-depth pixels, layer folders, etc. Right now the .PDN format is kludgy (it's based on .NET's binary object serialization) and not worth amending with these for various reasons.

    • Like 1
    • Upvote 4
  12. 1 hour ago, BoltBait said:

    Because I'm rendering letter by letter, the math involved would break my brain.

     

    You can do this by leveraging some DirectWrite stuff that I haven't wired up yet. No "math" involved, it will just tell you where to draw each glyph (letter). But, it's a bit more work. I can definitely get this wired up for v5.1 and then show you the ropes. I can probably make it "really easy" to use.

×
×
  • Create New...