Showing posts with label javafx. Show all posts
Showing posts with label javafx. Show all posts

Tuesday, 19 December 2017

jjmpeg, jni, javafx

So I guess the mood took me, I somehow ended poking away until the very late morning hours (4am) the last couple of nights hacking on jjmpeg. Just one more small problem to solve ... that never ended. Today I should've been working but i've given up and will write it off, it's nearly xmas break anyway so there's no rush, and i'm ahead of the curve anyway.

JJMediaReader

I got this ported over and playing video fairly easily, and then went through on a cleanup spree. I removed all the BufferedImage, multi-buffering, and scaling stuff and a few other experiments which never worked. Some api changes allowed me to consolidate more code into a base class, and some changes to AVStream necessitated a different approach to initialising the AVCodecContext (using AVCodecParameters). I made a few other little tweaks on the way.

The reason I removed the BufferedImage code is because I didn't want to pollute it with "platform specific" code. i.e. swing, javafx, etc. I've moved that functionality into a separate namespace (module?).

My first cut just took the BufferedImage code and put it into another class which provides the functionality by taking the current AVFrame from the JJMediaReader video stream. This'll probably do but when working on similar functionality for JavaFX I took a completely different approach - implementing a native PixelReader() so that the native code can decide the best way to write to the buffer. This is perhaps a little more work but is a lot cleaner to use.

swscale

jjmpeg1 lets you scale images 'directly' to/from primitive arrays or direct ByteBuffers in addition to AVFrame. Since they have no structure description (size, format), this either has to be passed in to the functions (messy) or stored in the object (also messy). jjmpeg1 used the latter option and for now I simply haven't implemented them.

The PixelReader mentioned above does implement it internally but for code re-use it might make sense to implement them with the structure information as explicit parameters, and use higher level objects such as PixelReader/Writer to track such information. On the other hand the native code has access to more information so it also makes sense to leave it there.

I went a bit further and created a re-usable super-class that does most of the work and toolkit specific routines only have to tweak the invocation. This approach hides libswscale behind another api. The slice conversions don't work properly but they're not necessary.

jni

So far I had public constructors and `finalisers' because otherwise the reflection code failed. That's a bit too ugly (and `dangerous') so I made them private. The reflection code just had to look up the methods and set them Accessible.

    Constructor cc = jtype.getDeclaredConstructor(Long.TYPE);

    cc.setAccessible(true);

    return cc.newInstance(p);

Whilst working on JJMediaReader I hit a snag with the issue of ownership. In most cases objects are either created anew and released (or gc'd) by the Java code, or are simply references to data managed elsewhere. I was addressing the latter problem by simply having an empty release() method for the instance, but that isn't flexible enough because some objects are created or referenced the the context determines which.

So I expanded the Java-side object tracking to include a `refer' method in addition to the 'resolve' method. `resolve' either creates a new instance or returns and existing one with a weak-reference object which will invoke the static release method when it gets finalised. `refer' on the other hand does the same thing but uses a different weak-reference object which does nothing.

I then noticed (the rather obvious) that if an object is created, it can't possibly 'go away' from the object tracking if it is still alive; therefore the `resolve' method was doing redundant work. So I created another `create' method which assumes the object is always a new one and simply adds it to the table. It can also do some checking but i'm pretty sure it can't fail ...

If on the other hand the underlying data was reference counted then the `resolve' method would be useful since it would be possible to lookup an existing object despite it being `released'. So i'll keep it in CObject.

As part of this change I also improved CObject in other ways.

I was storing the weak reference to the object itself inside the object so I could implement explicit release and to avoid copying the pointer. I removed that reference and only store the pointer now. The WeakReference it already tracked in a hash table so I just look it up if I need it. This lets me change the jni code to use a field lookup rather than a function call to retrieve it (I doubt it makes much perf difference but I will profile it at some point).

I also had some pretty messy "cross-layer" use of static variables and messy synchronisation code. I moved all map references to outside of the weak reference routine and use a synchronised map for the pointer to object table.

For explicit release I simply call .clear() and .enqueue() on the WeakReference - which seems to do the right thing, and simplifies the release code (at least conceptually) since it always runs on the same thread.

Tuesday, 1 December 2015

more termz

I tried a few more variants on the OpenCL rendering code but none are all that fast - the overheads kill it and whilst it does free the CPU up a little bit it isn't much. Probably not worth more time unless I look at OpenGL instead.

I added resizing. It meant I had to add some locking to the snapshot routine but it only needs to lock around the resize operation so it adds almost no overhead to normal operation (merely detecting a resize has occurred). I'm not yet sure what's supposed to happen with saved cursors and alternate screens when a resize occurs, probably just clip to size. Unfortunately there seems to be no way to set the WM_NORMAL_HINTS on the javafx stage, so there's no way to make it size to cells properly.

I did a bunch of benchmarking and profiling. One thing I tried was another test to compare to xterm - now at full-screen. Running "find . -name '*.c' | xargs cat" from the root of the linux 3.19.8 source tree. After a couple of runs this is about 25 seconds on termz, and 16 minutes in xterm. Well. Yeah it's a silly test but all those ls -l's during the day add up.

Looking at the memory profiler it doesn't really use too much heap during operation, just a few MB and most of that is the image and javfx. I mean nor should it, there isn't data structures to maintain. But having multiple compilers in ram (jvm, OpenCL), their generated output, and all the added overhead of the runtime support needed for those really adds up so it's very very fat in practice. I guess if multiple terms ran on the same jvm it would be ok.

enough yet?

So at this point i'm not really sure what i'll do with it. I'll probably poke at the edges when i'm bored and eventually when I get around to it I will dump what I have to my software site as the result of a weekend-and-a-bit-hack.

After that I'm not sure. It's actually quite functional and robust already (well, compared to the effort in) and wouldn't take much more work to turn it into a usable terminal for me - add some scrollback (pretty simple), mouse selection stuff (not that hard), and sort out some of the keyboard details (reading obtuse documents and testing). So maybe that will happen.

If I got that far adding the "10x20" typeface would probably be on the cards. Fixed-size outline fonts would be possible by just pre-rendering them but to me they just aren't terminal fonts.

Anything further such as a re-usable term component (which might actually be of use to the world) would require substantially more work on the i18n side of things and I don't feel like learning enough to do that properly.

Make

I did a bit poking at the java makefile stuff and it's to the point where i'm using it for out-of-ide builds of termz and zcl and will look into using it on other projects. That's the best way to find bugs/what works and what doesn't and previous attempts never got that far. For all it's gnumakefile obtuseness it's really rather compact at under 200 lines excluding comments and I didn't put any effort into making it particularly small. And that includes targets for javadocs, source jars, and binary builds.

Sunday, 29 November 2015

opencl termz

I was just going to "try something out" while I waited for the washing to finish ...

... so after a long and full day of hacking ...

The screenshot is from an OpenCL renderer. Each work item processes one output pixel and adds any attributes on the fly, somewhat similar in effect to how hardcoded hardware might have done it. I implemented a 'fancy' underline that leaves a space around descenders. The font is a 16x16 glyph texture of iso-8859-1 characters. I haven't implemented colour but there's room for 16.

On this kaveri machine with only one DIMM (== miserable memory bandwidth) the OpenCL routine renders this buffer in about 35-40uS. This doesn't sound too bad but it takes 3uS to "upload" the cell table input, and 60uS to "download" the raster output (and this is an indexed-mode 8-bit rather than RGBA which is ~2x slower again), but somehow by the time it's all gone through OpenCL that's grown to 300-500uS from first enqueue to final dequeue. Then add on writing to JavaFX (which converts it to BGRA) and it ends up ~1200uS.

I'm using some synchronous transfers and just using buffer read/write so there could be some improvements but the vast majority of the overheads are due to the toolkit.

So I guess that's "a bit crap" but it would still be "fast enough". For comparison a basic java renderer that only implements inverse is about 1.5x slower overall.

But for whatever reason the app still uses ~8% cpu even when not doing anything; and that definitely isn't ok at all. I couldn't identify the cause. Another toolkit looks like a necessity if it ever went beyond play-thing-toy.

I got bored doing the escape codes around "^[ [ ? Ps p" so it's broken aplenty beyond the bits I simply implemented incorrectly. But it's only a couple days' poking and just 1K3LOC. While there is ample documentation on the codes some of the important detail is lacking and since i'm not looking at any other implementation (not even zvt) i have to try/test/compare bits to xterm and/or remember the fiddly bits from 15 years ago (like the way the cursor wrapping is handled). I also have most of the slave process setup sorted beyond just the pty i/o - session leaders, controlling terminals, signal masks and signal actions, the environment. It might not be correct but I think all the scaffolding is now in place (albeit only for Linux).

FWIW a test i've been using is "time find ~/src" to measure elapsed time on my system - after a couple of runs to load everything into the buffer cache this is a consistent test with a lot of spew. If I run it in an xterm of the same size this takes ~25s to execute and grinds big parts of the desktop to a near halt while it's active. It really is abysmal behaviour given the modern hardware it's on (however "underpowered" it's supposed to be; and it's considerably worse on a much much faster machine). The same test in 'termz' takes about 4.5s and you'd barely know it was running. Adding a scrollback buffer would increase this (well probably, and not by much) however this goes through a fairly complete UTF-8 code-path otherwise.

The renderer has no effect on the runtime as it is polled on another thread (in this instance via the animation pulse on javafx). I don't use locks but rely on 'eventual consistency'. Some details must be taken atomically as part of the snapshot and these are handled appropriately.

Right now I feel like i've had my fill for now with this. I'm kinda interested, but i'm not sure if i'm interested enough to finish it sufficiently to use it - like pretty much all my hacking hacked up hacks. Time will be the teller.

Friday, 27 November 2015

termz

Every now and then I think about the sad state of affairs regarding terminal emulators for X11. It's been a bit of a thing for a while - it's how i ended up working at Ximian.

I stopped using gnome-terminal when i stopped working on it and went back to xterm. I never liked rxvt or their ilk and all of the 'desktop environment' terminal emulators are pretty naff for whatever reason.

xterm works and is reliable but with recent (being last 10 years) X Windows System servers the text rendering performance plummeted and even installing the only usable typefaces (misc-fixed 6x13, and 10x20, and sometimes xterm itself) became a manual job. Whilst performance isn't bad on this kaveri box I also use an uber-intel machine with a HD7970 where both emacs and xterm runs like an absolute pig whenever any GL applications are running, and it isn't even very fast otherwise (i'm talking whole desktop grinding to a halt as it redraws exposes at about 1 character column per SECOND). It's an "older" distribution so that may have something to do with it but there is no direct indication why it's so horrible (well apart from the AMD driver but i have no choice for that since it's used for OpenCL dev). I might upgrade it to slackware next year.

Ho hum.

Anyway I started poking last night at a basic xterm knockoff and got to the point of less sort of running inside it and now i'm thinking about ways I might be able to implement something a bit more complete. I'm working in Java and have a tiny bit of JNI to get the process going and handle some ioctl stuff (which seems somewhat easier now than it was in zvt, but portability is not on the agenda here).


TermZ? Glyphs are greymaps extracted directly from the PCF font.

zvt

When I wrote ZVT the primary goal was performance and to that end considerable effort was expended on making a terminal state machine which implemented zero-copy and zero-garbage algorithms. zero-copy is always a good thing but the zero-garbage was driven by the very slow malloc on Solaris at the time and my experience with Amiga memory management.

Another part of the puzzle was display and the main mechanism was inspired by some Amiga terminal emulators that used COPPER lists to re-render rows to the screen in arbitrary order without requiring them to be re-ordered in memory (memory bandwidth was a massive bottleneck when using pre 1985-spec hardware in 199x). I used a cyclic double-linked (exec) list of rows and to implement a scroll I just moved a row from the start to the end of the list which takes 8 pointer updates and a memset to clear it (and it also works for partial screen scrolls). By tracking the last row a given one was actually displayed at I could -at-any-point-later- attempt to create an optimal screen-update sequence including using blits for scrolling and minimising glyph redraws to only those that had changed. The algorithm for this was cheap and reliable if a little fiddly to get correct.

This last point is important as it allows the state machine to outpace the screen refresh rate which always becomes the largest bottleneck for terminal emulators in 'toolkit' environments. This is where it got all it's performance from.

new hardware, new approach

Thinking about the problem with current hardware my initial ideas are a little bit different.

I still quite like the linked list storage for the state machine and may go back to it but my current idea is instead to store a full cell-grid for the displayable area. I can still make full-screen scrolling just as cheap using a simple cyclic row trick (infact, even cheaper) but sub-region scrolling would require memory copies - but at the resolution of 4-bytes-per-glyph these are insanely cheap nowadays.

This is the most complex part of the emulator since it needs to implement all the control codes and whatnot - but for the most part thats just a mechanical process of implementing enough of them to have something functional.

I would also approach rendering from an entirely different angle. Rather than go smart i'm going wide and brute-forcing a simpler problem. At any given time - which can be throttled based on arbitrary metrics - I can take a snapshot of the current emulator screen and then asynchronously convert that to a screen display while the emulator continues to run on it's own thread.

For a basic CPU renderer it may still require some update optimisation but given it will just be trivial cell fonts to copy it probably wont be appreciably cheaper to scroll compared to just pasting new characters every time. And obviously this is utterly trivial code to implement.

The ultimate goal (and why the fixed-array grid backing is desirable) would be to use OpenCL or OpenGL (or more likely Vulkan if it ever gets here) to implement the rendering as a single pass operation which touches each output pixel only once. This would just take the raw cell-sized rectangle of the terminal state machine as it's only variable input and produce a fully rendered and styled framebuffer as the result. Basically just render the cells as a low-res nearest-neighbour texture lookup into a texture holding the glyphs. The former is a tiny tiny texture in GPU terms and rendering a single full-screen NN textured quad is absolutely nothing for any GPU. And compared to the gunk that is required to render a full-screen of arbitrary text through any gui toolkit ever it's many orders of magnitude less effort.

Ideally this would only ever exist at full-resolution in the on-screen framebuffer memory which would also make it extremely cheap memory wise.

But at least initially I would be going through JavaFX so it will instead have to have multiple copies and so on. The reason to use JavaFX is for all the auxiliary but absolutely necessary fluff like clipboard and dnd operations. I don't really like tabbed terminals (I mean I want to use windows as windows to multitask, not as a stack to task switch) but that is one way to ameliorate the memory use multiplication this would otherwise create.

So to begin with it would be extremely fat but that's just an implementation detail and not a limitation of the design.

worth bothering?

Still mulling that over. It's still a lot of work even if conceptually it's almost trivial.

Friday, 6 March 2015

Interactive synthesiser

Rather than 'play some more' i went head-first into writing a better display/model/control thing for the synthesiser stuff.

Doesn't look much different on the surface since the stylesheet is much the same but pretty much everything is backed by controls and skins and observable properties.

I have a 'Workbench' control which is the main controller and it handles the human wiring process and so on. I abstracted the connection points as 'Sockets' in a way which allows me to add other non-JSyn objects such as the dials which just feed out their value to some input port. Not shown but you can also reconfigure input ports to change their name and bounds so that they connect properly to dials.

I added the ability to unplug and move the ends of a given wire which works quite nicely. If you grab a wire near one end and 'pull' it far enough it detaches and becomes a free end, which can either be attached to some other compatible socket or letting go just deletes that wire.

I/O next I guess? Always the pain ...

FWIW The circuit above makes a pretty basic "idling chopper" "fop-fop" sound.

Thursday, 5 March 2015

Connecting the dots (with wires)

Yesterday I hacked up a "workbench" gui for JSyn. I just started experimenting with auto-generating the gui based on the UnitGenerator interfaces, it's designed with this in mind so it is fairly simple.

Blocks are added by clicking on the workspace, wires are connected by dragging a line between the discs, blocks can be arbitrarily dragged around, wires or blocks are deleted with delete or backspace keys; typical basic graphical user interface stuff.

One of the more difficult problems was how to wire up the ports ...

The difficulty arises because one uses container classes to form grouped gui components and do the layout, and then you want to be able to bind a linkage between an inner component of the group and components working in a different local coordinate system.

A diagram of the layout hierarchy as it currently exists helps to explain (this is just a prototype so the layout is a bit shit).

     Ellipse    Label
        +----+----+
            HBox
             +
          EndPoint (Pane)
       - ----+---- -
            VBox
       - ----+---- -
         Generator (BorderPane)    Wire (Line)
       - ----+-----------------------+
           Pane

So the Line representing the wire needs to connect to the Ellipse level, but the Line is in the coordinate space of the lower Pane and the Ellipse is in the coordinate space of the HBox which is in the coordinate space of the EndPoint, which is ...

So I created a new set of properties socketX, socketY, which reside on each EndPoint which maintain the location of the centre of the Ellipse relative to the lower Pane. The calculation is straightforward and based on transforming to and from scene-relative coordinates. It gets updated whenever the EndPoint is moved (relative to the Generator, i.e. after layout), or when the Generator is moved (i.e. relative to the Pane). The Wire can then just bind to these locations using javafx properties. I've got each generator maintaining the endpoint updates relative to it's parent but i'll probably have to come up with something better.

There's still a problem to solve though; the user interface allows you to plug a wire in to one socket and then drag it to another socket (i.e. click and drag). Unfortunately javafx currently has no way of picking a widget - i.e. looking it up by location or by the mechanism the event system uses. At first I tried using drag and drop mechanisms but it interfered with other gui operations and I couldn't find a way to show the wire following the mouse pointer.

So unfortunately I have to maintain a separate list of all the EndPoints in a model which I then scan for a match during the drag gesture. But given that this allows me to use layouts and stylesheets and so on, this is acceptable.

Duty Cycle

I created a new square wave oscillator type for JSyn as i was surprised the one it comes with doesn't have a duty cycle (pulse with) parameter. It was one of the more useful features of the square wave oscillator on the SID chip and features heavily in C=64 music. I think it could be created using a sawtooth generator and a gate but this is easier to use and was simple to make.

The circuit above generates a rather grating undulating / phasing sound effect like a 'robot thinking', or with a lower frequency a (metallic) misfiring engine.

I guess i'll add more of the unitgenerators from JSyn and do some experimentation with the code I have. If it's interesting enough i will probably dig deeper into making it a real application; it will need a better system model and probably a way to create a control panel separate from the inner workings of a circuit, as well as oscilloscope and spectrum analyser blocks (JSyn has most of this but it's all Swing).

Tuesday, 3 March 2015

bang!

Been getting pretty bored of being stuck in the house. Enough so that I coded up a basic space invaders game for something to do. At this point almost everything is there apart from the mother ship going past and some other game state things or animations. I've tried to keep the ship movement and wave structure correct (something clones usually try to 'improve') based on the C=64 version.

I'm using javafx for the graphics (i.e. most sprites are just a Rectangle - the actual shape isn't terribly important for the mechanics, and saves copyright issues) but the barriers are WritableImage's and i do the hit detection and bomb erosion on separate image arrays that back them. Because of the way the hit detection works it would probably be easier just to do everything on a bitmap manually but I didn't feel like starting from scratch after starting with a scenegraph version.

Yesterday I added some sound effects. The invader explosion sound is a flat beep but the rest are more or less correct including the 4-note 'tune' which speeds up as the invader movement does. It doesn't sound right when there's only one left but otherwise it's close.

This lead me to play a bit with the java sound api ... which is somewhat better than I thought it was; e.g. it provides automatic mixing and so on. It also meant I had to do some sound synthesis for the tune and effects. So far i'm generating sample Clip objects from some synthesis code I wrote myself but today I looked into it deeper and found some existing synthesiser libraries that should let me generate some better sounds. But i'll need to play with them a fair bit before getting anywhere. Actually unless I find something i'll probably have to write some tools for it anyway which starts to make it a fairly significant effort.

Last time i played with synthesisers was with the SID around 1990 and I never got very far with that, so i'm starting from a point of somewhat ignorance here.

Friday, 8 August 2014

Starting JavaFX from random Java code

I write a lot of prototype routines - too many to keep track of in separate projects so I end up with a ton of mains(). Best practice? Who gives a shit: its a prototype, played with for a day or a week and then forgotten.

So far for graphical output i've just been using Swing: actually there's probably not much reason not to use it for that because it does the job but once you need to add some interactivity it becomes a bit of a pain if you've been playing with JavaFX. I might add a 'display intermediate image' anywhere in the code and up it comes.

But JavaFX doesn't let you just call Platform.runLater() or new Stage() from anywhere as with Swing: the system needs initialising within an Application context.

Here's a solution. I have no claims it's a good one but it works for me so far.

// This code is placed in the public domain
public class FXUtils {

    static FXApplication app;
    static Semaphore sem = new Semaphore(0);

    public static void startFX(Runnable r) {
        if (app == null) {
            try {
                Thread t = new Thread(() -> {
                    FXApplication.start(r);
                });
                t.start();

                sem.acquire();
            } catch (InterruptedException ex) {
            }
        } else {
            Platform.runLater(r);
        }
    }

    public static class FXApplication extends Application {

        WritableImage image;
        static Runnable run;

        public FXApplication() {
        }

        @Override
        public void start(Stage stage) throws Exception {
            app = this;
            run.run();
            sem.release();
        }

        public static void start(Runnable r) {
            run = r;
            // Application.launch() can only be called from a static
            // method from a class that extends Application
            Application.launch();
            // no windows - no app!
            System.exit(0);
        }
    }
}

Whether start() calls System.exit() or not is up to you - personally when I close a window i'm prototyping stuff on I want everything else to fuck off for good.

And this is how to use it:

    public static void main(String[] args) {
        FXApplication.start(() -> {
            // Now on javafx thread
            Stage s = new Stage();

            s.setScene(new Scene(new VBox(new Label("foobar!"))));
            
            s.show();
        });

        // Will wait for javafx to start, but then continue here
        // exiting will leave the windows open, till they're closed
    }

This uses a thread to launch javafx so that the original main thread can continue; Application.launch() doesn't return until the last window is closed so would otherwise block. The thread could be made a daemon too for some different behaviours.

If you just want to launch a full JavaFX application from multiple mains then none of this is required, just create a static start() method which calls Application.launch().

Tuesday, 22 July 2014

JavaFX Task interface

I've been doing a bit of work on a JavaFX application turning it from a very rough prototype to a very rough product (i mean, what can one really accomplish in two weeks?). I already had a bunch of background tasks running using threads but because the original was thrown together in a rush for a small side-project I just hand-rolled everything using familiar techniques (combination of threads and ExecutorService).

I'd seen JavaFX's Task and wasn't really sure what the point was - sure it simplified a couple of things but Platform.runLater() is easy enough to use and so on.

But I found things got messy pretty fast and behaviour started leaking between abstraction layers.

So as part of this re-work I decided to "use it in anger" and see how it turned out. Quite well, if you're prepared to let JavaFX control the middle-tier of the application by using Task everywhere (and for a JavaFX application, there's no reason not to). Encapsulating the work in a Task object allows the decisions about what to do with the user interface to be decided wherever it is used; e.g. does it bother to start a spinny thing or just run silently and so on. And it handles some of the fiddly stuff so that you don't end up with a busy spinner that never runs out.

Having tasks as immutable single-use objects is how I usually write multi-thread code anyway so it wasn't much of a change (IMHO it's the only way which works). Basically all transient state needs to be captured in the job object so it can be worked on independently of the rest of the application, and all outputs are collected in a result object (memory permitting, and the size of modern memory systems makes them very permissive). If incremental updates are desirable then they can be communicated via some other mechanism although it is perhaps surprising how often incremental update just doesn't work very well for a user.

There are still some small gotchas. Say for example that you're firing off a calculation based on interaction with a slider. Ideally you want the result to update as fast as the slider does but this is often not possible. You can't just let every job run to completion because otherwise it will quickly start to lag and just feel wrong. You can't cancel every job if a new one arrives because you may never have one complete leaving the user staring at stale results. One hack is to just update the result when the user releases the slider knob but that removes most of the interactivity from the GUI and defeats the purpose.

Previously i've solved it by implementing a greedy consumer. Jobs are indivisible units which always run to completion (and to the user interface) but whenever the worker thread polls for incoming jobs it throws away all but the last one if more are queued. ExecutorService doesn't directly allow this granularity of job control but it can be emulated easily enough by something like the following.

ExecutorService queue;
Task task;

void dowork() {
   if (task != null && !task.isDone() && !task.isRunning()) {
       task.cancel();
   }

   task = new WorkTask( ... );

   task.setOnSucceeded( ... );

   queue.submit(task);
}
(is there another way? I don't know, this is what I found ...).

This isn't used for tasks which might take a very long time to complete but for ones which are already interactive speed or close to it (roughly, under 0.5s). It lets any already running jobs finish but cancels any waiting in the queue.

This makes the application "feel" much lighter and more responsive even if it does slightly more calculation than necessary. Unless the work is very trivial almost all such work needs to be thrown into a thread otherwise sliders start to feel unresponsive. This is pretty much the same for any toolkit (or os).

Saturday, 31 May 2014

that 'graphical' demo

Ended up coding that 'graphical' demo. Just another mandelbrot thingo ... not big on the imagination right now and I suppose it demonstrates flops performance.

This is using JavaFX as the frontend - using the monocle driver as mentioned on a previous post. I'm still running it via remote X11 over ssh.

I have each EPU core calculating interleaved lines which works quite well at balancing the scheduling - at first i tried breaking the output into bands but that worked very poorly. The start position (not shown, but is (-1.5,-1.0) to (0.5,+1.0) and 256 maximum iterations) with 16 cores takes 0.100 seconds. A single-threaded implementation in Java using Oracle JDK 1.8 on the ARM takes 1.500 seconds, i'm using the performance mode. A single EPU core takes a little longer at 1.589s - obviously showing near-perfect scaling of the trivially paralellisable problem here even with the simple static scheduling i'm using.

For comparison my kaveri workstation using the single-core Java takes 0.120 seconds. Using Java8 parallel foreach takes that down to 0.036 seconds (didn't have this available when I timed the ARM version).

Details

The IPC mechanism i'm using is an 'ez_port' with a on-core queue. The host uses the port to calculate an index into the queue and writes to it's reserved slot directly, and so then the on-core code can just use it when the job is posted to the port.

The main loop on the core-code is about as simple as one can expect considering the runtime isn't doing anything here.

struct job {
        float sx, sy, dx, dy;
        int *dst;
        int dstride, w, h;
};

ez_port_t local;
struct job queue[QSIZE];

int main(void) {
        while (1) {
                unsigned int wi = ez_port_await(&local, 1);

                if (!queue[wi].dst) {
                        ez_port_complete(&local, 1);
                        break;
                }

                calculate(&queue[wi]);

                ez_port_complete(&local, 1);
        }

        return 0;
}

This is the totality of code which communicates with the host. calculate() does the work according to the received job details. By placing the port_complete after the work is done rather than after the work has been copied locally allows it to be used as an implicit completion flag as well.

The Java side is a bit more involved but that's just because the host code has to be. After the cores are loaded but before they are started the communication values need to be resolved in the host code. This is done symbolically:

        for (int r = 0; r < rows; r++) {
                for (int c = 0; c < cols; c++) {
                        int i = r * cols + c;

                        cores[i] = wg.createPort(r, c, 2, "_local");
                        queues[i] = wg.mapSymbol(r, c, "_queue");
                }
        }

Then once the cores are started the calculation code just has to poke the result into the processing queue on each core. It has to duplicate the struct layout using a ByteBuffer - it's a bit clumsy but it's just what you do on Java (well, unless you do some much more complicated things).

        int N = rows * cols;

        // Send job to queue on each core directly
        for (int i = 0; i < N; i++) {
                int qi = cores[i].reserve(1);

                // struct job {
                //      float sx, sy, dx, dy;
                //      int *dst;
                //      int dstride, w, h;
                //};
                ByteBuffer bb = queues[i];

                bb.position(qi * 32);

                // Each core calculates interleaved rows
                bb.putFloat(sx);
                bb.putFloat(sy + dy * i);
                bb.putFloat(dx);
                bb.putFloat(dy * N);

                // dst (in bytes), dstride (in ints)
                bb.putInt(dst.getEPUAddress() + i * w * 4);
                bb.putInt(w * N);

                // w,h
                bb.putInt(w);
                bb.putInt(h - i);
                bb.rewind();

                cores[i].post(1);
        }
The post() call will trigger the calculation in the target core from the loop above.

Then it can just wait for it to finish by checking when the work queue is empty. A current hardware limitation requires busy wait loops.

        // Wait for them all to finish
        for (int i = 0; i < N; i++) {
                while (cores[i].depth() != 0) {
                        try {
                                Thread.sleep(1);
                        } catch (InterruptedException ex) {
                        }
                }
        }

These two loops can then be called repeatedly to calculate new locations.

The pixels as RGBA are then copied to the WritableImage and JavaFX displays that at some point. It's a little slow via remote X but it works and is just a bit better than writing to a pnm file from C ;-)

I've exhausted my current ideas for the moment so I might drop out another release. At some point. There are still quite a lot of issues to resolve in the library but it's more than enough for experimentation although i'm not sure if anyone but me seems remotely interested in that.

Friday, 4 April 2014

Quick swing by JavaFX

Had a chance to poke around a small JavaFX application for the customer for a couple of days. Unfortunately i've been 'booked' for other work for the next few months so I'm still not getting as much of a chance to play with JavaFX as i'd hoped. Might be the last too (on that s/w) as this new work thrust on me is basically an unrelated graduate-level task in a graduate-level work environment, and that's the least of the issues with it (not too happy right now but i'll have to see how it transpires).

Anyway ... I'm still having issues with layouts although in my particular problem I think it came down to not realising that the scale pivot point is the centre of objects. I had inconsistent/jumping ui's as things changed so it just looked like a layout bug.

I had a few hours left after adding the required functionality so I thought i'd tart it up a bit with clipboard and then drag and drop support. Nice ... it's nice. Just simple and hides all the data-type negotiation and whatnot; something that made sense in 90s era computers without the memory (and also high hopes of extensive functionality) but now there's no real need for it (and dnd is mostly used for stupid things like editing text where it doesn't make sense because of it's clumsiness, and not for file opening where it does). One of those things were a really good style guide might have helped rather than a free-for-all.

As an example this function pointer (or method handle, or whatever it is) can just be added to any ImageView to make it draggable as a picture - e.g. to drop into a picture editor.

    static EventHandler<MouseEvent> dragImageView = (MouseEvent event) -> {
        ImageView iv = (ImageView) event.getSource();
        Image im = iv.getImage();
                
        if (im != null && im.getProgress() == 1) {
            Dragboard db = iv.startDragAndDrop(TransferMode.COPY);
            ClipboardContent cc = new ClipboardContent();

            cc.putImage(im);
            db.setContent(cc);
            event.consume();
        }
    };

    // any image view not in a list:
    iv.setOnDragDetected(dragImageView);

Dragging from lists has to go on the list not the imageview, though isn't much more work.

The clipboard is even a bit easier although I did some strange behaviour with it losing track of the content of the clipboard from another application if it the copy was done when the JavaFX application wasn't already running.

It doesn't seem to support the primary selection though which is a bit of a bummer. Not that most applications that use it do it properly any more :( You do have to stop highlighting the selection when you lose it!

I realised the last time I properly looked at cut and paste was about 15 years ago with gnome-terminal ... hmm.

Compositing

I'm still needing to use BufferedImage for I/O but one of the things I was worried about was whether I would still need to use it for composition. Looks like I don't and depending on how one feels about the javafx layout and blending stuff it offers "all the power" of that - as well as CSS. You just set up an off-screen scene and either snapshot that or one of it's components.

    Scene s = new Scene(root);
    WritableImage wi = s.snapshot(null);

If you want alpha to make it through to the output:

    s.setFill(Color.TRANSPARENT);
    root.setBackground(Background.EMPTY);

(actually that is pretty nice, and about time you're able to unify off-screen and on-screen layout and composition. And the api doesn't prevent the implementation using hardware to speed it up either).

One thing I found a little frustrating is the fact that none of the layout objects clip their content. This makes sense but it ended up not quite working properly when I added it to what I thought was the right place - suddenly all my alpha compositing simply stopped working. I had to wrap the container inside another one and just set the clip on the outer container that then when into a BorderPane or whatever it was. Around this time was when I was also having the strange jumping layout issues so that artificially inflated the frustration level.

So just as i'm starting to get the feel of it after a few short hours ... i'm pulled away again.

(Not that I can't work on something at home ... which i probably will once this parallella has run it's course).

Update: So the "real" customer had a look-see this week and apparently were pretty impressed. Not that the JavaFX had much to do with it but it didn't hurt i'm sure. As I said to the PM afterwards and I quote "they're probably used to seeing some matlab piece of shit that takes days to run" ... anyway I guess we'll see if any more money comes along. If so it could be quite interesting indeed - although again, not particularly for JavaFX related reasons.

Wednesday, 12 March 2014

javafx on parallella via remote X, with added opencl

After the signoff on the last post I thought maybe I had spoken too soon about being able to write front-end code for the parallella in Java. I couldn't get JavaFX doesn't to work via remote X on ARM but writes directly to the framebuffer. While that's a nice think to have it doesn't help me. Always one step forward two steps back eh (I mean I could always just use swing but where's the fun in that).

The gl screensavers and other X11 stuff worked ok. I couldn't find any useful mention of it on the internets until I had a look in jira (openjdk bug system). Came across Monocle which I thought was worth a look. It didn't look all that promising until I saw it was already built-in to the ARM builds.

And ... it worked. Well I guess that's something. I had to add the following to the command line to get javafx working over remote X from an arm box:

  -Djavafx.platform=monocle -Djavafx.order=sw

I 'fixed' some coprthr peculiarities in the opencl code and got it running (but only on the arm cpu so far):

(Not sure what blogger is doing, it doesn't look that bad even with my shitty palette).

At first the UI was very unresponsive then I discovered that clEnqueueNDRangeKernel or clEnqueueReadBuffer runs synchronously - which is obviously not something to be doing from an animation handler. I chucked that through an Executor and whilst it wont win any land-speed records it is now basically usable.

Sunday, 9 March 2014

Another go at a smoothly loading list of icons

Due to the lack of streaming support in MediaPlayer I've given up on the idea of a javafx internet radio player for the moment but I thought perhaps I could make a remote interface for the android one I have. This is something I could actually use since I don't have my speakers plugged into my workstation.

First thing as ever is that scrolly list of stations with pictures. I think I finally have a tidy solution using JavaFX implemented using basic Java classes. It only requires a little bit more code than the custom ListCell required anyway.

First, the data item. I load this using an executor asynchronously.

  class Station {
    String title;
    String thumb;
  }
Then a cache based on a LinkedHashMap - which simply requires implementing removeEldestEntry. I think an important detail I missed last time I tried this was cancelling any still-loading image here directly. Without that it can end up with a queue of images to load that will never be seen and this adds an unnecessary delay in loading those that are currently being shown.
  class ImageCache extends LinkedHashMap<String, Image> {
    final int limit;

    ImageCache(int limit) {
      this.limit = limit;
    }

    protected boolean removeEldestEntry(Map.Entry<String, Image> eldest) {
      if (size() > limit) {
        eldest.getValue().cancel();
        return true;
      }
      return false;
    }
  }
And finally the custom cell itself. It fades the image in once it's loaded although to be honest i'm not sure if that feels right on a desktop machine. After playing with it a bit it feels like it could cause eye fatigue by drawing the eye to multiple parts of the screen for much longer than necessary. But it does appear 'smoother' this way.
 // Copyright 2014 Michael Zucchi
 // This code is covered by the GNU General Public License
 // version 3, or later.
 class StationListCell extends ListCell<Station> {
    ImageCache cache = new ImageCache(32);
    ImageView iv;
    FadeTransition fadein;

    StationListCell() {
      iv = new ImageView();
      iv.setFitWidth(128);
      iv.setFitHeight(64);
      iv.setPreserveRatio(true);

      setGraphic(iv);
    }

    protected void updateItem(Station t, boolean empty) {
      super.updateItem(t, empty);

      if (t != null) {
        setText(t.title);

        if (t.thumb != null) {
            Image icon = cache.get(t.thumb);

            if (icon == null) {
              if (fadein != null) {
                fadein.stop();
                fadein = null;
              }
              icon = new Image(t.thumb, 128, 64, true, true, true);
              icon.progressProperty().addListener((ObservableValue<? extends Number> ov,
                                                  Number t1, Number t2) -> {
                if (t2.doubleValue() == 1.0) {
                  fadein = new FadeTransition(Duration.millis(250), iv);
                  fadein.setFromValue(0);
                  fadein.setToValue(1);
                  fadein.play();
                }
              });
            }
            cache.put(t.thumb, icon); // update lru
            iv.setImage(icon);
          }
        } else {
          iv.setImage(null);
        }
      }
    }
  }

I think last time I tried it I forgot to write to the cache every time an entry is accessed - i.e. to update the LRU order. It's still a bit more code than i'd really like but given that it's in one language in one place it's probably about as concise as can be expected.

Actually there is still some weird JavaFX bug in that the label text jumps to the left once the image is loaded - which makes no sense given the properties on the ImageView and the constructor arguments to the background loaded Image. But this can be fixed by placing the ImageView inside an appropriately configured Region like an AnchorView.

I also played with a busy animation while it was loading but that just looked naff.

This appears very nice and smooth as you scroll through the list. The only obvious time it drops some frames is when the list is initially populated with setItems(ObservableList) (which is still a bit unfortunate).

The Java Heap vs native heap

I was curious about whether the size-limited cache was worth putting in at all rather than simply using the mechanism to lazily load every image (or ... just use the Image background loading feature directly). So I tried some profiling The images are fixed at 128x64 pixels so they're not particularly big, and I dunno there's a few dozen stations.

Using lazy loading the JVM maxes out at 10MB of active heap. A 32-element cache required about 7MB. So that seems a sizable benefit.

However ...

The process itself requires about 150MB total (top - RES) so it's pretty insignificant in the grand scheme of things. Using just the interpreter drops this down to 100MB but that's not much use. Classes, compilers, compiled code, X, GL and other native resources really chew it up.

A typical C++ application probably needs comparable total memory to exist, sans the compiler, but a lot of that is just in shared libraries so it can ameliorated by sharing across applications. Although in reality with so many libraries needed to do anything in C or C++ and such an ill-defined "platform" as GNU/Linux there is much much less sharing going on than there could be (it's certainly no AmigaOS). One of the trade-offs of using a jit compiler and dynamic runtime is that compiled code can't really be shared unless multiple applications run in the same jvm (i've seen mention of such a feature but it isn't here yet - it's certainly technologically possible).

But yeah, memory is cheap and the main memory factor in most applications is the data itself which is much the same regardless of language (unless it doesn't support primitive-type arrays).

Wednesday, 5 March 2014

opencl javafx mandelbrot thingy

I didn't want to think too much coming up with something to test my opencl binding so I took the mandelbrot demo code from the parallella opencl forum and ported it to JavaFX and zcl. Aim is to try it on the parallella but i'm having troubles with the opencl environment so I just did it on my new workstation.

Because I was too lazy to do a full 'explorer' I just converted it to a julia-set generator and use the mouse location to set the seed point.

Using the gpu it easily keeps up with the screen refresh even at 4x this resolution (1024x1024). The julia set escapes much faster than the mandelbrot set so even the cpu driver can keep up quite well actually until you hit the blobby empty areas. I'm using a kaveri 7850 APU and the above image is about 100-200uS on the gpu and about 3mS on the cpu driver according to the profiling timestamps.

At first I was a little stumped as to how to hook the rendering into the JavaFX refresh. But I came up with a couple of approaches:

  1. Use a never-ending Transition.

    Each time the interpolate method fires it checks to see if the last rendering has finished and if it has it fires off another rendering (and event) and copies the pixels to the WritableImage.

  2. Use an event callback.

    When the job is queued, add an event callback for when the output event reaches the CL_COMPLETE state. When it fires queue a copy to the WritableImage using Platform.runLater() and at the same time enqueue a new render.

The former hits the sort of rendering issues you get from double-buffering (if it's not fast enough it jumps to half speed) although it loads the system quite lightly and does a lot less mucking about with cross-thread invocation.

I wonder if you can efficiently triple-buffer with JavaFX? I guess render to a non-attached WritableImage from another thread and dump it into the ImageView at the next pulse? Maybe sort of.

Of course ... it would be better if the OpenCL just wrote directly to the GL texture, ... but I guess we can't have everything we want right away.

The code is too ugly to publish and it's not like the world needs another one of these demos but if i ever get opencl working on the parallella i'll drop it somewhere.

Software "upgrades"

Yes, scary quotes.

On to a short rant. As part of this post I needed to get a screenshot. No worries I says, fire up the gimp as usual, grab a screenshot, save it for blogger as png. Oh, it wont let me. What the hell? Why would I want to save in xcf unless I wanted to save in xcf? Bizarre.

Seems there's a whole ocean of complaints about this one I've managed to avoid until now because I so rarely re-install my operating system. The whole thing about not wanting "normal" users is pretty fucked up though. Who the hell do they think is going to use it then, Hollywood? And if so - why the fuck are they pandering to those DRM-eye-pee-bullshit bastards in the first place? Free software gone mad. Effectively forked from it's mission by it's own bully developers and yes-men cronies. Krita looks a bit too hip for my tastes but I suppose it's worth a look (yeah, i'm probably not going to poke at ImageZ again, although, you know, opencl + javafx could be a 'thing' there).

I'm sure i've mentioned this many times but in part i think it's just that nobody wants to 'just maintain' fully mature software and they have to keep poking at it just for the sake of it. And new blood always wants to make it's mark - and there's no wiser hands left to stop them. And no doubt they've caught a bit of the software-treadmill disease from M$ or apple since that's what they were brought up with. Not to mention this whole rolling-upgrade-never-ending-changes bullshit that mozilla and google are so fond of. I had reason to go to the australian acma website yesterday (robot caller kept calling back every half hour - which is apparently completely legal ... sigh ... and given it was polling political data for the upcoming state election we have no hope of the pollies doing anything about it) and I was absolutely astounded at how shitty and difficult to use it has become. Obviously a M$ weenie is in the design driver's seat because the whole front page is a huge mess of metro-inspired animating vomit.

It's no wonder i'm so averse to "upgrading" my gnu/linux install. Every time there's some piece or even whole suite of software which is just that little bit more fucked up and harder to use than the previous version. I gotta spend half a day just getting the defaults usable again and it's weeks before everything is sorted (e.g. like this gimp surprise). It even keeps happening to emacs of all things (visual line mode - i mean really?) and gcc (well the C standards) can't seem to agree on what is worth a warning from version to version.

Friday, 28 February 2014

javafx + internet radio = partial success?

After a long and pointless goose-chase with different versions of ffmpeg and libav ... I got my internet radio thing to work from JavaFX.

It turned out to be at least partly a problem with my proxy code. The ice-cast stream doesn't include a Content-Length header (because you know, it's a stream), so this was causing libfxplugins to crash as in my previous post on the subject. Shouldn't really cause a crash - at most it should just throw a protocol error exception? Not sure if it has javafx security implications (e.g. if media on a web page through the web component goes through the same mechanism it certainly does - Update: I filed a bug in jira, and it seems to have been escalated - even at this late stage of java 8).

If I add a made-up content-length value at least I get the music playing, .. but the 'user experience' isn't very good because it seems to change how much it pre-buffers depending on the reported length (rather strange i think). So if i report 1-10M it starts after a few seconds but if i report some gigantic number it buffers for minutes (or maybe it never starts, i lost patience). The problem is that as the data length is hounoured (as it should be) which means that too small a number causes the stream to finish quickly. And it seems to read the same stream twice at the same time which is also odd.

To be blunt I find it pretty perplexing 'in this day and age' that javafx doesn't support streaming media to start with. Or that g-"so-called-streamer" seems to be the reason for this. If I could work out how to compile libfxplugins.so from the openjfx dist I would have a poke, but alas ...

I was going to go ahead with the application anyway but I think because of this streaming issue I wont - or if I do I wont be using javafx to do the decoding which is a bit of a pain.

Update 2: The bug has just been patched. 4 working days from reporting and if the openjdk schedule is still correct, just 2 weeks from release. So yeah I guess it was reasonably important and even just mucking about has value.

Wednesday, 12 February 2014

javafx + internet radio = sigh

I thought i'd look at porting the android internet radio player I have over to JavaFX; although jjmpeg is an option I thought i would first try with the JavaFX MediaPlayer. Thought it might be a simple distraction on a hot day.

Unfortunately it's a no go so far.

Firstly it just doesn't accept the protocol from the shoutcast server that i'm using: it sends a response with ICY 200 OK rather than HTTP/1.1 200 OK. Because mpeg is a streaming protocol normally players just ignore that and keep going even if they aren't aware of the streaming protocol (which they normally are).

Then I realised it requires ffmpeg 0.10 libraries to function (the same version jjmpeg/head uses, oddly enough - which seems pretty odd for such a new product) - so I pointed to my local build of those and at least got it playing local mp3 files ...

So since I had that going I hacked up a quick proxy server (it's something i wanted to look at anyway wrt android; so the player can extract the current song info from the stream) and after mucking about with some silly bugs I managed to get it to the point of segfaulting. If I save the content of the stream it will play that ok it just seems to have trouble with loading from a network. The proxy server just rewrites the ICY header response to say HTTP/1.1 instead.

Steaming Poo.

I'm using the latest jdk 1.8.0 release candidate as of 12/2/14. I suspect it's a version compatability issue with my ffmpeg build or it could just be a bug in the media code - given it works with local files and particularly since it's using gstreamer: the second would be no surprise to me at all because gstreamer is a pile of shit.

   Stack: [0x84dad000,0x855ae000],  sp=0x855ad1e4,  free space=8192k
   Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
   C  [libfxplugins.so+0x8d28]  cache_has_enough_data+0xc
   C  [libfxplugins.so+0x74b8]  progress_buffer_loop+0xbd
   C  [libgstreamer-lite.so+0x6bdd5]  gst_task_func+0x203
   C  [libgstreamer-lite.so+0x6cebd]  default_func+0x29
   C  [libglib-2.0.so.0+0x6c3a1]  fileno+0x6c3a1
   C  [libglib-2.0.so.0+0x69bd0]  fileno+0x69bd0
   C  [libpthread.so.0+0x5e99]  abort@@GLIBC_2.0+0x5e99

My proxy code is also totally shit so that's always a possible cause but it shouldn't cause a crash regardless.

Update: The above was on an x86 machine, also tried on an amd64 isa and it did the same. So probably version incompatabilities. Unfortunately those versions (at least) of ffmpeg can be compiled in binary incompatible ways even if the library is the same revision, and if it's been built against ubuntu or debian, well they like to mess around with their packages.

Update 28/2/14: So I thought perhaps it was something to do with the debian mess of using libav instead of ffmpeg. But trying that results in the same crash. I also tried the libavcodec.so.53 that comes with the gst-ffmpeg-0.10.13 package ... but that doesn't include avcodec_open2(). Hmm, so much for version numbers eh.

Also tried ffmpeg 0.8.x and 0.9.x. But they all just crash in the same place.

On my new pc I also tried using the version of 'libavcodec.so.53' that comes with gst-ffmpeg-0.10.13 ... but that 'version 53' of ffmpeg doesn't include libavcodec_open2(). Actually it looks like that is also using libav for fucks sake. Oh, so it seems that it's actually using ffmpeg 0.7.2 instead. How odd.

What were oracle thinking if it is built against libav - a buggy and insecure fork of another project and a version that is well beyond maintenance at that.

I guess I will keep trying different versions and see if one sticks. Pretty fucked up though - libraries have a version for a reason and so what's the point if they don't actually mean anything. Possibly the situation was compounded by the whole libav fork. Or it might just be a bug with gstreamer-lite.

Time passes ...

Ok, so 0.8.x and 0.9.x also provide 'libavcodec.so.53' ... and they all crash in the same place, so quite probably it's just the code in libfxplugins.

Shit, I even tried building openjfx ... but even though it has the source-code for libfxplugins.so ... it doesn't seem to build it and just copies it from the installed jre. It doesn't help that it uses gradle which is both slow and opaque.

See follow-up post.

Saturday, 23 November 2013

A bit of S-FX fun

Last couple of days i've been poking around a bit with audio - trying to learn a bit more about how to process it digitally.

To start with I just wanted to get some visualisation up to see what sort of stuff you get out of a fourier transform.

I started in Swing but then re-started in JavaFX and came up with this little tool. A signal plot on the left and a scrolling spectrogram on the right.

I use an old trick from Amiga days to simplify the spectrogram display updates. I create a WritableImage which is twice the visibile size. When a new row of spectrogram data arrives I write it twice, at the current output row and at the current output row + visible size. This just keeps repeating forever, rolling back to the start when it overflows. Then I adjust the viewport on the ImageView to show the correct section - which is just the total output count modulo the visible row count. This creates a smooth scroll without having to write the whole display every time (let the GPU do that since it will anyway) or the need for an extra block of processing once every n frames.

So e.g. for a 256-wide spectrogram on a 600-high display:

        WritableImage spectrogram = new WritableImage(256, 1200);
        ImageView spec = new ImageView(spectrogram);
        int spectrogramRow = 0;

        void addRows(int[] srow, int rows) {
                PixelFormat fmt = PixelFormat.getIntArgbPreInstance();

                spectrogram.getPixelWriter().setPixels(0, spectrogramRow, 256, rows, fmt, srow, 0, 256);
                spectrogram.getPixelWriter().setPixels(0, spectrogramRow + 600, 256, rows, fmt, srow, 0, 256);
                spectrogramRow = (spectrogramRow + rows) % 600;
                spec.setViewport(new Rectangle2D(0, spectrogramRow, 256, 600));
        }

Unfortunately it's just running on the CPU (some ancient piece of shit intel graphics on this laptop) so the output isn't really very smooth at all, nor can up the spectrogram rate too high. Not that it's fast enough anyway but I don't think it helps that my laptop outputs 50Hz to it's screen and the external second screen is 60Hz, I think JavaFX uses 60Hz NTSC timing too, bletch.

Actually I dunno, it's only using 30% cpu. Must try it on my workstation.

Anyway, nothing special but it's still hypnotic enough I forgot why I started writing it.

Tuesday, 12 November 2013

How on earth did ant become the build tool for java?

I got pretty sick of netbeans taking forever to build a very simple JavaFX app on my apparently now-too-slow (too-little-memoried) dual-core laptop, and so looked into why it was taking so long by creating a Makefile.

I wasn't expecting this ...

[notzed@unknown001fe11d1e42 MapViewer]$ time ant clean jar

... many pages of completely illegible and altogether
    meaningless-to-human-or-computer output ...

BUILD SUCCESSFUL
Total time: 22 seconds

real    0m22.527s
user    0m32.211s
sys     0m1.919s
[notzed@unknown001fe11d1e42 MapViewer]$ make clean all

... a succinct if not particularly human-friendly list
    of the specific commands executed ...

real    0m1.563s
user    0m1.678s
sys     0m0.349s
[notzed@unknown001fe11d1e42 MapViewer]$ 

What? What? Huh?

Oh, so it seems 'ant clean' cleans all related projects as well so it's rebuilding many more files needlessly. I thought one of the main points of having multiple sub-projects is to avoid this kind of thing ... but yeah, "whatever", ... in the parlance of our time.

So what about just changing one file ...

[notzed@unknown001fe11d1e42 MapViewer]$ touch src/mapviewer/MapViewer.java 
[notzed@unknown001fe11d1e42 MapViewer]$ time ant jar

.. pages of crap again ...

BUILD SUCCESSFUL
Total time: 7 seconds

real    0m8.344s
user    0m9.161s
sys     0m1.038s
[notzed@unknown001fe11d1e42 MapViewer]$

Even what amounts to a simple batch script which just does everything from scratch is an order of magnitude faster than using ant - which only compiled one file. With JavaFX (as well as android), netbeans just keeps forgeting to pick up changes so I almost always have to use shift-f11 (complete clean and rebuild) every time I run whatever i'm working on otherwise I get either the old code or runtime failure.

I'm using javafxpackager to create the final jar, and the makefile is only 30 lines long, and you know, at least a bit readable.

I hate to think of the days I alone waste every year because of this completely incompetent and utterly shit tool.

Oh my god, it's full of boggles.

Friday, 24 May 2013

on google

So google have decided to disable downloads on google code.

So I have decided to stop using it.

... although as yet I have no concrete plans or timeline for when this decision will take effect.

Whilst they claim it's about abuse, one can only assume that is just a "likely-sounding excuse" for what in reality is just another straight-up lie from the PR department of a supra-national conglomerate, and it's really just a way to cut costs and promote their 'drive' service (a useless microsoft/apple only service as far as i'm concerned).

Nobody seems to have reported that they have also gimped their POP interface to gmail a couple of days ago. No more UID support. This makes POP a lot less reliable/useful as a mail store (although in honesty it was never designed for that purpose). I proceeded to delete all the mail in gmail to help them free up some disk space.

I guess over-all the writing is on the wall. We all know that at some point 'google account' will mean 'google+', and blogger may be retired at any time.

So it seems my on-going-but-totally-lax search for alternatives to 'everything google for convenience' just got another big kick up the rump-side.

As my projects are all pretty small and low-volume I might look at a local solution because every network based solution faces the same problem. I have a couple of beagleboards doing nothing although getting a running and secure-enough system might be more pain than it's worth.

It's a bit of a pain to have to deal with.

Sunday, 14 April 2013

Map Viewing Tool

I had a couple of hours after waking up too early so I hacked a couple more things into the prototype map viewer - almost making it a useful-if-a-bit-crude tool.

First it displays any 'interesting' tiles - ones with any associated game behaviour - using red squares. Then as it was so simple even though it isn't terribly useful more than once, it does the same for the original dusk game - using blue squares. Then down the left-hand side it shows all the details of the scripts.

For starters it shows that I didn't get the tutorial complete after-all, although one of those squares just has an empty script.

Not a lot more work is required to turn it into a useful if basic game behaviour editor. Just the ability to save and create scripts and a few little lookup and navigation functions.

A couple of days ago after some work on jjjay I had a fleeting thought about how the game might be transformed to use a database backend. With Berkeley DB JE it would be a cinch, I could reliably persist all the live game objects into a single table with very little work indeed - the subclassing stuff is better than I can recall from last time i looked at it but I suspect I just didn't look too closely. I shouldn't need any DTO's. Actually it would probably turn out to be easier than all the text-mode import/export stuff I had to come up with and it could also be used to replace some of the internal indices. Using a db means that a text editor can no longer be the primary development tool so it would also require additional tooling. Something to ferment in the wort a bit longer ...

I had some other fleeing thought about something about the game, but it just flitted away ...

On an unrelated note, ScrollBar doesn't support middle-click. Annoying.

Oh thats right on the flittery thought. The way JavaScript is being used in the scripts is so simple, I wonder if it isn't easier just using Java instead. The scripts would stay in their format but could inserted into a template before being compiled. Might be an option for rarely-changing/performance critical tasks, but might not be so easy for any dynamic content. Definitely not something i'm going to rush into without a lot of experimentation.