Dynamic dream API questions

If this post was any longer I could get a book deal

I'm playing around with doing a dynamic dream. I've got your sample working fine, using VS2005 (compiling both win32 and x64, making it into a dream, actually running in deskscapes).

I apologize hugely in advance for the length of this post, and for showing up guns blazing with Post One, but I'm psyched about being able to do this kind of thing - I've wanted to do something like this since the days of Win95 - but my skill and time haven't been adequate to the task of building the infrastructure. Now that you guys did the hard part, I'm like, "Now I can re-write all the cool but useless math visualizations I did back in 1994, and people can SEE them!" So, I'd really like to make this work, despite my utter lack of experience in the environment and the general inadequacy and antiquity of my coding knowledge.

So. I'm working on doing some simple pixel-pushing (don't ask me why; just accept it and move on... if I have to explain why I like drawing pixels ONE MORE TIME, I swear...! :) ), using the sample as a base and writing to the texture like so:

 

In UpdateScene() I have something like:

 

D3DLOCKED_RECT rect;
ZeroMemory(&rect, sizeof(D3DLOCKED_RECT));
D3DCOLOR mypixel;


obj[i].texture->LockRect(0, &rect, NULL, D3DLOCK_READONLY);

 

// ...and all the pixel writes I want to do to the texture, blah blah

someLoop

{

// blah blah blah

writePixel(rect, x, y, mypixel);

// ...with writePixel looking like:

void writePixel (D3DLOCKED_RECT rect, UINT x, UINT y, D3DCOLOR newpixel)
{

unsigned char *bits = (unsigned char *)rect.pBits;
unsigned int pixel = (unsigned int)&bits[rect.Pitch * y + 4 * x];
*(D3DCOLOR *)pixel = newpixel;

return;

}

}

 

// ...and then...

 

obj[i].texture->UnlockRect(0);

 

 

So, this works OK, making pixels and sticking them on the texture (it doesn't seem to be matching pixel-for-pixel with the real texture size, but I assume I'm just doing something stupid since I'm very new at C++ (in Visual Studio) and DirectX).

 

My questions are thus, however:

 

The sample code defines a struct containing the texture and the variables used to determine how the texture is oriented, to make its little swirly thing. But there's an array of 16 of these things. I presume this is because there's one instance per possible screen, and each has to be updated separately *within UpdateScene()*?

But that doesn't quite make sense to me; RenderSceneOnScreen() appears to be called with the ScreenID of the screen that should be updated. So it seems like the plugin works two different ways at once; in Update() I must do updates on *all possible screens*, and then DeskScapes calls RenderSceneOnScreen() only for the screens that are really being used?

This seems quite bizarre. Since I have no direct way of knowing if a given screen is in use in UpdateScene(), I have to do all my stuff over and over and over - or at least, in the case of the straight-up pixel writing that I'm doing, copy one result to each of 16 textures - for screens that aren't even being used. Without a terrible hack (eg, making RenderSceneOnScreen() set a flag saying, "OK, screen N is in use!" and reading it over in UpdateScene), I don't see how I can avoid updating 15 things that will almost never be seen. And it's confusing that one function is called and told which screen it's working on, and in the other I have to do my own code to handle it. It's strange enough that I assume I'm missing something obvious; is that the case?

 

2 The corollary to 1. Is there some document describing exactly what gets called when? I'm having strange things happening; I declare a static variable in UpdateScene() and it resets every call. If I declare it up where the obj array is declared - and it clearly persists - it... still resets every time UpdateScene() is run. Except sometimes it works, and I don't know why. Now, again, I presume that's because I'm an idiot and don't know what I'm doing, and it has nothing to do with the DeskScapes API, but I figured I'd ask just in case there's some kind of thing going on with how this stuff is called that I'm not aware of.

Not only that, if I make changes to the texture, they're reset each frame. But I'm writing straight to the texture itself, and it wouldn't show up if the texture wasn't being updated... which makes it seem like the texture is being initialized every frame. But that call only happens during SetupPlugin()! WHAT IS THIS I DON'T EVEN

 

3 Is there a set of guidelines ('best practices', *snort*) for the behavior of a dynamic dream? For instance, maximum CPU usage, access to local files or the network (assuming it's even possible from within the plugin; I don't know how that stuff works, having only done C on POSIX stuff and in DOS), maximum RAM usage, etc? Do dynamic dreams have a low enough priority that they won't hog the CPU when Photoshop wants all the cores to put a huge lens flare on a picture of your dog? What about during fullscreened games? Or do I need to use so little CPU that it won't too-negatively affect your average dude's computer no matter what he's doing?

 

OK, I think that's enough for now. In closing, I'd like to thank you guys for the awesome work you've been doing all along; I remember using WindowBlinds back in college, and that was a damn while ago now. Consider my glass raised to you.

Thanks in advance!

3,411 views 2 replies
Reply #1 Top

The total number of screens is passed into SetupPlugin as the screenCount parameter, so you can simply save this value and use it in UpdateScene later.

UpdateScene is called once per frame, RenderSceneOnScreen is called once per screen per frame.  If you have things you have to do every single frame that impact every single display then do it in UpdateScene.  If you have things you need to do that are per display per frame then feel free to do it in RenderSceneOnScreen.  Ultimately Deskscapes is calling UpdateScene followed by a for loop calling RenderSceneOnScreen.

Deskscapes has no impact on anything thats happening with your static variables.  It just calls the exports from the dll.

Deskscapes will automatically pause the dream when in a game and the dream gets to decide what the target frame rate is.  The lower the number, the less of an impact it has.  On XP this will not drop below a set number due to OS limitations, but on other OSes it will allow any number from 1 up.

One thing I do notice is you seem to be locking and passing D3DLOCK_READONLY.  This tells DirectX that you care about reading the buffer, but not about what you write to it.  I.e. it discards everything you do, or as Microsoft puts it "An application that specifies D3DLOCK_READONLY but then writes to the resource should expect undefined results"

You need to make your texture a dynamic one, using 32 bit ARGB or XARGB and then locking it with D3DLOCK_DISCARD.  This will allow optimal performance as it knows you have no plan to read back from the texture.  Reading back from DirectX resources is very costly as it may cause the code to wait for the GPU to finish what it was doing first.

Reply #2 Top

Awesome, thanks a ton for the response.

I noticed the D3DLOCK_READONLY thing a little while after I posted, and *cue 'things that make you go hmm* lo, that was the problem. It confused me because my initial tests (written with the help of a friend who knows directX stuff) worked; it turns out that somewhere along the way I'd copied the wrong bit of code and changed the lock to READONLY... oops.

I noticed it because of debugging the static vars - I learned how to write text on the screen (crazy, I know...) and saw that my variables were just fine. So the only thing left was that the vars were persistent but that they only changed the texture on the first frame. Then I noticed READONLY...

Unfortunately, you're right about performance. I was used to the rates that I was (apparently) getting using READONLY; turns out the other options are horrifyingly slow. I think I tried DISCARD but I'm not sure; I ended up just using the default - which, IIRC, is 'MANAGED'; it seemed to be faster than the other options. I'll try DISCARD again.

I'm really rather disappointed with the general performance of things - not due to deskscapes, just the overall speed of shoveling memory around and doing loops and writing to memory. It doesn't seem much more than three or four times as fast as SDL was on my Athlon 600 in 1998... it just seems like pixelpushing should be vastly faster. I don't know how it's possible that I can't do a 1080p screenfull of 'custom pixels' at more than 15hz or so, which is exactly what I'd need to, say, render an ever-changing fractal - and that's precisely the kind of thing that would be awesome to do with deskscapes! How the hell is it possible that I can't do that in 1920x1200 now, with such utterly massive CPU and memory bandwidth, much faster than I could with an AGP card on an Athlon 600 at 1280x1024? :( I feel like there must be something I'm doing horribly wrong, but I'm not sure what. Do I need to do DEFINT A-Z? ;)

(Not sure anyone will get that, but...)

Anyway, Neil, big thanks for the response, it helps a lot with my deciding how to go about this. Unfortunately it doesn't make things a ton *easier*, since even if I decide to do all my calcs per-frame and then send the same thing to every screen, adding another screen's worth of stuff is going to require me to sling that buffer to every screen every frame, which apparently will be quite costly... :(

My real problem *now* is that Deskscapes is going down in flames when I try to load my .dream, even though it works fine in Framework32 and 64. It seems to be an access violation, so I assumed it was due to my pixel writer, but I cut that out and still have the problem... as Marvin the Martian said after a neanderthal-ized Bugs Bunny squashed him into his helmet: "Oh well - back to the ol' electronic drawing board..."