Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial Implementation of Shader Programs #73

Merged
merged 1 commit into from
Feb 2, 2017

Conversation

Quaker762
Copy link
Member

Can load, compile and link shaders from files. Currently untested (as we
don't have a GLContext working as of yet!)

@z33ky I'm going to add more to this over the next few days. We should probably start doing some GL stuff to test drawing/some other systems (like textures). Dis you want to try out fast-forwaring instead of merging this time?

@Quaker762 Quaker762 requested a review from z33ky January 27, 2017 13:43
@Quaker762
Copy link
Member Author

Also see #74

@Quaker762
Copy link
Member Author

Quaker762 commented Jan 29, 2017

Okay I've fixed a weird segfault. This should be good to go. glShaderSource is a bizarre function...

EDIT: It isn't, I just realised my file IO on about line 93 of glprogram.cpp is REALLY bad. I'll fix it ASAP.

@Quaker762 Quaker762 force-pushed the shaderloader branch 2 times, most recently from 5a376ca to 4518d34 Compare January 29, 2017 13:57
Copy link
Collaborator

@z33ky z33ky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the glDelete* stuff should just be in the destructor of the class (even in the error case). This way resources will always be released when the sh3_glprogram is destroyed, be it because it couldn't be loaded or when it simply isn't needed anymore.

std::string fname; // Name of the file we want to open
std::vector<GLchar> errorLog; // Error log

if(type == GL_VERTEX_SHADER)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's plenty of code duplication in these branches.
For each shader type, only fname seems to be the difference.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I'm getting on fixing this ASAP.

die(&errorLog[0]);
}

source.close();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for that, RAII will do that.


errorLog.resize(logLength);
glGetProgramInfoLog(programID, logLength, &logLength, &errorLog[0]);
glDeleteProgram(vertShader);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be glDeleteShader I think.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops haha

@@ -51,21 +53,24 @@ GLint sh3_glprogram::Load(const std::string& name)

void sh3_glprogram::Bind()
{

if(programID != 0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if(programID == 0)
{
    //warn
    return;
}

?

}

void sh3_glprogram::Unbind()
{

glUseProgram(0); // The 'correct' way to unbind a shader, but apparently undefined?!?!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a huge issue with this, but as a fix we could use a dummy shader (and have a static class variable refer to it) that is set on Unbind().
The dummy shader would either just render a solid color or an error message if we want to be fancy.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that sounds like a good idea. Maybe even a checkered square like the Source engine haha.

@@ -75,11 +80,17 @@ GLuint sh3_glprogram::Compile(std::uint32_t type)

source.open(fname);

if(!source.is_open())
die("sh3_glprogram::Compile( ): Unable to open a handle to %s!", fname.c_str());

while(!source.eof())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could require the shader sources to have UNIX-style line endings ('\n'), in which case we can open the file in binary mode and use a std::ostringstream and read the whole file via stringstream << source.rdbuf();.
Reading the file like this is safer though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh I see. I'm using Windows, so I think the problem is stemming from the stupid \r\n at the end of each line.

Why is this method safer?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Safer as in, doesn't lead to errors when using different line endings.
You should be able to switch to different line endings in your editor.

@Quaker762
Copy link
Member Author

Regarding glDelete*() calls, the OpenGL spec seems to recommend that glDeleteShader be called if compile or link fails. I've added glDeleteShader() and glDeleteProgram() calls to the destructor nonetheless.

@@ -39,7 +41,7 @@ GLint sh3_glprogram::Load(const std::string& name)

errorLog.resize(logLength);
glGetProgramInfoLog(programID, logLength, &logLength, &errorLog[0]);
glDeleteProgram(vertShader);
glDeleteShader(vertShader);
glDeleteShader(fragShader);

die(&errorLog[0]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the string contains something looking like a format specifier, things will go wrong. Use die("%s", ...) instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completely missed that, it's fixed now.

@z33ky
Copy link
Collaborator

z33ky commented Jan 30, 2017

The glDestroy* functions will still be called when the destructor is run. Would this be insufficient?
Also, now it will be called twice when a shader fails to compile, once in Load() and once in sh3_glprogram.

@Quaker762
Copy link
Member Author

Quaker762 commented Jan 31, 2017

The glDestroy* functions will still be called when the destructor is run. Would this be insufficient?

If anything, they should be destroyed right after the link is performed, as they are no longer needed and are just a waste of memory (as I have read, but it seems everyone has their own opinion on this stuff haha), though with the amount most people have in their system, this is probably a non-issue (though if we preload stuff it may be).

Also, now it will be called twice when a shader fails to compile, once in Load() and once in sh3_glprogram

Will the constructor still be run if a call to die() is made??? I thought that was only the case if they're static/global objects.
Also, now that I think about it, should we actually die if it fails to compile, or just replace the shader with a default one as you've suggested somewhere in the comment chain?

@z33ky
Copy link
Collaborator

z33ky commented Jan 31, 2017

I though that die() was just a sort of "error-handling to be implemented later" in most cases.
Like stuff not being found in an arc doesn't seem to be a truly fatal error in many cases. At worst it should just abort loading the current scene, not the whole program.

@Quaker762
Copy link
Member Author

Quaker762 commented Jan 31, 2017

I though that die() was just a sort of "error-handling to be implemented later" in most cases.

True, we should probably just keep them to aid with debugging shaders at this point.

Like stuff not being found in an arc doesn't seem to be a truly fatal error in many cases

Wouldn't that imply the file is corrupt or damaged in some way though?

Also, do you want me to move the glDeleteShader() calls to straight after the program has been linked, and leave just glDeleteProgram() in the destructor?

@z33ky
Copy link
Collaborator

z33ky commented Feb 2, 2017

Wouldn't that imply the file is corrupt or damaged in some way though?

That or driver issues probably.
I think we should make a best effort. If something goes wrong we should definitely log, but just fallback to the dummy shader. It probably won't make for a good playing experience, but if multiple shader fail for instance, then you get all errors in one run, instead of a cycle of run, die, fix shader until all are fixed.

@z33ky
Copy link
Collaborator

z33ky commented Feb 2, 2017

Also, do you want me to move the glDeleteShader() calls to straight after the program has been linked, and leave just glDeleteProgram() in the destructor?

Yeah, that seems good. Although now glDeleteShader() is missing for the successful case.
The spec is okay with deleting the shader while still attached; It will then be deleted when the shader is detached. So we should just always do that after the shader was attached.
The program will also automatically detach the shaders, so we don't need to do that manually.

@Quaker762
Copy link
Member Author

I think we should make a best effort. If something goes wrong we should definitely log, but just fallback to the dummy shader. It probably won't make for a good playing experience, but if multiple shader fail for instance, then you get all errors in one run, instead of a cycle of run, die, fix shader until all are fixed.

Good point, I'll get rid of all of the calls to die() and replace them with Log() with the ERROR status.

Yeah, that seems good. Although now glDeleteShader() is missing for the successful case.

Bloody hell, more of my 1AM programming... I think I should make myself a coffee before I attempt to program (that or crack open a beer). I've fixed it now.

The spec is okay with deleting the shader while still attached

I had no clue this was the case. Everything I read 'recommended' a detach before delete. Very interesting. I've removed all calls to detach.

@@ -93,7 +95,7 @@ GLuint sh3_glprogram::Compile(GLenum type)
source.open(fname);

if(!source.is_open())
die("sh3_glprogram::Compile( ): Unable to open a handle to %s!", fname.c_str());
Log(LogLevel::ERROR, "sh3_glprogram::Compile( ): Unable to open a handle to %s!", fname.c_str());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can just return at this point.
//TODO: default shader fallback.

@z33ky
Copy link
Collaborator

z33ky commented Feb 2, 2017

You can also squash the commits. I don't see a good reason to keep them separate.

{
id = glCreateShader(GL_FRAGMENT_SHADER); // Generate a shader ID
fname = "data/shaders/" + programName + ".frag";
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else
    die()

#include <fstream>
#include <vector>

#define BAD_SHADER 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a static const GLuint IMO.

Can load, compile and link shaders from files. Currently untested (as we
don't have a GLContext working as of yet!)
@z33ky z33ky merged commit f6a8464 into Palm-Studios:master Feb 2, 2017
@Quaker762 Quaker762 deleted the shaderloader branch February 3, 2017 03:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants