Julia Set (shader)
-
DDRM
- Posts: 33
- Joined: Mon 17 Jun 2024, 08:02
Re: Julia Set (shader)
Using static variables doesn't prevent it crashing.... 
-
Richard Russell
- Posts: 591
- Joined: Tue 18 Jun 2024, 09:32
Re: Julia Set (shader)
Try it in BBCSDL, as that's a platform you should be able to run on the same machine. Another platform you can readily try is in a browser, since that's just a case of selecting the 'Deploy as a web application' checkbox.
You probably have a good excuse for not testing it on other platforms, but BB4W, BBCSDL and in-browser should be the minimum you try whenever you make modifications (I would include at least one 64-bit platform too, which you could achieve by installing 64-bit BBCSDL).
And indeed I can confirm that the program you listed does not work here, I see a white ellipse but nothing else happens, wherever the mouse is moved. Why would you remove code that does no harm and in fact turns out to be essential?
-
Richard Russell
- Posts: 591
- Joined: Tue 18 Jun 2024, 09:32
Re: Julia Set (shader)
I think you must be doing something wrong, because there's no way the shader should be able to tell the difference between a structure and a pair of static variables, all it gets passed is a memory address (pointer) after all.
List the non-working code if you want me to try to diagnose the fault.
-
Richard Russell
- Posts: 591
- Joined: Tue 18 Jun 2024, 09:32
Re: Julia Set (shader)
I tried the following changes to mandel.bbc here (BBCSDL):Richard Russell wrote: ↑Mon 26 Jan 2026, 17:30 there's no way the shader should be able to tell the difference between a structure and a pair of static variables
Changed all Float.0% to U%
Changed all Float.1% to V%
Changed all Float{} to ^U%
It worked perfectly.
-
Richard Russell
- Posts: 591
- Joined: Tue 18 Jun 2024, 09:32
Re: Julia Set (shader)
To make it work here, I had to make two changes:Richard Russell wrote: ↑Mon 26 Jan 2026, 17:27 And indeed I can confirm that the program you listed does not work here, I see a white ellipse but nothing else happens
- Restore the , @memhdc% to four SYS statements.
- Remove the PRINT statement which was trying to output to the same window as the shader.
Code: Select all
MODE 9
REM MODE 9 is 640 x 512 pixels, or 1280 x 1024 graphics units
xres%=1280
yres%=1024
INSTALL @lib$ + "shaderlib"
DIM Vertex$(10), Fragment$(20),Float{0%,1%}
PROC_readshader(Vertex$())
PROC_readshader(Fragment$())
PROC_shaderinit(oVertex%, oFragment%)
PROC_compileshader(oVertex%, Vertex$(), "Vertex")
PROC_compileshader(oFragment%, Fragment$(), "Fragment")
oProgram% = FN_useshaders(oVertex%, oFragment%)
REM Here we store the locations of our shader variables ("uniforms")
REM in BBC BASIC variables (pReal and pImag)
SYS `glGetUniformLocation`, oProgram%, "cr", @memhdc% TO pReal%%
SYS `glGetUniformLocation`, oProgram%, "ci", @memhdc% TO pImag%%
REPEAT
REM We get the mouse coordinates, and check it's in the window area
REM (That way we know the calculated start point will lie within (-2 to 2,-1.25 to 1.25) )
REM Though I think the shader actually only shows the area (-1.5 to 1.5, -1 to 1)?
MOUSE px%,py%,pz%
IF px%>0 AND px%<xres% AND py%>0 AND py%<yres% THEN
REM Scale the mouse X coordinate into the required space. Not sure why it needs to go into a structure...
Float.0% = FN_f4(4*px%/xres% - 3)
SYS `glUniform1fv`, pReal%%, 1, Float{}, @memhdc%
REM Ditto for Y coordinate
Float.0% = FN_f4(2.5*py%/yres% - 1.25)
SYS `glUniform1fv`, pImag%%, 1, Float{}, @memhdc%
SYS "SDL_SetWindowTitle", @hwnd%, STR$(4*px%/1280 - 2) + \
\ CHR$9 + CHR$9 + STR$(4*py%/1024 - 1.25), @memhdc%
ENDIF
PROC_render
WAIT 2
UNTIL FALSE
END
REM Vertex shader:
DATA "attribute vec4 vPosition;"
DATA "void main()"
DATA "{"
DATA "gl_Position = vPosition;"
DATA "}"
DATA ""
REM Fragment shader:
REM We'll define two parameters, representing
REM the real and imaginary parts of the start location
DATA "uniform float cr;"
DATA "uniform float ci;"
DATA "void main()"
DATA "{"
DATA "float v;"
DATA "float zr = gl_FragCoord.x * 3.0 / 639.0 - 1.5;"
DATA "float zi = gl_FragCoord.y * 2.0 / 511.0 - 1.0;"
DATA "for( int i = 0; i <= 510; i++ )"
DATA " {"
DATA " v = float(i) / 512.0;"
DATA " float zn = (zr + zi) * (zr - zi) + cr;"
DATA " zi = 2.0 * zr * zi + ci; zr = zn;"
DATA " if ((zr * zr + zi * zi) > 3.0) break;"
DATA " }"
DATA "gl_FragColor = vec4(sqrt(v), v, v*v, 1.0 );"
DATA "}"
DATA ""
-
DDRM
- Posts: 33
- Joined: Mon 17 Jun 2024, 08:02
Re: Julia Set (shader)
Ah, it's the Float{} - I can try with a pointer (which I think is what the ^ does?). Yes, that works OK.
Your new version works nicely in BBC-SDL - I can confirm that my version doesn't here either, but does with the changes you made. Your version fails in BB4W until I disable the SDL command to write to the title bar, of course, but works then.
I find it surprising and a bit alarming that the SDL version appears to require an additional undocumented parameter for the OpenGL commands - could BB4W and BBC-SDL be using different versions of OpenGL? What is that parameter doing, and why do you think it is needed? Is it to do with SDL's processing of the command before passing it to OpenGL? Do other SDL graphics commands need to be given the device context?
Best wishes,
D
Your new version works nicely in BBC-SDL - I can confirm that my version doesn't here either, but does with the changes you made. Your version fails in BB4W until I disable the SDL command to write to the title bar, of course, but works then.
I find it surprising and a bit alarming that the SDL version appears to require an additional undocumented parameter for the OpenGL commands - could BB4W and BBC-SDL be using different versions of OpenGL? What is that parameter doing, and why do you think it is needed? Is it to do with SDL's processing of the command before passing it to OpenGL? Do other SDL graphics commands need to be given the device context?
Best wishes,
D
-
Richard Russell
- Posts: 591
- Joined: Tue 18 Jun 2024, 09:32
Re: Julia Set (shader)
It doesn't, you're misinterpreting it. In this context @memhdc% is not a parameter (undocumented or otherwise), it's a flag which tells BBC BASIC to invoke the special handling required when calling an API function in the context of the GUI.
This has come up before, but it was probably a long time ago because it affects both BB4W and BBCSDL. It's all to do with the fact that on a modern platform such as Windows or MacOS the interpreter runs concurrently with the GUI. If special measures are not taken, this concurrency can result in instability or worse.
So the presence of @memhdc% in the parameter list, which is generally a reliable indication that the GUI is being accessed, invokes this special handling. Where things get a little complicated is when you are bypassing the regular GUI (GDI32 in BB4W, SDL2 in BBCSDL), for example because you are using OpenGL or DirectX, when the special handling is likely still required but @memhdc% isn't a needed parameter.
In those (rare) cases you have to add @memhdc% as an additional parameter, which will be ignored by the API function but still act as a flag. This means you should have kept the @memhdc% in the BB4W version as well, since you are accessing the GUI, but seemingly you got away with not doing so (although I would expect stability to suffer).
The key takeaway from this is that modern computers and modern Operating Systems are complicated and if you see something in an example program that you don't understand leave well alone (or at the very least ask for advice before simply removing it) because the chances are that it is there for a reason and it's much safer to leave it in than to remove it.
-
Richard Russell
- Posts: 591
- Joined: Tue 18 Jun 2024, 09:32
Re: Julia Set (shader)
It may perhaps be helpful to add some historical context. When BB4W was first released, in 2001, the thought of bypassing the standard Windows GUI (GDI32) to write to the screen more directly wasn't considered. I probably didn't know what DirectX and Direct3D were, and I certainly had no idea that they might be callable from BBC BASIC - or indeed why one might want to.Richard Russell wrote: ↑Mon 26 Jan 2026, 22:55 So the presence of @memhdc% in the parameter list, which is generally a reliable indication that the GUI is being accessed, invokes this special handling.
So in those simpler times, detecting when a SYS statement was going to be calling a function in the Windows GUI, requiring special handling to deal with the concurrency issue, was simple - if the parameters included @memhdc% it was and if they didn't it wasn't. This worked even when calling GDIplus, not just GDI32. So using @memhdc% as a flag was a no-brainer.
Much later, when BBCSDL was developed, this 'trick' worked equally well because once again most SDL2 functions that require special handling would necessarily take @memhdc% as a parameter (now referring to a Renderer rather than a Device Context).
But with the increasing use of 3D renderers or other technologies for accessing the display directly rather than via the GDI32 or SDL2 GUI (e.g. shaders) the need to add @memhdc% as a flag rather than as a true parameter has increased.
-
DDRM
- Posts: 33
- Joined: Mon 17 Jun 2024, 08:02
Re: Julia Set (shader)
Hi Richard,
Oh, so the additional parameter is a requirement of (your) BBC BASICs? That would explain why it isn't in the OpenGL documentation!
With regard to your advice not to mess with stuff you don't understand, fair enough! However, as a computer science student I'm strongly encouraged NOT to use code I don't understand, so I tend to go read the (friendly) manual, which I know is also a piece of advice you favour, until I DO understand it, and then try to implement it in the cleanest possible way (which means not passing random stuff it doesn't need, among other things). Since the documentation made no mention of the need for the extra parameter, and it ran fine without it, I couldn't see much point in including it.
As an aside, you could argue that using Float{} is a black mark for me in that context, but (a) I tested it and it WAS necessary (b) I asked about it so I COULD understand it, and (c) I'm an idiot and should have worked out that Float{} was a pointer to the actual data, but I didn't.
Returning to the question of @memhdc%, I wonder if the reason I get away with it in BB4W (using the standard IDE) is your oft-noted fact that they run in the same thread?
It would definitely be helpful to have this use of @memhdc% noted somewhere in the manual - I've searched, and I don't think any of the current occurrences mention this use (or use it, as far as I can see). I found a couple of cases on the wiki where it is apparently used (for example, in the context of sound handling), but it doesn't explain why it is there. There's actually no page for the ShaderLib in either the embedded on online manual, so maybe it could go there?
Best wishes,
D
Oh, so the additional parameter is a requirement of (your) BBC BASICs? That would explain why it isn't in the OpenGL documentation!
With regard to your advice not to mess with stuff you don't understand, fair enough! However, as a computer science student I'm strongly encouraged NOT to use code I don't understand, so I tend to go read the (friendly) manual, which I know is also a piece of advice you favour, until I DO understand it, and then try to implement it in the cleanest possible way (which means not passing random stuff it doesn't need, among other things). Since the documentation made no mention of the need for the extra parameter, and it ran fine without it, I couldn't see much point in including it.
As an aside, you could argue that using Float{} is a black mark for me in that context, but (a) I tested it and it WAS necessary (b) I asked about it so I COULD understand it, and (c) I'm an idiot and should have worked out that Float{} was a pointer to the actual data, but I didn't.
Returning to the question of @memhdc%, I wonder if the reason I get away with it in BB4W (using the standard IDE) is your oft-noted fact that they run in the same thread?
It would definitely be helpful to have this use of @memhdc% noted somewhere in the manual - I've searched, and I don't think any of the current occurrences mention this use (or use it, as far as I can see). I found a couple of cases on the wiki where it is apparently used (for example, in the context of sound handling), but it doesn't explain why it is there. There's actually no page for the ShaderLib in either the embedded on online manual, so maybe it could go there?
Best wishes,
D
-
Richard Russell
- Posts: 591
- Joined: Tue 18 Jun 2024, 09:32
Re: Julia Set (shader)
Absence of evidence is not evidence of absence!
Firstly, the documentation making no mention of it is not the same thing as the documentation saying it is unnecessary! Secondly, that it "ran fine without it" on one specific platform (in your case 32-bit Windows) does not mean that it will run without it on any other platform.
I agree in principle about 'following the documentation' but all one could say in the BBC BASIC documentation is that the extra parameter might be required, not when it is required. The latter is determined by the function you are calling using SYS, and you won't find anywhere in the SDL 2.0 documentation whether a specific API must be called from a specific thread or not.
The same is sadly true of Windows. Whether or not a specific Win32 API function must be called from a specific thread, or can be called from any thread, is simply not documented. In practice the only way to find out seems to be to try it! You will find some overarching recommendation that all display-related calls be made from the 'GUI thread' but doing so unnecessarily will hit performance.
So the bottom line is that, yes, you should of course strive to understand the code you are writing and to follow the documentation, but when that documentation says nothing about the particular feature you are interested in what are you to do? And if you are coding for a cross-platform language testing it on every single platform is likely to be impractical.
Given that you used the Float{} structure, which holds two numbers, I'm surprised that you didn't send both cr and ci together to the shader (as a two-component vector) rather than using two scalar calls.As an aside, you could argue that using Float{} is a black mark for me in that context, but (a) I tested it and it WAS necessary (b) I asked about it so I COULD understand it, and (c) I'm an idiot and should have worked out that Float{} was a pointer to the actual data, but I didn't.
The IDE doesn't come into it; the requirement for the @memhdc% 'flag' is the same even if your program runs standalone without the IDE. The key thing is that the Windows GUI itself is running in a different thread from the BBC BASIC interpreter, hence without special handling they could attempt concurrent access to shared resources such as a Device Context.Returning to the question of @memhdc%, I wonder if the reason I get away with it in BB4W (using the standard IDE) is your oft-noted fact that they run in the same thread?
The manual does use it. An additional @memhdc% parameter, used as a flag rather than being accepted by the called API function itself, is present in several of the sections of the manual under Accessing the SDL 2.0 API. Indeed the variety of different calls needing it (not just display related but also sound, for example) shows how difficult it can be to predict when it will be needed.I don't think any of the current occurrences mention this use (or use it, as far as I can see)
It's not at all specific to shaderlib. I think the only place it could sensibly go would be in the documentation of the SYS statement. That is, after all, where the code to activate the 'special handling' resides.There's actually no page for the ShaderLib in either the embedded on online manual, so maybe it could go there?