Enabling OpenGL extensions (Linux, instanced_arrays)

Hmm...not having default access to OpenGL >=3.3 (...circa 2010!) is unfortunate/significant limitation of the open-source amdgpu driver then. I've been developing code to use more native-3D drawing commands that use instanced drawing to render 'dots' as proper geodesic spheres in xyz-space.

I ordered modern AMD cards for an experimental rig, knowing that the AMD drivers are so highly spoken of on the forum, and thinking they'd at least have access to the limited set of newer drawing commands from the Nvidia GTX 760 that I used to do proof-of-concept stimulus development. (see code snippet below)

Native OpenGL 3d rendering is sort-of-possible to do on OSX (which is hard-limited to OpenGL 2.1) but I could only get our stoutest Mac Pros to render ~100 spheres at a time without dropping frames (only mercator glutSolidSpheres at that). With instanced drawing on a Linux machine, I can easily render thousands of geodesic spheres binocularly(!) without dropping any frames. 

----
What would be the best --and fastest-- way to enable use of GL functions for instanced drawing in 3D (glVertexAttribDivisor, glDrawArraysInstanced)?

Is this even possible on AMD hardware?  (Radeon Pro WX7100)

I've fought the AMDGPU-PRO driver (ver. 17.40 & 17.50) on Ubuntu 16.04 for the last few days. It at least implements modern opengl 4.x compatibility, but xorg configuration of multiple monitors/screens seems totally broken (...is the "ZaphodHeads"  option officially obsoleted now?). Is there an alternative method for achieving two independent xorg screens using the PRO driver? (e.g. Screen('Screens') == [0, 1] )

...I've hacked & tweaked xorg.conf settings and prodded /var/log/Xorg* logs, but the only progress made there was that BusID (== "PCI:1:0:0" or "PCI:1:0:1") needs to be defined in the Device section for the system to even boot up using config files from XOrgConfCreator, but the result still just comes up as a single-monitor spanning screen.

The catch with the Nvidia GTX card used for initial coding was that when I moved it to a production rig with a ProPixx/Datapixx display, it began missing 15-100% of flip times in irregular bouts with no rational connection to rendering demand. ...also unusable, but being able to execute the code & allow displays to be independently addressed seems at least closer than one-or-the-other situation from AMD.

---
Are the proprietary Nvidia drivers just that much more capable than whats currently available for AMD that I'd be better off blindly sampling Nvidia proprietary driver versions/builds until things work?

From what I can tell, the AMDGPU-PRO drivers seem to be in total disarray right now. They're enacting some abrupt sea change from the old 'Catalyst' drivers --that at least seemed mostly reliable & had a ui for basic settings-- to a completely rewritten driver that seems only marginally functional & is missing lots of core features.
(...not unlike the iWork rewrite a few years back that turned a perfectly good suite of software into MS Office grade garbage).

That said, I'd rather spend my days figuring out how the brain works, than how a linux driver stack works. So if there's a way to piece-wise enable certain OpenGL extensions (like ARB_instanced_arrays) and get off the ground using the open-source AMD drivers, I'm all for it. ...whatever works!

Any guidance on breaking through this wall would be fantastic!

Thanks,
Thad Czuba

---
Previously:
"Matlab's  opengl info  is still only reporting version 3.0 with the open-source amdgpu driver & Radeon Pro WX 7100 though. This seems like its probably a separate issue, so I'll dig a little more to confirm & document, then post a new topic here shortly.

-> That's expected. Both PTB and (i assume) jogl want an OpenGL context that is backwards compatible with OpenGL 2.1, so you get the highest OpenGL core version that is backwards compatible. With the Mesa drivers that maximum is 3.0 or 3.1 iirc. This doesn't really matter, as e.g., PTB still uses > OpenGL 3.1 features as needed via the OpenGL extension mechanism. If an app doesn't require backwards compat with GL-2, it gets whatever the maximum supported by hardware + drivers is, ie. up to OpenGL 4.6 atm. PTB only needs OpenGL 2.1 + a few extensions for full functionality. I assume Matlab's plotting doesn't need any more advanced stuff either.

-mario"

---

Instanced drawing snippet:

%% inputs are xyz positions, dotsz, etc... global structure glB for buffer info storage

...code snippet...   %


 %% Draw as 3D geodesic spheres (soo nice, but needs Linux atm.)


    % Dot size gets tacked onto xyz buffer data

    xyz(4,:) = dotsz(:);


    % Initialize buffers (only once!)

    if ~isfield(glB,'glsl')

        % Load the speedy shader

        shaderpath = {fullfile(glslshader, 'geosphere.vert'), fullfile(glslshader, 'geosphere.frag')};

        glB.glsl = LoadGLSLProgramFromFiles(shaderpath,1);


        [vv,ff] = glDraw.icosphere(dotType-3);

        % convert vv into direct triangles (...would be better if indexed vectors, but whatever)

        ff = ff';

        vv = 0.5*vv(ff(:),:)'; % expand indexing & convert to unit diameter (size == [3, ntriangles]);

        glB.ntris = size(vv,2);

        

        % vertex buffer

        % jnk = whos('vv'); glB.vert.mem=jnk.bytes; % gets memory size of var

        glB.vert.mem = numel(vv)*4; % will become GL.FLOAT, 4 bytes/el.  

        glB.vert.h = glGenBuffers(1);

        glB.vert.i = 0; % attribute index   (must correspond to init order inside shader)

        glBindBuffer(GL.ARRAY_BUFFER, glB.vert.h);

        glBufferData(GL.ARRAY_BUFFER, glB.vert.mem, single(vv(:)), GL.STATIC_DRAW);

        

        % position buffer: [x, y, z, size]

        % Data will stream to this buffer for each frame

        %jnk = whos('xyz'); glB.pos.mem = jnk.bytes;  % gets memory size of var

        glB.pos.mem = numel(xyz)*4;  % 4 bytes/el.  

        glB.pos.h = glGenBuffers(1);

        glB.pos.i = 1; % attribute index

        glBindBuffer(GL.ARRAY_BUFFER, glB.pos.h);

        glBufferData(GL.ARRAY_BUFFER, glB.pos.mem, single(xyz(:)), GL.STREAM_DRAW);

        

        % color buffer: [r, g, b, a]

        % Data will stream to this buffer for each frame

        % jnk = whos('col'); glB.col.mem = jnk.bytes;   % gets memory size of var

        glB.col.mem = numel(dotcolor)*4;  % 4 bytes/el.  

        glB.col.h = glGenBuffers(1);

        glB.col.i = 2; % attribute index

        glBindBuffer(GL.ARRAY_BUFFER, glB.col.h);

        glBufferData(GL.ARRAY_BUFFER, glB.col.mem, single(dotcolor(:)), GL.STREAM_DRAW);

        

    else

        % Update position buffer (via "orphaning")

        glBindBuffer(GL.ARRAY_BUFFER, glB.pos.h);

        glBufferData(GL.ARRAY_BUFFER, glB.pos.mem, 0, GL.STREAM_DRAW);

        glBufferSubData(GL.ARRAY_BUFFER, 0, glB.pos.mem, single(xyz(:)));

        

        % Update color buffer

        glBindBuffer(GL.ARRAY_BUFFER, glB.col.h);

        glBufferData(GL.ARRAY_BUFFER, glB.col.mem, 0, GL.STREAM_DRAW);

        glBufferSubData(GL.ARRAY_BUFFER, 0, glB.col.mem, single(dotcolor(:)));

        

    end


    % Backup old shader binding:

    oldShader = glGetIntegerv(GL.CURRENT_PROGRAM);

    % Set new one:

    glUseProgram(glB.glsl);


    % vertex buffer

    glEnableVertexAttribArray(glB.vert.i);  %(GL attribute index starts at zero)

    glBindBuffer(GL.ARRAY_BUFFER, glB.vert.h);

    glVertexAttribPointer(glB.vert.i, 3, GL.FLOAT, GL.FALSE, 0, 0);

    % pos & size buffer

    glEnableVertexAttribArray(glB.pos.i);

    glBindBuffer(GL.ARRAY_BUFFER, glB.pos.h);

    glVertexAttribPointer(glB.pos.i, 4, GL.FLOAT, GL.FALSE, 0, 0);

    % color buffer

    glEnableVertexAttribArray(glB.col.i);

    glBindBuffer(GL.ARRAY_BUFFER, glB.col.h);

    glVertexAttribPointer(glB.col.i, 4, GL.FLOAT, GL.TRUE, 0, 0);


    % Assign buffer usage   (!!specific to glDrawArrays*Instanced*!!)

    % // The first parameter is the attribute buffer #

    % // The second parameter is the "rate at which generic vertex attributes advance when rendering multiple instances"

    glVertexAttribDivisor(0, 0); % particles vertices : always reuse the same n vertices -> 0

    glVertexAttribDivisor(1, 1); % positions : one per element (its center) -> 1

    glVertexAttribDivisor(2, 1); % color : one per element -> 1

    

    % % % % % %

    % DRAW IT!!

    % % % % % %

    glDrawArraysInstanced(GL.TRIANGLES, 0, glB.ntris, ndots);

    

    % disable dot attribute buffers & clean up

    glDisableVertexAttribArray(0);

    glDisableVertexAttribArray(1);

    glDisableVertexAttribArray(2);

    

    % Reset old shader binding:

    glUseProgram(oldShader);



A-B tested my way to a workaround by iteratively testing -ARB & -EXT suffixes for calls to modern gl functions, and using debuglevel 3 when calling InitializeMatlabOpenGL so that mogl returns useful error info for problems that occur between Screen('BeginOpenGL',...) & Screen('EndOpenGL',...).

Adding ARB suffixes to glVertexAttribDivisor, glDrawArraysInstanced, & glDisableVertexAttribArray calls did the trick.  ...its possible these changes broke what was sort-of working on the nvidia hardware...I haven't tested and hopefully don't have to if the AMD hardware & opensource drivers play nicely with the rest of the rig.

My usage of newer OpenGL functions is still totally rudimentary --and probably already outdated itself-- but proper access to OpenGL 4.x functionality (as in the proprietary drivers) would still be valuable in opening up a vastly more powerful way of rendering stimuli. The overall return on speed & functionality available with new methods is really compelling...enough to make the jump to PTB Linux machines make sense for me.

As I understand it, with OpenGL versions >=3.3 there was a fundamental shift away from using a handful of 'magic' matrix transformation functions & stacks to take care of rendering a 3D scene into the 2D display. Modern implementations pretty much leave it all up to the user to understand the linear algebra behind those functions and take care of it all themselves. While it does make for a much steeper learning curve, it also demystifies much of the under-the-hood aspects of OpenGL & allows more direct/principled experimental control of those transformations. 

-Thad.


---
Fixed code snippet: 

    % Assign buffer usage   (!!specific to glDrawArrays*Instanced*!!)
    % // The first parameter is the attribute buffer #
    % // The second parameter is the "rate at which generic vertex attributes advance when rendering multiple instances"
    glVertexAttribDivisorARB(0, 0); % particles vertices : always reuse the same n vertices -> 0
    glVertexAttribDivisorARB(1, 1); % positions : one per element (its center) -> 1
    glVertexAttribDivisorARB(2, 1); % color : one per element -> 1
    
    % % % % % %
    % DRAW IT!!
    % % % % % %
    glDrawArraysInstancedARB(GL.TRIANGLES, 0, glB.ntris, ndots);
    
    % disable dot attribute buffers & clean up
    glDisableVertexAttribArrayARB(0);
    glDisableVertexAttribArrayARB(1);
    glDisableVertexAttribArrayARB(2);
    
    % Reset old shader binding:
    glUseProgram(oldShader);

---


---In psychtoolbox@yahoogroups.com, <tbc.class@...> wrote :

Hmm...not having default access to OpenGL >=3.3 (...circa 2010!) is unfortunate/significant limitation of the open-source amdgpu driver then. I've been developing code to use more native-3D drawing commands that use instanced drawing to render 'dots' as proper geodesic spheres in xyz-space.

I ordered modern AMD cards for an experimental rig, knowing that the AMD drivers are so highly spoken of on the forum, and thinking they'd at least have access to the limited set of newer drawing commands from the Nvidia GTX 760 that I used to do proof-of-concept stimulus development. (see code snippet below)

Native OpenGL 3d rendering is sort-of-possible to do on OSX (which is hard-limited to OpenGL 2.1) but I could only get our stoutest Mac Pros to render ~100 spheres at a time without dropping frames (only mercator glutSolidSpheres at that). With instanced drawing on a Linux machine, I can easily render thousands of geodesic spheres binocularly(!) without dropping any frames. 

----
What would be the best --and fastest-- way to enable use of GL functions for instanced drawing in 3D (glVertexAttribDivisor, glDrawArraysInstanced)?

Is this even possible on AMD hardware?  (Radeon Pro WX7100)

I've fought the AMDGPU-PRO driver (ver. 17.40 & 17.50) on Ubuntu 16.04 for the last few days. It at least implements modern opengl 4.x compatibility, but xorg configuration of multiple monitors/screens seems totally broken (...is the "ZaphodHeads"  option officially obsoleted now?). Is there an alternative method for achieving two independent xorg screens using the PRO driver? (e.g. Screen('Screens') == [0, 1] )

...I've hacked & tweaked xorg.conf settings and prodded /var/log/Xorg* logs, but the only progress made there was that BusID (== "PCI:1:0:0" or "PCI:1:0:1") needs to be defined in the Device section for the system to even boot up using config files from XOrgConfCreator, but the result still just comes up as a single-monitor spanning screen.

The catch with the Nvidia GTX card used for initial coding was that when I moved it to a production rig with a ProPixx/Datapixx display, it began missing 15-100% of flip times in irregular bouts with no rational connection to rendering demand. ...also unusable, but being able to execute the code & allow displays to be independently addressed seems at least closer than one-or-the-other situation from AMD.

---
Are the proprietary Nvidia drivers just that much more capable than whats currently available for AMD that I'd be better off blindly sampling Nvidia proprietary driver versions/builds until things work?

From what I can tell, the AMDGPU-PRO drivers seem to be in total disarray right now. They're enacting some abrupt sea change from the old 'Catalyst' drivers --that at least seemed mostly reliable & had a ui for basic settings-- to a completely rewritten driver that seems only marginally functional & is missing lots of core features.
(...not unlike the iWork rewrite a few years back that turned a perfectly good suite of software into MS Office grade garbage).

That said, I'd rather spend my days figuring out how the brain works, than how a linux driver stack works. So if there's a way to piece-wise enable certain OpenGL extensions (like ARB_instanced_arrays) and get off the ground using the open-source AMD drivers, I'm all for it. ...whatever works!

Any guidance on breaking through this wall would be fantastic!

Thanks,
Thad Czuba

---
Previously:
"Matlab's  opengl info  is still only reporting version 3.0 with the open-source amdgpu driver & Radeon Pro WX 7100 though. This seems like its probably a separate issue, so I'll dig a little more to confirm & document, then post a new topic here shortly.

-> That's expected. Both PTB and (i assume) jogl want an OpenGL context that is backwards compatible with OpenGL 2.1, so you get the highest OpenGL core version that is backwards compatible. With the Mesa drivers that maximum is 3.0 or 3.1 iirc. This doesn't really matter, as e.g., PTB still uses > OpenGL 3.1 features as needed via the OpenGL extension mechanism. If an app doesn't require backwards compat with GL-2, it gets whatever the maximum supported by hardware + drivers is, ie. up to OpenGL 4.6 atm. PTB only needs OpenGL 2.1 + a few extensions for full functionality. I assume Matlab's plotting doesn't need any more advanced stuff either.

-mario"

---

Instanced drawing snippet:

%% inputs are xyz positions, dotsz, etc... global structure glB for buffer info storage

...code snippet...   %


 %% Draw as 3D geodesic spheres (soo nice, but needs Linux atm.)


    % Dot size gets tacked onto xyz buffer data

    xyz(4,:) = dotsz(:);


    % Initialize buffers (only once!)

    if ~isfield(glB,'glsl')

        % Load the speedy shader

        shaderpath = {fullfile(glslshader, 'geosphere.vert'), fullfile(glslshader, 'geosphere.frag')};

        glB.glsl = LoadGLSLProgramFromFiles(shaderpath,1);


        [vv,ff] = glDraw.icosphere(dotType-3);

        % convert vv into direct triangles (...would be better if indexed vectors, but whatever)

        ff = ff';

        vv = 0.5*vv(ff(:),:)'; % expand indexing & convert to unit diameter (size == [3, ntriangles]);

        glB.ntris = size(vv,2);

        

        % vertex buffer

        % jnk = whos('vv'); glB.vert.mem=jnk.bytes; % gets memory size of var

        glB.vert.mem = numel(vv)*4; % will become GL.FLOAT, 4 bytes/el.  

        glB.vert.h = glGenBuffers(1);

        glB.vert.i = 0; % attribute index   (must correspond to init order inside shader)

        glBindBuffer(GL.ARRAY_BUFFER, glB.vert.h);

        glBufferData(GL.ARRAY_BUFFER, glB.vert.mem, single(vv(:)), GL.STATIC_DRAW);

        

        % position buffer: [x, y, z, size]

        % Data will stream to this buffer for each frame

        %jnk = whos('xyz'); glB.pos.mem = jnk.bytes;  % gets memory size of var

        glB.pos.mem = numel(xyz)*4;  % 4 bytes/el.  

        glB.pos.h = glGenBuffers(1);

        glB.pos.i = 1; % attribute index

        glBindBuffer(GL.ARRAY_BUFFER, glB.pos.h);

        glBufferData(GL.ARRAY_BUFFER, glB.pos.mem, single(xyz(:)), GL.STREAM_DRAW);

        

        % color buffer: [r, g, b, a]

        % Data will stream to this buffer for each frame

        % jnk = whos('col'); glB.col.mem = jnk.bytes;   % gets memory size of var

        glB.col.mem = numel(dotcolor)*4;  % 4 bytes/el.  

        glB.col.h = glGenBuffers(1);

        glB.col.i = 2; % attribute index

        glBindBuffer(GL.ARRAY_BUFFER, glB.col.h);

        glBufferData(GL.ARRAY_BUFFER, glB.col.mem, single(dotcolor(:)), GL.STREAM_DRAW);

        

    else

        % Update position buffer (via "orphaning")

        glBindBuffer(GL.ARRAY_BUFFER, glB.pos.h);

        glBufferData(GL.ARRAY_BUFFER, glB.pos.mem, 0, GL.STREAM_DRAW);

        glBufferSubData(GL.ARRAY_BUFFER, 0, glB.pos.mem, single(xyz(:)));

        

        % Update color buffer

        glBindBuffer(GL.ARRAY_BUFFER, glB.col.h);

        glBufferData(GL.ARRAY_BUFFER, glB.col.mem, 0, GL.STREAM_DRAW);

        glBufferSubData(GL.ARRAY_BUFFER, 0, glB.col.mem, single(dotcolor(:)));

        

    end


    % Backup old shader binding:

    oldShader = glGetIntegerv(GL.CURRENT_PROGRAM);

    % Set new one:

    glUseProgram(glB.glsl);


    % vertex buffer

    glEnableVertexAttribArray(glB.vert.i);  %(GL attribute index starts at zero)

    glBindBuffer(GL.ARRAY_BUFFER, glB.vert.h);

    glVertexAttribPointer(glB.vert.i, 3, GL.FLOAT, GL.FALSE, 0, 0);

    % pos & size buffer

    glEnableVertexAttribArray(glB.pos.i);

    glBindBuffer(GL.ARRAY_BUFFER, glB.pos.h);

    glVertexAttribPointer(glB.pos.i, 4, GL.FLOAT, GL.FALSE, 0, 0);

    % color buffer

    glEnableVertexAttribArray(glB.col.i);

    glBindBuffer(GL.ARRAY_BUFFER, glB.col.h);

    glVertexAttribPointer(glB.col.i, 4, GL.FLOAT, GL.TRUE, 0, 0);


    % Assign buffer usage   (!!specific to glDrawArrays*Instanced*!!)

    % // The first parameter is the attribute buffer #

    % // The second parameter is the "rate at which generic vertex attributes advance when rendering multiple instances"

    glVertexAttribDivisor(0, 0); % particles vertices : always reuse the same n vertices -> 0

    glVertexAttribDivisor(1, 1); % positions : one per element (its center) -> 1

    glVertexAttribDivisor(2, 1); % color : one per element -> 1

    

    % % % % % %

    % DRAW IT!!

    % % % % % %

    glDrawArraysInstanced(GL.TRIANGLES, 0, glB.ntris, ndots);

    

    % disable dot attribute buffers & clean up

    glDisableVertexAttribArray(0);

    glDisableVertexAttribArray(1);

    glDisableVertexAttribArray(2);

    

    % Reset old shader binding:

    glUseProgram(oldShader);



XXXIn PSYCHTOOLBOX@yahoogroups.com, <tbc.class@...> wrote :

A-B tested my way to a workaround by iteratively testing -ARB & -EXT suffixes for calls to modern gl functions, and using debuglevel 3 when calling InitializeMatlabOpenGL so that mogl returns useful error info for problems that occur between Screen('BeginOpenGL',...) & Screen('EndOpenGL',...).

Adding ARB suffixes to glVertexAttribDivisor, glDrawArraysInstanced, & glDisableVertexAttribArray calls did the trick.  ...its possible these changes broke what was sort-of working on the nvidia hardware...I haven't tested and hopefully don't have to if the AMD hardware & opensource drivers play nicely with the rest of the rig.

-> You should be fine, as that's how you use OpenGL 3.1+ core functionality from OpenGL < 3.1. You pretty much use the same functions, just with an ARB suffix slapped onto them. Syntax and behavior is otherwise (almost always) identical to core. The way making a new OpenGL core version works is by looking which of the new ARB extensions have proven useful, popular and high-quality and then declaring that set as a new spec update, just stripping the ARB suffix from the name and making it part of the default feature set of the new OpenGL version.

If you want to use any of that functionality, you either check if the OpenGL core version is >= the one where functionality was introduced, or you check the glGetString(GL_EXTENSIONS) extension string for presence of specific extensions. Once you've confirmed the extension, e.g., ARB_instanced_draw is present, you can use the glFoooARB() functions safely.

Of curse you can also just use the stuff and trust the mogl error handling to abort if you tried to use something unsupported.

It would be surprising - and likely a driver bug - if the ARB suffixed functions wouldn't work on you proprietary drivers, as they usually expose the core and ARB variants of the functions, which do the same thing, just accessed under different names.



My usage of newer OpenGL functions is still totally rudimentary --and probably already outdated itself-- but proper access to OpenGL 4.x functionality (as in the proprietary drivers) would still be valuable in opening up a vastly more powerful way of rendering stimuli. The overall return on speed & functionality available with new methods is really compelling...enough to make the jump to PTB Linux machines make sense for me.

-> It is proper access via the extension mechanism. I've added some experimental support for the next beta that allows requesting a core profile context for user-defined rendering between Begin/EndOpenGL under Linux only for now. Such core contexts don't provide any of the backward compatible OpenGL 1/2 functionality though, forcing you to be disciplined about choosing the old or new style, no mixing. Also almost completely untested and therefore possibly buggy or broken, as we don't have any code that tests core context rendering, and i don't have time for that atm. Using the extension mechanism is a safer way to write portable code. Also core contexts don't really provide you with much that is vastly more powerful, as much of this stuff can already be done by proper use of extensions.

-> Not everything OpenGL 3/4.x can be easily supported in Matlab/Octave, extensions or otherwise, as some of this stuff would be difficult or work intense/time consuming to expose to the Matlab programming language via mogl, because it makes advanced use of memory pointers to other memory pointers, ie. double- or maybe even triple-indirections, so would need tedious manual implementation of interfaces instead of our automatic interface code generation. Writing compiled mex files to access it in C code is of course possible...

-> But of the many reasons to switch to Linux, the ability to use OpenGL core contexts is one that never came to my mind as especially compelling, although Linux OpenGL implementations do provide more functionality and generally higher performance than macOS.

As I understand it, with OpenGL versions >=3.3 there was a fundamental shift away from using a handful of 'magic' matrix transformation functions & stacks to take care of rendering a 3D scene into the 2D display. Modern implementations pretty much leave it all up to the user to understand the linear algebra behind those functions and take care of it all themselves. While it does make for a much steeper learning curve, it also demystifies much of the under-the-hood aspects of OpenGL & allows more direct/principled experimental control of those transformations. 

-> There's nothing magic about it. Even the standard introductory programming books from the 90's (RedBook) define the math that is performed when you use those functions. You also had the ability to use shaders and extensions and define everything yourself since at least OpenGL 1.5. You are right in that the new OpenGL core 3.1+ spec does away with much of the stuff that is no longer considered the most efficient or flexible approach to rendering on modern hardware. And most of the fixed function pipeline, almost all now requires shaders. If you only use core profiles it kind of forces you to choose a more efficient approach by taking away all the convenient but possibly lower performance high level stuff. With the introduction of completely optional backwards compatibility profiles that was back-pedaled a bit mostly to not scare away mediocre or lazy programmers (or companies that don't want to or can't invest into rewriting their software) with this harsh new reality. But compatibility profiles bring their own problems when people mix old and new approaches without a deep understanding of the tradeoffs and pitfalls and totally new types of bugs. That was one of the reasons the Mesa OSS driver developers mostly resisted compatibility support and spent their limited resources on other things. AMD may introduce backwards compat, maybe because they want to get rid of their proprietary OpenGL driver. Just today Marek posted patches to enable OpenGL 3.1 with ARB_compatibility support at least on AMD hardware.

-mario


-Thad.


---
Fixed code snippet: 

    % Assign buffer usage   (!!specific to glDrawArrays*Instanced*!!)
    % // The first parameter is the attribute buffer #
    % // The second parameter is the "rate at which generic vertex attributes advance when rendering multiple instances"
    glVertexAttribDivisorARB(0, 0); % particles vertices : always reuse the same n vertices -> 0
    glVertexAttribDivisorARB(1, 1); % positions : one per element (its center) -> 1
    glVertexAttribDivisorARB(2, 1); % color : one per element -> 1
    
    % % % % % %
    % DRAW IT!!
    % % % % % %
    glDrawArraysInstancedARB(GL.TRIANGLES, 0, glB.ntris, ndots);
    
    % disable dot attribute buffers & clean up
    glDisableVertexAttribArrayARB(0);
    glDisableVertexAttribArrayARB(1);
    glDisableVertexAttribArrayARB(2);
    
    % Reset old shader binding:
    glUseProgram(oldShader);

---


---In psychtoolbox@yahoogroups.com, <tbc.class@...> wrote :

Hmm...not having default access to OpenGL >=3.3 (...circa 2010!) is unfortunate/significant limitation of the open-source amdgpu driver then. I've been developing code to use more native-3D drawing commands that use instanced drawing to render 'dots' as proper geodesic spheres in xyz-space.

I ordered modern AMD cards for an experimental rig, knowing that the AMD drivers are so highly spoken of on the forum, and thinking they'd at least have access to the limited set of newer drawing commands from the Nvidia GTX 760 that I used to do proof-of-concept stimulus development. (see code snippet below)

Native OpenGL 3d rendering is sort-of-possible to do on OSX (which is hard-limited to OpenGL 2.1) but I could only get our stoutest Mac Pros to render ~100 spheres at a time without dropping frames (only mercator glutSolidSpheres at that). With instanced drawing on a Linux machine, I can easily render thousands of geodesic spheres binocularly(!) without dropping any frames. 

----
What would be the best --and fastest-- way to enable use of GL functions for instanced drawing in 3D (glVertexAttribDivisor, glDrawArraysInstanced)?

Is this even possible on AMD hardware?  (Radeon Pro WX7100)

I've fought the AMDGPU-PRO driver (ver. 17.40 & 17.50) on Ubuntu 16.04 for the last few days. It at least implements modern opengl 4.x compatibility, but xorg configuration of multiple monitors/screens seems totally broken (...is the "ZaphodHeads"  option officially obsoleted now?). Is there an alternative method for achieving two independent xorg screens using the PRO driver? (e.g. Screen('Screens') == [0, 1] )

...I've hacked & tweaked xorg.conf settings and prodded /var/log/Xorg* logs, but the only progress made there was that BusID (== "PCI:1:0:0" or "PCI:1:0:1") needs to be defined in the Device section for the system to even boot up using config files from XOrgConfCreator, but the result still just comes up as a single-monitor spanning screen.

The catch with the Nvidia GTX card used for initial coding was that when I moved it to a production rig with a ProPixx/Datapixx display, it began missing 15-100% of flip times in irregular bouts with no rational connection to rendering demand. ...also unusable, but being able to execute the code & allow displays to be independently addressed seems at least closer than one-or-the-other situation from AMD.

---
Are the proprietary Nvidia drivers just that much more capable than whats currently available for AMD that I'd be better off blindly sampling Nvidia proprietary driver versions/builds until things work?

From what I can tell, the AMDGPU-PRO drivers seem to be in total disarray right now. They're enacting some abrupt sea change from the old 'Catalyst' drivers --that at least seemed mostly reliable & had a ui for basic settings-- to a completely rewritten driver that seems only marginally functional & is missing lots of core features.
(...not unlike the iWork rewrite a few years back that turned a perfectly good suite of software into MS Office grade garbage).

That said, I'd rather spend my days figuring out how the brain works, than how a linux driver stack works. So if there's a way to piece-wise enable certain OpenGL extensions (like ARB_instanced_arrays) and get off the ground using the open-source AMD drivers, I'm all for it. ...whatever works!

Any guidance on breaking through this wall would be fantastic!

Thanks,
Thad Czuba

---
Previously:
"Matlab's  opengl info  is still only reporting version 3.0 with the open-source amdgpu driver & Radeon Pro WX 7100 though. This seems like its probably a separate issue, so I'll dig a little more to confirm & document, then post a new topic here shortly.

-> That's expected. Both PTB and (i assume) jogl want an OpenGL context that is backwards compatible with OpenGL 2.1, so you get the highest OpenGL core version that is backwards compatible. With the Mesa drivers that maximum is 3.0 or 3.1 iirc. This doesn't really matter, as e.g., PTB still uses > OpenGL 3.1 features as needed via the OpenGL extension mechanism. If an app doesn't require backwards compat with GL-2, it gets whatever the maximum supported by hardware + drivers is, ie. up to OpenGL 4.6 atm. PTB only needs OpenGL 2.1 + a few extensions for full functionality. I assume Matlab's plotting doesn't need any more advanced stuff either.

-mario"

---

Instanced drawing snippet:

%% inputs are xyz positions, dotsz, etc... global structure glB for buffer info storage

...code snippet...   %


 %% Draw as 3D geodesic spheres (soo nice, but needs Linux atm.)


    % Dot size gets tacked onto xyz buffer data

    xyz(4,:) = dotsz(:);


    % Initialize buffers (only once!)

    if ~isfield(glB,'glsl')

        % Load the speedy shader

        shaderpath = {fullfile(glslshader, 'geosphere.vert'), fullfile(glslshader, 'geosphere.frag')};

        glB.glsl = LoadGLSLProgramFromFiles(shaderpath,1);


        [vv,ff] = glDraw.icosphere(dotType-3);

        % convert vv into direct triangles (...would be better if indexed vectors, but whatever)

        ff = ff';

        vv = 0.5*vv(ff(:),:)'; % expand indexing & convert to unit diameter (size == [3, ntriangles]);

        glB.ntris = size(vv,2);

        

        % vertex buffer

        % jnk = whos('vv'); glB.vert.mem=jnk.bytes; % gets memory size of var

        glB.vert.mem = numel(vv)*4; % will become GL.FLOAT, 4 bytes/el.  

        glB.vert.h = glGenBuffers(1);

        glB.vert.i = 0; % attribute index   (must correspond to init order inside shader)

        glBindBuffer(GL.ARRAY_BUFFER, glB.vert.h);

        glBufferData(GL.ARRAY_BUFFER, glB.vert.mem, single(vv(:)), GL.STATIC_DRAW);

        

        % position buffer: [x, y, z, size]

        % Data will stream to this buffer for each frame

        %jnk = whos('xyz'); glB.pos.mem = jnk.bytes;  % gets memory size of var

        glB.pos.mem = numel(xyz)*4;  % 4 bytes/el.  

        glB.pos.h = glGenBuffers(1);

        glB.pos.i = 1; % attribute index

        glBindBuffer(GL.ARRAY_BUFFER, glB.pos.h);

        glBufferData(GL.ARRAY_BUFFER, glB.pos.mem, single(xyz(:)), GL.STREAM_DRAW);

        

        % color buffer: [r, g, b, a]

        % Data will stream to this buffer for each frame

        % jnk = whos('col'); glB.col.mem = jnk.bytes;   % gets memory size of var

        glB.col.mem = numel(dotcolor)*4;  % 4 bytes/el.  

        glB.col.h = glGenBuffers(1);

        glB.col.i = 2; % attribute index

        glBindBuffer(GL.ARRAY_BUFFER, glB.col.h);

        glBufferData(GL.ARRAY_BUFFER, glB.col.mem, single(dotcolor(:)), GL.STREAM_DRAW);

        

    else

        % Update position buffer (via "orphaning")

        glBindBuffer(GL.ARRAY_BUFFER, glB.pos.h);

        glBufferData(GL.ARRAY_BUFFER, glB.pos.mem, 0, GL.STREAM_DRAW);

        glBufferSubData(GL.ARRAY_BUFFER, 0, glB.pos.mem, single(xyz(:)));

        

        % Update color buffer

        glBindBuffer(GL.ARRAY_BUFFER, glB.col.h);

        glBufferData(GL.ARRAY_BUFFER, glB.col.mem, 0, GL.STREAM_DRAW);

        glBufferSubData(GL.ARRAY_BUFFER, 0, glB.col.mem, single(dotcolor(:)));

        

    end


    % Backup old shader binding:

    oldShader = glGetIntegerv(GL.CURRENT_PROGRAM);

    % Set new one:

    glUseProgram(glB.glsl);


    % vertex buffer

    glEnableVertexAttribArray(glB.vert.i);  %(GL attribute index starts at zero)

    glBindBuffer(GL.ARRAY_BUFFER, glB.vert.h);

    glVertexAttribPointer(glB.vert.i, 3, GL.FLOAT, GL.FALSE, 0, 0);

    % pos & size buffer

    glEnableVertexAttribArray(glB.pos.i);

    glBindBuffer(GL.ARRAY_BUFFER, glB.pos.h);

    glVertexAttribPointer(glB.pos.i, 4, GL.FLOAT, GL.FALSE, 0, 0);

    % color buffer

    glEnableVertexAttribArray(glB.col.i);

    glBindBuffer(GL.ARRAY_BUFFER, glB.col.h);

    glVertexAttribPointer(glB.col.i, 4, GL.FLOAT, GL.TRUE, 0, 0);


    % Assign buffer usage   (!!specific to glDrawArrays*Instanced*!!)

    % // The first parameter is the attribute buffer #

    % // The second parameter is the "rate at which generic vertex attributes advance when rendering multiple instances"

    glVertexAttribDivisor(0, 0); % particles vertices : always reuse the same n vertices -> 0

    glVertexAttribDivisor(1, 1); % positions : one per element (its center) -> 1

    glVertexAttribDivisor(2, 1); % color : one per element -> 1

    

    % % % % % %

    % DRAW IT!!

    % % % % % %

    glDrawArraysInstanced(GL.TRIANGLES, 0, glB.ntris, ndots);

    

    % disable dot attribute buffers & clean up

    glDisableVertexAttribArray(0);

    glDisableVertexAttribArray(1);

    glDisableVertexAttribArray(2);

    

    % Reset old shader binding:

    glUseProgram(oldShader);