Do software surfaces use the graphics card?

33 views
Skip to first unread message

Başar Erdivanlı

unread,
Nov 9, 2014, 10:28:26 AM11/9/14
to lispb...@googlegroups.com
I have a windows 7, emacs 24.3, slime 2.10.1, sbcl 1.2.1 and have no problem building and running animations like below:



I have three separate questions, where the first two may not be specific to lispbuilder:

1) Whenever I install lispbuilder-sdl libraries through quicklisp (which is the only way I succeeded), [Condition of type CFFI:LOAD-FOREIGN-LIBRARY-ERROR] error occurs. I always do 'use-value' and type for example '("c:/zlib1.dll")' and it works. In order to keep the typing short, I keep the dll files in C:/, but although I added C:/ to windows PATH, and evenhough I setf *default-pathname-defaults* to #P"C:/", I can't get rid of this error.

I installed games using lispbuilder-sdl like slugmage or The Testament of the White Cypress. All these games contain the corresponding dll files in their folder. so I also tried to put the dll files into the lisp program's folder, but this didn't work, too. Files in question are: jpeg.dll, libfreetype-6.dll, libpng12-0.dll, libtiff-3.dll, zlib1.dll. The other dll files required ( SDL.dll and SDL-ttf.dll) can be found/seen by quicklisp.

So where should I put these dll files so that lisp (or maybe slime) can find them?

2) I occasionally get '; Evaluation aborted on #<BABEL-ENCODINGS:INVALID-UTF8-CONTINUATION-BYTE {268D41D1}>.' error. This usually occurs when the png library is not loaded. I know that, because with sbcl 1.2.1, I can get by reloading lispbuilder-sdl, but with earlier versions of sbcl, I suffer from this error, which was asked by someone else in this forum. This occasional problem is not related to any duration or command, and it's really not much of a problem, but may be related to problem1. Any idea?

3) As for the above program (where I try to simulate red blood cells, who turn around themselves, move to the right and occasionally collide to the walls of a vein), the animation (naturally) get progressively slower the more red blood cells I add. I already read that a surface in system memory (software surface) improves the performance of pixel level access but is incompatible with some types of hardware blitting. But I want to be able to check what resource the program is exactly using (sbcl usually uses 25% cpu time and around 100 mgb ram). I tried to see details in process explorer and got this screenshot:

but the CPU Graph is completely empty. Does this mean that I am using the cpu only and do not benefit from the graphics card? If so, or if I should better benefit from the graphics card, could someone guide me about my code below:

(sdl:draw-surface (sdl:load-image *vessel*))                                        ; *vessel* is the background in gif format
(loop for rbc in blood                                                                         ; blood is the state of all red blood cells as a list like  '( '(x-coordinate y-coordinate horizontal-speed current-degree-of-rotation) '(x-coord...
  do (sdl:draw-surface-at-*
         (sdl:rotate-surface (fourth rbc)
         :surface (sdl:blit-surface (sdl:load-image *rbc* :alpha 128)           ; *rbc* is the red blood cell in png format, hence the :alpha value
                                             (sdl:create-surface 50 45 :alpha 128)))
         (first rbc) (second rbc)))

Note: Basically, the code loops through each red blood cell in the list,
               rotates it to the new degree (which, and the next x- and y-coordinates, and the horizontal speed are calculated by another function),
               then puts it at the x-coordinate (first rbc) and y-coordinate (second rbc)


Elliott Slaughter

unread,
Nov 9, 2014, 2:32:44 PM11/9/14
to lispb...@googlegroups.com
1. This is an issue with CFFI not knowing the right place to find the DLL files. Last time I tested on Windows, it was sufficient to put DLL files in the current directory (not the one where sbcl.exe lives, but wherever you are running from). If that fails, I would try setting cffi:*foreign-library-directories* according to the instructions below. Note that, unlike what the CFFI manual claims, you are expected to modify this directory on Windows where typically there is no universally accepted place to put DLL files.
2. I'm honestly not sure about this one, and I don't know what libpng would have to do with babel encodings. If you find a reliable way to repro this please let me know.

3. My guess is that your time is going into repeatedly calling sdl:load-image. Both CPU and GPU are going to be massively faster than hitting disk, even when the file in question cached. I probably should have gotten around to responding to your other email sooner (sorry for the delay! I'll try to go answer it now!) but the short answer is: call sdl:load-image once, save the result in a surface, and repeatedly blit that surface over and over. If that's still slow, then we can talk about further optimizations.

--
You received this message because you are subscribed to the Google Groups "Lispbuilder" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lispbuilder...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Elliott Slaughter

"Don't worry about what anybody else is going to do. The best way to predict the future is to invent it." - Alan Kay

Başar Erdivanlı

unread,
Nov 9, 2014, 4:50:06 PM11/9/14
to lispb...@googlegroups.com
Thank you very much!

1. (setf cffi:*foreign-library-directories* '(#P"C:/")) solved that issue.

2. This problem occurs when libpng is not loaded properly (due to lispcabinet's old version of sbcl) and lispbuilder-sdl cannot read png files. Gif or bmp images work for example, but the transparency is lost. But as long as I can use sbcl 1.2.1, this is not a problem. I wrote that just in case problem 1 and 2 may be related somehow.

3. I'm gonna work on this. But just didn't get one thing: Shall I stop using the loop in order to call sdl:load-image only once? Or is it still possible with the loop? *Please don't answer this one with a code. I just want a direction*

Başar Erdivanlı

unread,
Nov 9, 2014, 5:14:17 PM11/9/14
to lispb...@googlegroups.com
Sorry, I just saw your other response about the surfaces. I think I'll be able to handle problem 3 with the loop, if I'll save each image in a variable, and then put them on a surface at once.

Elliott Slaughter

unread,
Nov 9, 2014, 8:56:23 PM11/9/14
to lispb...@googlegroups.com
Just in case you haven't seen it, there is a lispbuilder-sdl-image library which should be able to load PNGs. (It wasn't clear to me whether your PNG problem was SBCL-version related or just related to the fundamental limitation that core lispbuilder-sdl doesn't handle as many image types as lispbuilder-sdl-image.)

https://lispbuilder.googlecode.com/svn/trunk/documentation/lispbuilder-sdl-image.html

Yup, I think your looping approach should still work, as long as your have the images in global variables or something.

On Sun, Nov 9, 2014 at 2:14 PM, Başar Erdivanlı <berdi...@gmail.com> wrote:
Sorry, I just saw your other response about the surfaces. I think I'll be able to handle problem 3 with the loop, if I'll save each image in a variable, and then put them on a surface at once.

--
You received this message because you are subscribed to the Google Groups "Lispbuilder" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lispbuilder...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Başar Erdivanlı

unread,
Nov 10, 2014, 6:03:43 PM11/10/14
to lispb...@googlegroups.com

Well, the animation runs definitely much better. Unfortunately I can't benchmark it to provide objective results.

May I have just one more question, if that's not rude? A referral to any book will also suffice. I'm just learning C from Zed Shaw's learn C the hard way. I'm up to pointers. But I can't figure out one very fundamental thing:

1) When I define a variable (defvar x) as an image with the call (setf x (sdl:load-image "y.png")), does the code assign part of the memory (a pointer to an address on the ram block, I guess) to hold the image?
2) And if so, evaluating that variable x again and again does not result in another call to sdl:load-image, right?
3) Instead, evaluating variable x simply and only results in access to the memory address defined by the pointer, right?

And finally, if all these are correct, then it is my fault/abuse to call sdl:load-image several times. If I would try to create the same code in a low level language like C for example, I would have to create a massive code duplication to achieve the same thing. This last sentence is a bit obscure, so here is what I really mean:

Since I am using a higher level language, it is easy for a noob like me to accidentally overuse the high level language's capability to create pointers/objects etc.
And since lisp has a garbage collector, it is hard for a noob like me to be aware of this condition.
Because lisp collects the garbage, I may not understand that I'm flooding the memory with useless pointers/objects by looking at the ram usage.

PS: I won't mind if you won't answer this, since I couldn't find a direct answer to this in books or stack exchange sites, yet:(

Başar Erdivanlı

unread,
Nov 11, 2014, 5:18:16 PM11/11/14
to lispb...@googlegroups.com
Well, I'm truly sorry for the last question. Today, I read the sentence belowand now I see why people don't answer such questions:
 

Seems that I have to read a lot. On the other hand, I was thinking whether my state (a list of lists) is not good for performance and the same paper says that if arrays are created with a type-specification are more quick to process compared to arrays created with no type-specificaiton. This is a very useful paper I think. Just wanted to share.

Thank you for the help.

Elliott Slaughter

unread,
Nov 12, 2014, 1:22:40 AM11/12/14
to lispb...@googlegroups.com
Don't worry about asking; as many of my teachers have said, there are no stupid questions. :-)

I think you're already on your way to the right answer, but there are a couple things I would mention. I'm going to use terminology from C, just to be really clear what the machine is doing. Most Lisp introductions won't actually describe things this way.

1. Conceptually, global variables live in the data section of a program. They get initialized at program start (well, kind of... Lisp is interactive, so this isn't really true, but if you think of it this way you'll be right most of the time).

2. Because this is Lisp, all variables hold pointers, or immediate values which are roughly pointer sized (like a 29-bit integer on a machine with 32-bit pointers).

3. So if you assign a Lisp variable (global or otherwise) to an array, you are assigning the variable (which is a pointer) to a block of heap-allocated, which you could think of as being returned by C's malloc. Depending on what sort of type annotations you supply with the array, each element will be either a pointer (again, like variables) or an immediate value.

4. Surfaces behave (for the most part) like arrays, except that they might potentially live on the GPU, and will always have an appropriate type declared. So conceptually, sdl:load-image calls malloc, reads the contents of the image from a file, stuffs that into the memory just allocated, and returns a pointer. This pointer is what you are storing in a variable, or passing to draw-surface.

You are right to an extent that Lisp's garbage collector allows you to worry much less about memory allocation. For example, you could write the same code in C, and it would actually be worse, because in addition to loading the image over and over you'd also have a memory leak:

draw_surface(load_image("filename.jpg"))

I think the bigger issue is actually one of education. None of the standard Lisp texts teach you at the level of regions of memory (data, heap, stack, text) and pointers vs immediates. Even though I don't always need the performance, I find that thinking this way really clarifies my coding, especially if I am doing anything with aliasing. Certainly, if you ever do performance programming in Lisp, you'll need to think this way to understand what sort of code the compiler will generate for the programs you write.

One word of caution though: even though it helps to think conceptually about the underlying operations in your code, that doesn't mean you want to start adding type declarations everywhere. Lisp is still not C and shouldn't be written like C. And more importantly, Lisp compilers are actually really smart and can often give you really decent code without type declarations. I've even seen some cases where well-written code without type declarations out-performed less-well-written code with type declarations.

P.S. By the way, the paper you linked seems reasonable enough, though I haven't read it personally. One thing to keep in mind though is that when they are talking about performance they are usually using algorithms with very tight inner loops where is it possible to generate really efficient code with a small number of type declarations. For typical Lisp programs, you do not need to do this for 99% of your program, and in general, I would avoid using type declarations at all (except possibly for arrays) until you get the hang of writing efficient *non-typed* Lisp code (which is entirely doable for the vast majority of applications).

--
You received this message because you are subscribed to the Google Groups "Lispbuilder" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lispbuilder...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Başar Erdivanlı

unread,
Nov 15, 2014, 7:05:25 PM11/15/14
to lispb...@googlegroups.com
Well, finally this makes sense to me:
  1. If you get a block of memory from malloc, and have that pointer on the stack, then when the function exits, the pointer will get popped off and lost.
  2. If you put too much data on the stack (like large structs and arrays) then you can cause a "stack overflow" and the program will abort. In this case, use the heap with malloc.
  3. If you take a pointer to something on the stack, and then pass that or return it from your function, then the function receiving it will "segmentation fault" (segfault) because the actual data will get popped off and disappear. You'll be pointing at dead space.
That made me read about dynamic extent, and understand much more about workings of the common lisp, and cffi.
Thanks again for the great help!

Elliott Slaughter

unread,
Nov 17, 2014, 6:00:41 PM11/17/14
to lispb...@googlegroups.com
Right. Something to remember though is that in Lisp, the garbage collector (plus having pointers be implicit instead of explicit) saves you from a lot of potential problems. E.g. your case 1 is fine in Lisp; the memory gets collected by the GC. Case 3 can't happen unless you explicitly use dynamic extent, which is assumed to be an expert-only feature (so basically, don't use it unless you really know what you are doing).

In general, feel free to reason about memory and pointers, but still try to stick to the intuitive code first and worry about performance (e.g. dynamic extent) after you know you've got a performance problem. (And even then, Lisp performance optimization is unintuitive and different from C optimization.)

Anyway, glad you're learning to pull the cover of the compiler :-)

--
You received this message because you are subscribed to the Google Groups "Lispbuilder" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lispbuilder...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Luke Crook

unread,
Nov 17, 2014, 6:46:35 PM11/17/14
to lispb...@googlegroups.com

One of the nice things about SDL software surfaces is the ability to share memory with an OpenGL surface.  What I've done in the past is to share the SDL display surface with an OpenGL texture, then map this to the side of a rotating OpenGL cube.  I actually looks pretty cool.


Reply all
Reply to author
Forward
0 new messages