Rewrite input system for hot-plugging

Kenneth Bull wrote:

2009/9/8 Mason Wheeler :

Your assertion that most initialization values should be zero or NULL
is completely f’n retarded. It is critical to initialize values
yourself.

This is true, you should be initializing variables yourself, but
having a sensible default assigned by the constructors of the various
types you’re working with helps. Not zeroing everything through some
backend compiler magic, but using well designed type classes that do
it for you. Even int and double have constructors, which do assign a
zero value by default. The compiler just doesn’t always call these
constructors on basic types when you might expect it to.

Isn’t it true that in C++, all uninitialized data members are implicitly
0? Which is to say that it’s
not by some ‘backend compiler magic’ that an uninitialized pointer member
of some class is
already NULL before initialization, but instead through compliance to the
language itself.

To make it extra clear for those who don’t get it: Zero is often not the
right ultimate value to initialize your references to when you create an
object. But it’s the only starting point that makes sense, because
things can go wrong while creating an object, and C++'s object model
not zeroing object memory before the constructor runs is a serious
defect.

I’m sure you meant ‘pointer’ rather than ‘reference’ in the preceding.

On the other hand, there’s often a fair amount of the object that you want
to initialize to 0, especially non-object members. In this case, zeroing
the memory beforehand saves you a lot of work.

“Zeroing memory beforehand” would also be time consuming for large
types and arrays. So would calling constructors. Also, if you’re
using pointers, the compiler can’t really initialize the pointer’s
target, only the pointer itself.

Everybody has to pay the consequences for their design decisions, if you
really have a large array that
has to be zeroed, I’m assuming that you’ve examined alternative methods
and concluded that it has to
be done, and that nobody is going to do it for you.

Mason Wheeler wrote:

Compared to the alternative of requiring ugly workarounds for more
common use cases (ie. both video and input) seems undesirable to the
SDL community.

What ugly workarounds?

The ugly workaround of having to manually separate the input events for
your window from input events for some other window.–
Rainer Deyke - rainerd at eldwood.com

The scoped lock is an incontrovertible victory IMHOOn Tue, Sep 8, 2009 at 4:02 PM, Rainer Deyke wrote:

Mason Wheeler wrote:

Umm… what C++ are you using? ?In the one I learned in college,
RAII isn’t “great”, it’s an annoying, hackish idom requiring the
coder to do a lot of extra work to compensate for two stupid
mistakes in the language design: that object construction
doesn’t zero out the memory space first and that you’re allowed
to allocate objects on the stack.

RAII and the ability to put objects in the stack are the reasons I use
C++. ?Other designs are possible, but it is supremely ignorant to call
these aspects of C++ “design mistakes”.


http://codebad.com/

This is true, you should be initializing variables yourself, but
having a sensible default assigned by the constructors of the various
types you’re working with helps. Not zeroing everything through some
backend compiler magic, but using well designed type classes that do
it for you.

Yep. Ideally, the compiler shouldn’t have to do that for you; it should be
built into the base object class’s initialization routine. (Oh, wait…) Or I
suppose you could rewrite malloc/new to zero the dynamic memory it
allocates before returning.

“Zeroing memory beforehand” would also be time consuming for large
types and arrays. So would calling constructors. Also, if you’re
using pointers, the compiler can’t really initialize the pointer’s
target, only the pointer itself.

True, but you’ll need a very large array or object (with size measured in
megabytes) before this becomes a noticeable performance hit. And
if you’re doing something like that, you’d probably benefit from evaluating
your options and seeing if a single large array is really the best solution
for the problem you’re working on.

Objects, on the other hand, tend to be very small. It’s not very common
to see one with an instance size over 200 bytes. (Especially if you don’t
go allocating other large objects or arrays as value types within your
object.)

You’re not likely to get an exception when assigning values to basic
types. You could initialize the simple stuff at the beginning of the
constructor and the more complex stuff near the end. Also, don’t
forget that most exceptions can be caught. You can put a try/catch
block in a constructor. You can also set a flag at the beginning of
the constructor and clear it at the end to indicate whether it
finished or not.

The problem is that just knowing it didn’t finish doesn’t tell you where it
failed. What if you have 10 different sub-objects in your object, and
something goes wrong while constructing #3? You’d need 10 flags to do
it right, and I think we can all agree that that’s a far worse solution than
zeroing out the memory first.

Umm… most of the resources you acquire do exist only inside process
memory! Show me even one program where external resources account
for more than 1% of resource acquisitions. And there are plenty of
better ways to handle external resources. (And if you know of a nuclear
power plant whose control system runs on C++, please let me know
where it is so I can make sure I don’t live nearby.)

Anything which uses files, input devices or system calls.

raises an eyebrow OK, let’s take the program I work on at work. Serious
app. Around 3.5M lines of code. One COM object to work with an external
DLL. One comm subsystem that handles connections with a handful of
middle-tier app servers. Maybe a few dozen synchronization objects, and
of course a few thousand Windows handles for all the GUI stuff, user input,
and a little bit of file handling. And hundreds of thousands of objects that
get allocated in process memory. The middle-tier servers look a lot like
that, too. A bit more comm stuff, a whole lot less GUI, but a similar
overall distribution. And I don’t think there are very many apps that don’t
look like that.>----- Original Message ----

From: Kenneth Bull
Subject: Re: [SDL] Rewrite input system for hot-plugging

2009/9/8 Donny Viszneki <donny.viszneki at gmail.com>:

Can you see any benefits (to the API
users primarly, but also to the library maintainers) of writing some
areas in C++?

First, I’m not talking about replacing parts of the backend with C++,
but rather having a separate C++ library with access to SDL internals.
Basically libSDL.a, libSDL.so, SDL.lib or SDL.dll would be the same
as it is now, but there would be another API, with it’s own separate
set of include files which makes use of C++ for the publicly
accessible parts of the library. For platforms without a C++
compiler, the C library would still be available.

Advantages to C++:

  1. constructors and destructors.
  2. namespaces. Doing this as an alternative API instead of a wrapper
    avoids having SDL_* functions dumped into the main namespace when they
    aren’t going to be used there anyway.
  3. inheritance. For example, having specialized surface classes for
    different pixel formats could boost performance. Users could also
    define their own surface classes to support things like jpeg and png
    surfaces.
  4. operator and function overloading. Allows stuff like this for example:

Surface output = screen(
(screen.width - image.width) / 2, (screen.height - image.height) / 2,
image.width, image.height
);
for (int i = 0; i <= fps; ++i) {
output.pixels = image.pixels * ((float) i / fps);
sleep(1000/fps);
}

Or this:
surface(x, y) = Color(1.0, 0.0, 0.0);

Or this:
screen(x, y) << image;

Or this:
for (Surface::iterator i = screen.begin(); i < screen.end(); ++i)
*i = Color(rnd(), rnd(), rnd());

  1. keeping everything neatly packaged in separate objects makes
    thread safety easier.
  2. virtual member functions. Structs loaded with function pointers
    are ugly, and uninitialized function pointers are very, very bad, even
    if you set them to 0. With C++, if you forget to define a pure
    virtual function, it’s caught at compile time.
  3. you can use a signal/slot system for input.

Here’s an example of what it might look like:
#include

// define a class to handle input events
class MyHandler: public SDL::Container {
public:
MyHandler();
void quit();
bool running;
};

MyHandler::MyHandler() {
running = true;
}

void MyHandler::quit() {
running = false;
}

int main(int, char**) {
// Initialize SDL and subsystems
SDL::Instance sdl = SDL::Instance();
SDL::Video::Instance video(sdl, “opengl”);
SDL::Input::Instance input(sdl, “x11”);
// or without the drivers to select sensible defaults.

// Create handler instance
MyHandler handler;

// Create main window
SDL::Video::Window window = video.CreateWindow(windowTitle,
Rect(0, 0, 640, 480), SDL::Video::FullScreen);

// Tell window to send events to input
// On Windows, this would basically replace DefWindowProc
// with an input member function.
window.bind(input); // or input.bind(window);

SDL::Signal0<> windowClosed =
SDL::Input::Events::WindowClosed(input, window);
windowClosed.connect(handler, &MyHandler::quit);

window.Show();

while (handler.running) {
input.Wait()
}

return 0;
}

SDL is an abstraction layer. There are a lot of C structs packed with
pointers to functions which have been selected by SDL as being the
appropriate implementations of what is symbolically referred to by the
corresponding struct member. These are a lot like Java interfaces, or
C++ pure virtual base classes (or nearly pure, anyhow.)

“C++ tends to produce much larger binaries” is a myth. If you write
something using a bunch of STL or other template-heavy code, then
sure, you get big binaries. But attributing this to C++ is a mistake.

RTTI also adds to the size of binaries, but is often disabled by
default and rarely used.
Virtual function tables add some bulk, but probably not much more than
function pointers in a struct.> On Tue, Sep 8, 2009 at 10:32 AM, Brian<brian.ripoff at gmail.com> wrote:

Mason Wheeler skrev:

A much better way to measure the quality of a language feature is to
see what else uses it. Truly good features get copied around and
integrated elsewhere. AFAIK the only other programming language that
implements RAII is D.

A quick look at wp:RAII shows:
"… is a popular design pattern in several object oriented programming
languages like C++, D and Ada"

2009/9/8 Kenneth Bull <@Kenneth_Bull>:

?SDL::Signal0<> windowClosed =
? ?SDL::Input::Events::WindowClosed(input, window);
?windowClosed.connect(handler, &MyHandler::quit);

Make that

SDL::Adapter1_0
windowClosed(input.WindowClosed, &window);
windowClosed.connect(handler, &MyHandler::quit);

Where Adapter1_0 looks like this:
template
class Adapter1_0: public Signal0<>, public Container {
public:
Adapter1_0(Signal1&, A1);
private:
void slot(A1);
A1 a1;
};

template
Adapter1_0::Adapter1_0(Signal1& signal, A1 a1) {
signal.connect(*this, &Adapter1_0::slot);
}

template
void Adapter1_0::slot(A1 a1) {
if (a1 == this->a1)
this.emit();
}

2009/9/8 Kenneth Bull <@Kenneth_Bull>:

template
void Adapter1_0::slot(A1 a1) ?{
?if (a1 == this->a1)
? ?this.emit();
}

just emit(), this is a pointer…
I need caffeine…

Agreed. C++ is great, but it doesn’t belong in libraries.On Tue, 08 Sep 2009 21:18:10 +0200 Jens wrote:

i prefer c++ over c but anyway I would not introduce C++ to SDL.
Why? Because providing language bindings and a stable API for C
libraries is so much easier. (+ portability is still easier with C).

Kenneth Bull wrote:

Advantages to C++:

I like C++ and use it almost exclusively, but…

  1. inheritance. For example, having specialized surface classes for
    different pixel formats could boost performance. Users could also
    define their own surface classes to support things like jpeg and png
    surfaces.

Using inheritance here is less flexible than treating the pixel format
as pure data. Jpeg and png loading is not a property of a surface, but
of the function that generates the surface.

Or this:
surface(x, y) = Color(1.0, 0.0, 0.0);

Too slow to be useful.

Or this:
screen(x, y) << image;

Yuck!

  1. virtual member functions. Structs loaded with function pointers
    are ugly, and uninitialized function pointers are very, very bad, even
    if you set them to 0. With C++, if you forget to define a pure
    virtual function, it’s caught at compile time.

This is an implementation issue that doesn’t affect library users.

  1. you can use a signal/slot system for input.

This is a very bad idea. As a low-level library, SDL should provide a
clean and minimal interface. The choice of input dispatch system should
be left to the application, not the library. I don’t want to deal with
a dozen different signal/slot systems just because I use a dozen
different low-level libraries.

#include

And please don’t use extension-less header files unless your library has
been accepted as part of the C++ standard library.–
Rainer Deyke - rainerd at eldwood.com

Rainer Deyke wrote:

Kenneth Bull wrote:

Advantages to C++:

Or this:
surface(x, y) = Color(1.0, 0.0, 0.0);

Too slow to be useful.

Too slow to be useful for what? Your answer implies that there is only
one problem to be solved, and only one acceptable way to solve it.
Bicycles are too slow to be useful, and yet they’ve been used daily
since they were invented.

Or this:
screen(x, y) << image;

Yuck!

You say ‘Yuck!’ as if that were some useful examination of the pros and
cons of something going on in that particular code snippet.

I say that that is a very elegant piece of high level language and
brings up one of the valuable aspects of C++, the ability to make a
syntax that is quick and intuitive to write. The ability to write bug
free code, and then return years later for maintenance purposes and be
able to read it and understand it without spending hours trying to
decipher it. If there’s any ‘Yuck’ behind that simple code, it’s
certainly not in that line, nor is it a requirement for the
implementation of that line. Since we can’t see the implementation
details, any ‘Yuck’ is in your imagination.

Runtime and compile time efficiencies are always considered in a design,
but coding and maintenance efficiencies are also very valuable, and
should not be discounted just because somebody says, ‘Yuck’. (As if
’Yuck’ had any value).

2009/9/8 Rainer Deyke :

Using inheritance here is less flexible than treating the pixel format
as pure data. ?Jpeg and png loading is not a property of a surface, but
of the function that generates the surface.

Don’t need to sacrifice flexibility for speed or vice versa. You can
have a general surface class which handles pixel format just like
SDL_Surface does now, but that doesn’t have to be the only surface
class available. A 32-bit or 8-bit surface class could run much
faster when setting or retrieving pixel values or converting colors to
pixel data than a more general class would. It also allows formats
which can’t be represented using the standard pixel format, like
anything with less than 8-bits per pixel or that uses a color system
other than RGB.

Having jpeg and png surfaces would allow you to trade time when
actually displaying the image for lower load time and memory
consumption. It’s not something everyone would use, but it would be
nice to at least have that option. It also means you can work with
the data in it’s original format, which helps when dealing with lossy
compression.

Or this:
surface(x, y) = Color(1.0, 0.0, 0.0);

Too slow to be useful.

Depends what you’re using it for. If you really do need to set just
one pixel, that’ll work fine.
For multiple pixels, you could use something like this:

uint32_t data = surface.format.FormatColor(Color(1.0, 0.0, 0.0));
Pixel pixel(surface, x, y);

then, to set a pixel:
pixel = data;

and move pixel using pixel.MoveBy(dx, dy), pixel.MoveDown(),
pixel.MoveRight(), etc., which could be implemented through friend
functions in the surface class to handle whatever customizations were
made there.

As long as Pixel stores it’s position as a pointer (and maybe bit
offset), not an x, y pair, this will be plenty fast, though you’ll
need to be careful with clipping and bounds checking.

Or this:
screen(x, y) << image;

Yuck!

I’m not a fan of that one either, to be honest. I figure = should
assign a value without moving the Pixel, while << should assign a
value and update the position to the end of whatever you put in there.
A one liner like this should probably use = or ditch the operators
and use something like screen.draw(x,y, image); (which could be
overloaded to draw other objects).

  1. ?virtual member functions. ?Structs loaded with function pointers
    are ugly, and uninitialized function pointers are very, very bad, even
    if you set them to 0. ?With C++, if you forget to define a pure
    virtual function, it’s caught at compile time.

This is an implementation issue that doesn’t affect library users.

Except when they submit a patch or run across a bug, and this would
reduce the number of bugs. SDL users are SDL developers and vice
versa. You don’t work on something you can’t use.

This would have to be added at a fairly low level if you want to use
it in video drivers, etc. though, which would mean no more pure C
library.

  1. ?you can use a signal/slot system for input.

This is a very bad idea. ?As a low-level library, SDL should provide a
clean and minimal interface. ?The choice of input dispatch system should
be left to the application, not the library. ?I don’t want to deal with
a dozen different signal/slot systems just because I use a dozen
different low-level libraries.

So keep the signal/slot library separate from the rest so other
libraries can use it without depending on SDL.
(like this one for example: http://sourceforge.net/projects/signalslot/ )

2009/9/8 Donny Viszneki <donny.viszneki at gmail.com>:

What ugly workarounds?

SDL_Init(SDL_INIT_VIDEO | SDL_INIT_INPUT);

Done.

sigh

Yes, that is the way things are now. I wasn’t advising against making
core changes to the input and video subsystems that would make things
the way they are already.

No, it’s not. There is an event thread flag, but that’s just passed
the SDL_VideoInit; It does not specify a separate subsystem. Right
now, SDL_INIT_VIDEO starts both video and events and neither can be
started without the other.

Right now it can be a little hairy if you want input without video. My
understanding which I explained already was that this was because some
platforms require a window before you can listen to certain input
devices.

If you’re talking about Windows, which expects an HWND for
RegisterRawInputDevices(), among others, you can create a window, but
not show it, and still receive events. For events which do require a
visible window, like most mouse input for example, you can have your
window procedure handle WM_PAINT and such, and call a function pointer
stored in the window data to handle everything else. When creating
the window the function pointer is set to DefWindowProc (or some brief
wrapper around it). When the window is bound to the input system, the
function pointer is changed so that the input system receives all
unhandled events.

I believe X11 could be handled more or less the same way, and I don’t
think it’ll be much of a problem for the rest.

This would also mean you can have video-sans-input, which might mean
faster start times if you don’t really need input in the SDL window
(like if you’re using it in a child window via the SDL_WINDOWID
environment variable).> On Tue, Sep 8, 2009 at 10:10 AM, Mason Wheeler wrote:

2009/9/8 Mason Wheeler :

Or I
suppose you could rewrite malloc/new to zero the dynamic memory it
allocates before returning.

that would be calloc ( http://www.cppreference.com/wiki/c/mem/calloc )

True, but you’ll need a very large array or object (with size measured in
megabytes) before this becomes a noticeable performance hit. ?And
if you’re doing something like that, you’d probably benefit from evaluating
your options and seeing if a single large array is really the best solution
for the problem you’re working on.

Objects, on the other hand, tend to be very small. ?It’s not very common
to see one with an instance size over 200 bytes. ?(Especially if you don’t
go allocating other large objects or arrays as value types within your
object.)

And then you have arrays of objects… or objects allocated and freed
in a loop (generally bad programming, but still pretty common).

You’re not likely to get an exception when assigning values to basic
types. ?You could initialize the simple stuff at the beginning of the
constructor and the more complex stuff near the end. ?Also, don’t
forget that most exceptions can be caught. ?You can put a try/catch
block in a constructor. ?You can also set a flag at the beginning of
the constructor and clear it at the end to indicate whether it
finished or not.

The problem is that just knowing it didn’t finish doesn’t tell you where it
failed. ?What if you have 10 different sub-objects in your object, and
something goes wrong while constructing #3? ?You’d need 10 flags to do
it right, and I think we can all agree that that’s a far worse solution than
zeroing out the memory first.

10 flags or one counter, but still, it’s one of several options, not
the one and only option. What makes sense depends on what you’re
doing.

Umm… most of the resources you acquire do exist only inside process
memory! ?Show me even one program where external resources account
for more than 1% of resource acquisitions. ?And there are plenty of
better ways to handle external resources. (And if you know of a nuclear
power plant whose control system runs on C++, please let me know
where it is so I can make sure I don’t live nearby.)

Anything which uses files, input devices or system calls.

raises an eyebrow ?OK, let’s take the program I work on at work. ?Serious
app. ?Around 3.5M lines of code. ?One COM object to work with an external
DLL. ?One comm subsystem that handles connections with a handful of
middle-tier app servers. ?Maybe a few dozen synchronization objects, and
of course a few thousand Windows handles for all the GUI stuff, user input,
and a little bit of file handling. ?And hundreds of thousands of objects that
get allocated in process memory. ?The middle-tier servers look a lot like
that, too. A bit more comm stuff, a whole lot less GUI, but a similar
overall distribution. ?And I don’t think there are very many apps that don’t
look like that.

Not many programs make it to 3.5 million lines of code… In a
smaller program, I expect a much larger proportion of code and memory
would be devoted to GUI, I/O, networking and system calls, or whatever
libraries it’s using. It would also vary greatly by the type of
program you’re writing.

2009/9/8 Tim Angus :

Agreed. C++ is great, but it doesn’t belong in libraries.

The one reason I can see for keeping C++ out of libraries is that the
C++ standard doesn’t define an ABI like C does.
Specifically, the manner in which C++ classes are stored varies wildly
from one compiler to the next, or even different version of the same
compiler.

This isn’t really a big deal though since, on Windows, you can just
include the library with your program, and on linux, you generally use
the same compiler to compile just about everything.

CWC wrote:

Kenneth Bull wrote:

Or this:
screen(x, y) << image;

I say that that is a very elegant piece of high level language and
brings up one of the valuable aspects of C++, the ability to make a
syntax that is quick and intuitive to write.

How is left-shifting a pixel by an image an intuitive operation?–
Rainer Deyke - rainerd at eldwood.com

2009/9/8 Rainer Deyke :

CWC wrote:

Kenneth Bull wrote:

Or this:
screen(x, y) << image;

I say that that is a very elegant piece of high level language and
brings up one of the valuable aspects of C++, the ability to make a
syntax that is quick and intuitive to write.

How is left-shifting a pixel by an image an intuitive operation?

Is left shifting an output stream by a string any better?

Kenneth Bull wrote:

Not many programs make it to 3.5 million lines of code… In a
smaller program, I expect a much larger proportion of code and memory
would be devoted to GUI, I/O, networking and system calls, or whatever
libraries it’s using. It would also vary greatly by the type of
program you’re writing.

Don’t forget that ownership of external resources is a transitive
property. You can have memory objects pointing to memory objects
containing memory objects pointing to memory objects referencing
external resources. Now the entire chain holds an external resource and
must be disposed in a timely manner.–
Rainer Deyke - rainerd at eldwood.com

Rainer Deyke wrote:

CWC wrote:

Kenneth Bull wrote:

Or this:
screen(x, y) << image;

I say that that is a very elegant piece of high level language and
brings up one of the valuable aspects of C++, the ability to make a
syntax that is quick and intuitive to write.

How is left-shifting a pixel by an image an intuitive operation?

I assume that if you were really interested in a discussion, you
wouldn’t pretend that you don’t recognize the stream insertion operator,
while at the same time pretending that you do recognize the return
values and data types used in a line of code you didn’t write.

At any rate, given a context where that line of code was valid, but
beyond your intuition, I’m sure that it would not be much harder to
learn than the meaning of var++.

Kenneth Bull wrote:

Don’t need to sacrifice flexibility for speed or vice versa.

When you add virtual functions to a class, every use of that class and
its subclasses pays the penalty. If you don’t use virtual functions,
there’s not much you can do with inheritance.

You can
have a general surface class which handles pixel format just like
SDL_Surface does now, but that doesn’t have to be the only surface
class available.

In which case you’re sacrificing simplicity.

A 32-bit or 8-bit surface class could run much
faster when setting or retrieving pixel values or converting colors to
pixel data than a more general class would.

This is better handled by a wrapper class than by inheritance, IMO.

It also allows formats
which can’t be represented using the standard pixel format, like
anything with less than 8-bits per pixel or that uses a color system
other than RGB.

Fundamentally, SDL needs to be able to understand the pixel format in
order to use it.

Having jpeg and png surfaces would allow you to trade time when
actually displaying the image for lower load time and memory
consumption.

If you display the image even once, you lose any speed gains you made.

For multiple pixels, you could use something like this:

uint32_t data = surface.format.FormatColor(Color(1.0, 0.0, 0.0));
Pixel pixel(surface, x, y);

then, to set a pixel:
pixel = data;

‘a = b’ should not have any side effects beyond setting local variable
’a’ equal to ‘b’. ‘*pixel = data;’, maybe.

So keep the signal/slot library separate from the rest so other
libraries can use it without depending on SDL.
(like this one for example: http://sourceforge.net/projects/signalslot/ )

I like the Boost signal/slot library, but I don’t want SDL to use that
either. The input dispatch mechanism should be left up to the application.

Example: it’s not unusual for games to implement mini-games that use
their own input schemes. This is simple enough to implement using SDL:

void run_mini_game() {
// Local event loop here.
}

void main_game() {
for (;:wink: { // Main event loop.
//…
if (cond) run_mini_game();
//…
}
}

Now, if you use a na?ve signal/slot system, you will have to unregister
all of your event handlers at the start of the mini game and reregister
them at the end. If you do your own event dispatching, you can simply
choose not to dispatch events from inside the mini game to the outer game.–
Rainer Deyke - rainerd at eldwood.com