Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2017-05

OpenGL and SDL frustrations

11 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Ryan Joseph

I’ve wasted so much time on this I just need to stop and ask for help already. Over the last few years I’ve been picking away at OpenGL and only ever got the legacy 2.x API to work which has been fine for making 2D games but I wanted to at least learn the modern API and shaders.

Here’s a snippet I cobbled together from a test program. It merely wants to draw a triangle. The actual OpenGL is from a tutorial and I don’t see how anything could be simpler than this. The only thing curious to me is why I can’t load the version of OpenGL I want from SDL. If I attempt to load 4.0 (with SDL_GL_SetAttribute) GL_VERSION returns null but if I load 3.3 it works and GL_VERSION returns 4.1 anyways (I’m a Mac from 2015).

I removed the error handling code here but I don’t get any errors, just a black screen. Despite the tutorial I was following not using a shader they still got a white triangle (I added a shader also but it still didn’t work so I removed it to reduce complexity). The only thing I can think of is they were using GLEW and it did some init that SDL isn’t doing but I doubt it. This is barebones simple OpenGL here.

Any ideas on what’s wrong with this? I don’t care about this example in particular I just want to draw ANYTHING using OpenGL 3.3 so I can move forward.

=====

type
	TVec2 = record
		x, y: GLfloat;
	end;
var
	verts: array[0..2] of TVec2;
	bufferID: GLuint;
	vao: GLuint;
// run sdl window
if SDL_Init(SDL_INIT_VIDEO) < 0 then
	Fatal('SDL could not initialize! '+SDL_GetError);
// load function pointers
if Load_GL_VERSION_3_3 = false then
	Fatal('OpenGL is not loaded');
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
// NOTE: 4.0 doesn't work, GL_VERSION return null
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
// create window
window := SDL_CreateWindow('SDL Tutorial', SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN + SDL_WINDOW_OPENGL);
context := SDL_GL_CreateContext(window);
SDL_GL_MakeCurrent(window, context);
SDL_GL_SetSwapInterval(1);
writeln('Vendor: ', glGetString(GL_VENDOR));
writeln('OpenGL Version: ', glGetString(GL_VERSION));
writeln('GLSL Version: ', glGetString(GL_SHADING_LANGUAGE_VERSION));
// NOTE: despite SDL_GL_SetAttribute asking for 3.3 and 4.0 failing GL_VERSION still returns 4.1
// Vendor: Intel Inc.
// OpenGL Version: 4.1 INTEL-10.25.13
// GLSL Version: 4.10
// setup
glViewPort(0, 0, width, height);
// simplest example possible
// https://www.youtube.com/watch?v=Dyue3MzJDss
verts[0].x := 0.0;
verts[0].y := 1.0;
verts[1].x := -1.0;
verts[1].y := -1.0;
verts[2].x := 1.0;
verts[2].y := -1.0;
// NOTE: glEnableVertexAttribArray returns an error if I don't bind a vao
glGenVertexArrays(1, @vao);
glBindVertexArray(vao);
// gen array buffer and bind to verts
glGenBuffers(1, @bufferID);
glBindBuffer(GL_ARRAY_BUFFER, bufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), @verts, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(TVec2), nil);
// draw loop
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
SDL_GL_SwapWindow(window);
...

Regards,
Ryan Joseph

Reply by email

Graeme Geldenhuys
to Ryan Joseph
Ryan Joseph wrote
Any ideas on what’s wrong with this?

I actually used the Java + OpenGL tutorials on YouTube, and translating those examples to Object Pascal + OpenGL + SDL2 was pretty easy.

This is my favourite one, and uses "modern OpenGL" only.

https://www.youtube.com/watch?v=VS8wlS9hF8E&list=PLRIWtICgwaX0u7Rf9zkZhLoLuZVfUksDP

"OpenGL 3D Game Tutorial" by ThinMatrix.

I also wanted something reusable, so I implemented classes in separate units that I can reuse between projects. Instead of 100's of loosely scattered OpenGL API calls. I was actually going to contribute all this work as part of my Lazarus Graphics Programming Contest entry, but I might just release it earlier than that.

Anyway, attached is one such unit setting up my display. I use proprietary NVIDIA drivers under FreeBSD, and I only target OpenGL 4.x with my code. It works perfectly here.

My program code is pretty much like this:

    TDisplayManager.CreateDisplay;
    while running do
    begin
      // do the "gaming loop" here
      TDisplayManager.UpdateDisplay;
    end;
    // clean-up code here
    TDisplayManager.CloseDisplay;

Regards,
Graeme

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/ My public PGP key: http://tinyurl.com/graeme-pgp

Reply by email

Ryan Joseph
to Graeme Geldenhuys
On May 24, 2017, at 7:18 PM, Graeme Geldenhuys wrote: > Any ideas on what’s wrong with this?

Ok, I got an answer from a person on YouTube and figured this out.

The problem was 1) that SDL is returning a different version then I asked for and I didn’t do proper error checking. glEnableVertexAttribArray was failing for example because with OpenGL 4.1 (or earlier) a VAO is required before using VBO’s and 2) again, since 4.x, a shader is required to even draw white triangle. The demos I saw must have been on some version of 3.x but I was on 4.1.

I’m still now sure how to guarantee SDL returns the version I want and it looks in your code you didn’t even try to specify anything besides core compatibility, not that it makes any difference because I always get 4.1 on my Mac or 2.1 and GLSL 1.2 for legacy mode. This begs the question of how I can write shaders if on any given computer I get a different version of GLSL.

At least I got it working FINALLY after so much hassle but everything I do could easily break on others computers so...

Regards,
Ryan Joseph

Reply by email

Anthony Walter
to Ryan Joseph

You need to tell SDL what OpenGL kind and version before you create a window. For example if you want OpenGLES 2.0 you would write:

SDL_Init(SDL_INIT_VIDEO);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
If you want normal OpenGL 4.0 you would write:
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);

Then you can create the SDL and load the appropriate OpenGL function prototypes using:

glClear := SDL_GL_GetProcAddress('glClear');
It's up to you to know which functions are part of which which OpenGL spec, and you should need to load the functions dynamically to stubs:

var glClear: procedure(mask: GLbitfield); cdecl;
Don't forget, if you want a specific values for stencil bits, pixel order, multisampling levels and other stuff, you need to set those values before you create a window. Check the return values of SDL_CreateWindow and SDL_GL_CreateContext to see if anything above fails, for example the target device doesn't support OpenGL 4.0.

SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 8); // 8x anti-aliasing,
must be called before SDL_CreateWindow
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 16); // 16 bit stencil buffer,
must be called before SDL_CreateWindow

Reply by email

Ryan Joseph
to Anthony Walter
Show quoted text 15 lines
On May 25, 2017, at 2:30 PM, Anthony Walter wrote: You need to tell SDL what OpenGL kind and version before you create a window. For example if you want OpenGLES 2.0 you would write: SDL_Init(SDL_INIT_VIDEO); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); If you want normal OpenGL 4.0 you would write: SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);

That’s just a hint to SDL but it doesn’t guarantee anything. See my example below where I asked for 3.3 but got 4.1. I learned I can use a lower version of GLSL so I can enforce that version but for OpenGL I’m stuck on 4.1 or 2.1, at least on my Mac. That wouldn’t be a problem I guess but I’m trying to follow tutorials which have subtle things not work but I’m not using the same version as them. Maybe it doesn’t matter though and 4.1 will run on older graphics cards? No idea but it’s worrying.

Regards,
Ryan Joseph

Reply by email

Anthony Walter
to Anthony Walter: You need to tell SDL what OpenGL kind and version before you create a window. For example…

Oh and another note, you cannot load your gl function such as (glClear in my previous reply, this time I use glGenTextures):

var glGenTextures: procedure(n: GLsizei; var textures: GLuint); cdecl;

Until you create and make current your OpenGL context. SDL_GL_MakeCurrent(window, context); // after this is done the first time you can then load the OpenGL functions matching your requested version

So the order is

SDL_Init()
SDL_GL_SetAttribute() multiple times
SDL_CreateWindow() returns your window
SDL_GL_CreateContext() returns your context
SDL_GL_MakeCurrent() makes gl functions available
SDL_GL_GetProcAddress() for every gl function in your requested version

Then you are done initializing everything and can write a game/demo/whatever thing you want.

Reply by email

Anthony Walter
to Ryan Joseph: That’s just a hint to SDL but it doesn’t guarantee anything. See my example below…

Ryan,

Are you loading the OpenGL API functions using SDL_GL_GetProcAddress? You really should be doing that or you're asking for problems.

Anyways, if you want maximum capability you should probably use ES version 2, as it's supported on the most devices. It requires you to drop the fixed function pipeline, that is dropping glBegin/glEnd and using GLSL vertex and fragment shaders. It's mostly like OpenGL 2.0, with a few differences, like there is no glMatrixMode.

And if you're not using GLSL shaders, then you don't need anything greater than Open 1.5. You can see the list of changes at the link below. With the exception of frame buffer objects (better known as render to texture) in version 3.0 and up, there's likely very little you're going to need in the 3.0+ realm of APIs you're ever going to need.

https://www.khronos.org/opengl/wiki/History_of_OpenGL#Summary_of_version_changes

Reply by email

Marco van de Voort
to Anthony Walter

In our previous episode, Anthony Walter said:

Show quoted text 7 lines
And if you're not using GLSL shaders, then you don't need anything greater than Open 1.5. You can see the list of changes at the link below. With the exception of frame buffer objects (better known as render to texture) in version 3.0 and up, there's likely very little you're going to need in the 3.0+ realm of APIs you're ever going to need. https://www.khronos.org/opengl/wiki/History_of_OpenGL#Summary_of_version_changes

PBO speeds up texture upload on most DX10+ cards.

Reply by email

Unknown author
to Ryan Joseph: I’ve wasted so much time on this I just need to stop and ask for help already. Over the…
Ryan Joseph wrote 5 lines
I’ve wasted so much time on this I just need to stop and ask for help already. Over the last few years I’ve been picking away at OpenGL and only ever got the legacy 2.x API to work which has been fine for making 2D games but I wanted to at least learn the modern API and shaders.

Not sure what ZenGL uses for opengl version but why do you struggle to use opengl directly instead of using a wrapper like zengl that has already made the functions available for you...

The only problem with using a wrapper like zengl or andorra is that of course it could go stale and not be updated, I'm not even sure if it uses 2.x, I have forgotten.

[...]

Show quoted text 15 lines
if SDL_Init(SDL_INIT_VIDEO) < 0 then Fatal('SDL could not initialize! '+SDL_GetError); // load function pointers if Load_GL_VERSION_3_3 = false then Fatal('OpenGL is not loaded'); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); // NOTE: 4.0 doesn't work, GL_VERSION return null SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);

All these calls look kind of tedious, instead of using a wrapper. But maybe you want to learn opengl at its heart and not use a wrapper.. and learn all the fine details the hard way (full respect for that).

Reply by email

Ryan Joseph
to Anthony Walter: Are you loading the OpenGL API functions using SDL_GL_GetProcAddress? You really should…
Show quoted text 8 lines
On May 25, 2017, at 7:02 PM, Anthony Walter wrote: Ryan, Are you loading the OpenGL API functions using SDL_GL_GetProcAddress? You really should be doing that or you're asking for problems. Anyways, if you want maximum capability you should probably use ES version 2, as it's supported on the most devices. It requires you to drop the fixed function pipeline, that is dropping glBegin/glEnd and using GLSL vertex and fragment shaders. It's mostly like OpenGL 2.0, with a few differences, like there is no glMatrixMode.

I loaded the functions using Load_GL_VERSION_3_3 (and similar) from the Free Pascal RTL and it seems to correctly load the functions.

Right now I’m using 2.1 and the fixed pipeline because I don’t really need shaders but I’m learning shaders and matrix transforms now so if there’s any performance benefit I can update my code base.

Regards,
Ryan Joseph

Reply by email

Ryan Joseph
to Unknown author: Not sure what ZenGL uses for opengl version but why do you struggle to use opengl…
On May 26, 2017, at 11:56 AM, wrote: All these calls look kind of tedious, instead of using a wrapper. But maybe you want to learn opengl at its heart and not use a wrapper.. and learn all the fine details the hard way (full respect for that).

Imo I think it pays off to learn the actual graphics pipeline and what the process is really doing from direct memory in CPU to GPU. Graphics are so sensitive to performance and minor optimizations it would no doubt bother me deep down inside if I didn’t have 100% control over the process. Overall it’s only a minor part of the code actually so once you get it down it can be buried and not worried about later.

Regards,
Ryan Joseph

Reply by email