Poor Performance with Point Light rendering in a Deferred Rendering pipeline?

I am rendering the scene in a deferred rendering pipeline with the G-buffer pass using 32 bit floating point accuracy and the lighting pass using 16 bit floating point accuracy RGBA rendertargets.

Because Dark Photon said it would be more efficient (ALL HAIL DARK PHOTON), I am rendering an entire screenquad for every point light in the scene.

I seem to dip below 60 FPS after 20-25 point lights at 1080p. I was told that I would get hundreds of point lights, so I am quite disappointed.

at 1/4 of the number of pixels (1/4 of the resolution) my code runs a lot faster, allowing me nearly 60 point lights without dipping below 60 FPS

C++ Rendering Function:

void GkScene::drawPipeline(){ //Approaches spaghetti levels of unreadability
	//Used for error checking
	GLenum communism;
	
	/* Error Check code. Paste where you need it.
	
	// communism = glGetError(); //Ensure there are no errors listed before we start.
	// if (communism != GL_NO_ERROR) //if communism has made an error (which is pretty typical)
	// {
		// std::cout<<"
 OpenGL reports an ERROR!";
		// if (communism == GL_INVALID_ENUM)
			// std::cout<<"
 Invalid enum.";
		// if (communism == GL_INVALID_OPERATION)
			// std::cout<<"
 Invalid operation.";
		// if (communism == GL_INVALID_FRAMEBUFFER_OPERATION)
			// std::cout <<"
 Invalid Framebuffer Operation.";
		// if (communism == GL_OUT_OF_MEMORY)
		// {
			// std::cout <<"
 Out of memory. You've really done it now. I'm so angry, i'm going to close the program. ARE YOU HAPPY NOW, DAVE?!?!";
			// std::abort();
		// }
	// }
	*/
	
	
	
	/*
	
	FUNCTION STRUCTURE:
	* Initial Opaque Pass
		* SkyboxShader pass
		* InitialOpaquePassShader pass
	* SHADOWED LIGHT DEPTH PASSES
	* LIGHT PASSES
		* SHADOWLESS LIGHTING PASSES
			* Point Light Passes
		* SHADOWED LIGHTING PASSES
	* FINAL OPAQUE PASS
	* TRANSPARENCY
	* TOSCREEN/TOTARGET
	*/
	
	
	if (!SceneCamera || !InitialOpaqueShader || !ShowTextureShader || !InitialOpaqueUniforms || !FinalOpaqueShader){ //if one is not good
		return; //gtfo
	}
	
	
	
	
	
	
	//Setup Camera mat4s so that we can send in the addresses.
	InitialOpaqueCameraMatrix = SceneCamera->GetViewProjection();
	InitialOpaqueCameraViewMatrix = SceneCamera->GetViewMatrix();
	InitialOpaqueCameraProjectionMatrix = SceneCamera->GetProjection();
	
	
	//In case we need it...
	InverseViewProjectionMatrix = glm::inverse(InitialOpaqueCameraMatrix); //Inverse of the Viewprojection Matrix.
	InverseProjectionMatrix = glm::inverse(InitialOpaqueCameraProjectionMatrix);//Matrix that undoes perspective transformation
	InverseViewMatrix = glm::inverse(InitialOpaqueCameraViewMatrix); 
	
	
	
	
	
	
	/*
	=========================
	BEGIN INITIAL OPAQUE PASS
	=========================
	*/
	FboArray[OPAQUE_INITIAL]->BindRenderTarget(); //Bind this FBO as the Render Target. We render the skybox here too...
	FBO::clearTexture(0.0,0.0,0.2,0.0);//Clears the Opaque Initial target. The screen isn't cleared for a long time.
	
//Skybox code culled to conserve space on OpenGL Forums

	
	/*
		INITIAL OPAQUE PASS- NON SKYBOX
	*/
	InitialOpaqueShader->Bind(); //Bind the shader!
	
	
	//Runs whenever the window is resized or a shader is reassigned, so that we only need to get uniform locations once. It's not optimized fully yet...
	if(HasntRunYet){
		// screensize.x = width;
		// screensize.y = height;

		HasntRunYet = false;
		InitialOpaqueUniforms[INITOPAQUE_DIFFUSE] = InitialOpaqueShader->GetUniformLocation("diffuse"); //Literal texture unit
		InitialOpaqueUniforms[INITOPAQUE_WORLD2CAMERA] = InitialOpaqueShader->GetUniformLocation("World2Camera"); //World --> NDC
		InitialOpaqueUniforms[INITOPAQUE_MODEL2WORLD] = InitialOpaqueShader->GetUniformLocation("Model2World"); //Model --> World
		InitialOpaqueUniforms[INITOPAQUE_AMBIENT] = InitialOpaqueShader->GetUniformLocation("ambient"); //Ambient component of the material
		InitialOpaqueUniforms[INITOPAQUE_SPECREFLECTIVITY] = InitialOpaqueShader->GetUniformLocation("specreflectivity"); //Specular reflectivity
		InitialOpaqueUniforms[INITOPAQUE_SPECDAMP] = InitialOpaqueShader->GetUniformLocation("specdamp"); //Specular dampening
		InitialOpaqueUniforms[INITOPAQUE_EMISSIVITY] = InitialOpaqueShader->GetUniformLocation("emissivity"); //emissivity... currently unused
		InitialOpaqueUniforms[INITOPAQUE_DIFFUSIVITY] = InitialOpaqueShader->GetUniformLocation("diffusivity"); //Diffusivity... currently unused
		InitialOpaqueUniforms[INITOPAQUE_RENDERFLAGS] = InitialOpaqueShader->GetUniformLocation("renderflags");
		InitialOpaqueUniforms[INITOPAQUE_WORLDAROUNDME] = InitialOpaqueShader->GetUniformLocation("worldaroundme");
		InitialOpaqueUniforms[INITOPAQUE_ENABLE_CUBEMAP_REFLECTIONS] = InitialOpaqueShader->GetUniformLocation("enableCubeMapReflections");
		InitialOpaqueUniforms[INITOPAQUE_CAMERAPOS] = InitialOpaqueShader->GetUniformLocation("CameraPos");
		InitialOpaqueUniforms[INITOPAQUE_JANEAR] = InitialOpaqueShader->GetUniformLocation("janear");
		InitialOpaqueUniforms[INITOPAQUE_JAFAR] = InitialOpaqueShader->GetUniformLocation("jafar");
		InitialOpaqueShader->setUniform1f("windowsize_x", (width
		* Initial_Opaque_Pass_Approximation_Factor
		));
		InitialOpaqueShader->setUniform1f("windowsize_y", (height
		* Initial_Opaque_Pass_Approximation_Factor
		));
	}
	glUniform3f(InitialOpaqueUniforms[INITOPAQUE_CAMERAPOS], SceneCamera->pos.x, SceneCamera->pos.y, SceneCamera->pos.z);
	glUniform1f(InitialOpaqueUniforms[INITOPAQUE_JAFAR], SceneCamera->jafar); //Needed for depth.
	glUniform1f(InitialOpaqueUniforms[INITOPAQUE_JANEAR], SceneCamera->janear); //Needed for depth.
	glUniform1f(InitialOpaqueUniforms[INITOPAQUE_ENABLE_CUBEMAP_REFLECTIONS], 1.0f);
	
	
	
	Texture::SetActiveUnit(0);
	//InitialOpaqueShader->setUniform1i("diffuse", 0);//Texture unit 0 is reserved for the textures of objects.
	glUniform1i(InitialOpaqueUniforms[INITOPAQUE_DIFFUSE],0);
	
	if(SkyBoxCubemap)
	{
		Texture::SetActiveUnit(1);
		SkyBoxCubemap->Bind(1); //Bind to 1
	}
		
	//Do this regardless of the presence of Skyboxcubemap
	glUniform1i(InitialOpaqueUniforms[INITOPAQUE_WORLDAROUNDME], 1);//Cubemap unit 1 is reserved for the cubemap representing the world around the object, for reflections.
	
	
	glUniformMatrix4fv(InitialOpaqueUniforms[INITOPAQUE_WORLD2CAMERA], 1, GL_FALSE, &InitialOpaqueCameraMatrix[0][0]);

	
	/*
	
	Actually Render the objects to the screen
	
	*/
	
	
	
	//Now that we have the shader stuff set up, let's get to rendering!
	glEnableVertexAttribArray(0); //Position
	glEnableVertexAttribArray(1); //Texture
	glEnableVertexAttribArray(2); //Normal
	glEnableVertexAttribArray(3); //Color
		if (Meshes.size() > 0) //if there are any
			for (size_t i = 0; i < Meshes.size(); i++) //for all of them
				if (Meshes[i]) //don't call methods on nullptrs
				{
					unsigned int flagerinos = Meshes[i]->getFlags(); //Set flags
					glUniform1ui(InitialOpaqueUniforms[INITOPAQUE_RENDERFLAGS], flagerinos); //Set flags on GPU
					Meshes[i]->DrawInstancesPhong(
						InitialOpaqueUniforms[INITOPAQUE_MODEL2WORLD], 		//Model->World transformation matrix
						InitialOpaqueUniforms[INITOPAQUE_AMBIENT], 		//Ambient material component
						InitialOpaqueUniforms[INITOPAQUE_SPECREFLECTIVITY], 	//Specular reflective material component
						InitialOpaqueUniforms[INITOPAQUE_SPECDAMP], 		//Specular dampening material component
						InitialOpaqueUniforms[INITOPAQUE_DIFFUSIVITY],   //Diffusivity. Reaction to diffuse light.
						InitialOpaqueUniforms[INITOPAQUE_EMISSIVITY], 		//Emissivity material component
						InitialOpaqueUniforms[INITOPAQUE_ENABLE_CUBEMAP_REFLECTIONS],
						false		//Yes, we're using textures.
					);
				}
				
		
	//glDisableVertexAttribArray(0); //Position. We use this for the screenquadding, so we shouldn't disable it.
	glDisableVertexAttribArray(1); //Texture
	glDisableVertexAttribArray(2); //Normal
	glDisableVertexAttribArray(3); //Color

	
	//Note to self: Insert shadowed light depth passes here.
	
	
	
	
	
	/*
	===============================
	* SHADOWLESS LIGHTING PASSES  *
	===============================
	*/
	
	//Setup for lights
	glEnable(GL_BLEND);
	glBlendFunc(GL_ONE, GL_ONE);
	glDisable(GL_DEPTH_TEST); //Disable depth testing, we don't need it.
	FboArray[LIGHT_ACCUMULATOR]->BindRenderTarget();
	FBO::clearTexture(0.0,0.0,0.0,0.0);
	
	/*
	
	Point Lights
	
	*/
	if (SimplePointLights.size() > 0)
	{
		//Prep
		PointLightShader->Bind();
		if (!haveInitializedPointlightUniforms){
			PointlightUniforms[POINTLIGHT_WORLD2CAMERA] = PointLightShader->GetUniformLocation("World2Camera");
			PointlightUniforms[POINTLIGHT_TEX1] = PointLightShader->GetUniformLocation("tex1");
			PointlightUniforms[POINTLIGHT_TEX2] = PointLightShader->GetUniformLocation("tex2");
			PointlightUniforms[POINTLIGHT_TEX3] = PointLightShader->GetUniformLocation("tex3");
			PointlightUniforms[POINTLIGHT_TEX4] = PointLightShader->GetUniformLocation("tex4");
			PointlightUniforms[POINTLIGHT_POS] = PointLightShader->GetUniformLocation("lightpos");
			PointlightUniforms[POINTLIGHT_COLOR] = PointLightShader->GetUniformLocation("lightcolor");
			PointlightUniforms[POINTLIGHT_RANGE] = PointLightShader->GetUniformLocation("range");
			PointlightUniforms[POINTLIGHT_DROPOFF] = PointLightShader->GetUniformLocation("dropoff");
			PointlightUniforms[POINTLIGHT_JAFAR] = PointLightShader->GetUniformLocation("jafar");
			PointlightUniforms[POINTLIGHT_JANEAR] = PointLightShader->GetUniformLocation("janear");
			PointlightUniforms[POINTLIGHT_CAMERAPOS] = PointLightShader->GetUniformLocation("camerapos");
		}
		glUniform1i(PointlightUniforms[POINTLIGHT_TEX1], 0); 
		glUniform1i(PointlightUniforms[POINTLIGHT_TEX2], 1);
		glUniform1i(PointlightUniforms[POINTLIGHT_TEX3], 2);
		glUniform1i(PointlightUniforms[POINTLIGHT_TEX4], 3);
		FboArray[OPAQUE_INITIAL]->BindasTexture(0,0);
		FboArray[OPAQUE_INITIAL]->BindasTexture(1,1);
		FboArray[OPAQUE_INITIAL]->BindasTexture(2,2);
		FboArray[OPAQUE_INITIAL]->BindasTexture(3,3);


		
		glUniform3f(PointlightUniforms[POINTLIGHT_CAMERAPOS], SceneCamera->pos.x, SceneCamera->pos.y, SceneCamera->pos.z);
		glUniform1f(PointlightUniforms[POINTLIGHT_JAFAR], SceneCamera->jafar);
		glUniform1f(PointlightUniforms[POINTLIGHT_JANEAR], SceneCamera->janear);
		//Now do the point lights
		if (SimplePointLights.size() > 0)
			for (size_t i = 0; i < SimplePointLights.size(); i++) //LOOK HERE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! POINT LIGHT RENDERING HERE!!!!!!!!!!!!!!!!!!!!!!!!!!
			{
				SimplePointLights[i]->bindToUniformLight(PointlightUniforms[POINTLIGHT_POS], PointlightUniforms[POINTLIGHT_COLOR], PointlightUniforms[POINTLIGHT_RANGE], PointlightUniforms[POINTLIGHT_DROPOFF]);
				ScreenquadtoFBO(PointLightShader);
			}
	}//Eof Point Lights.
	
	
	
	//DONE WITH SHADOWLESS LIGHTS
	
	/*
	===================
	* SHADOWED LIGHTS *
	===================
	*/
	//(No code yet)
	
	glEnable(GL_DEPTH_TEST); //We want it back!
	glDisable(GL_BLEND);
	
	//Final Opaque
	if(FinalOpaqueShader) {
		FboArray[OPAQUE_FINAL]->BindRenderTarget();
		FBO::clearTexture(0.0,0.0,0.0,0.0);
		FinalOpaqueShader->Bind();
		//Grab uniform locations
		if (!haveInitializedFinalOpaqueUniforms)
		{
			/*
			enum{
				FINALOPAQUE_INITOPAQUE1_TEX, //Holds the albedo
				//Data buffers
				FINALOPAQUE_INITOPAQUE2_TEX,
				FINALOPAQUE_INITOPAQUE3_TEX,
				FINALOPAQUE_INITOPAQUE4_TEX,
				//Light Accumulator Textures
				FINALOPAQUE_LIGHTACCUM1_TEX, //Diffuse
				FINALOPAQUE_LIGHTACCUM2_TEX, //Specular
				FINALOPAQUE_NUM_FINALOPAQUE_SHADER_UNIFORMS
			};
			GLuint FinalOpaqueUniforms[FINALOPAQUE_NUM_FINALOPAQUE_SHADER_UNIFORMS];
			*/
			FinalOpaqueUniforms[FINALOPAQUE_INITOPAQUE1_TEX] = FinalOpaqueShader->GetUniformLocation("initopaque1");
			FinalOpaqueUniforms[FINALOPAQUE_INITOPAQUE2_TEX] = FinalOpaqueShader->GetUniformLocation("initopaque2");
			FinalOpaqueUniforms[FINALOPAQUE_INITOPAQUE3_TEX] = FinalOpaqueShader->GetUniformLocation("initopaque3");
			FinalOpaqueUniforms[FINALOPAQUE_INITOPAQUE4_TEX] = FinalOpaqueShader->GetUniformLocation("initopaque4");
			
			FinalOpaqueUniforms[FINALOPAQUE_LIGHTACCUM1_TEX] = FinalOpaqueShader->GetUniformLocation("lightaccum1");
			FinalOpaqueUniforms[FINALOPAQUE_LIGHTACCUM2_TEX] = FinalOpaqueShader->GetUniformLocation("lightaccum2");
			haveInitializedFinalOpaqueUniforms = true;
		}
		//Bind Uniform values
		glUniform1i(FinalOpaqueUniforms[FINALOPAQUE_INITOPAQUE1_TEX], 0);
		glUniform1i(FinalOpaqueUniforms[FINALOPAQUE_INITOPAQUE2_TEX], 1);
		glUniform1i(FinalOpaqueUniforms[FINALOPAQUE_INITOPAQUE3_TEX], 2);
		glUniform1i(FinalOpaqueUniforms[FINALOPAQUE_INITOPAQUE4_TEX], 3);
		
		glUniform1i(FinalOpaqueUniforms[FINALOPAQUE_LIGHTACCUM1_TEX], 4);
		glUniform1i(FinalOpaqueUniforms[FINALOPAQUE_LIGHTACCUM2_TEX], 5);
		
		//Bind Textures. Remember: Unit, Whichone
		FboArray[OPAQUE_INITIAL]->BindasTexture(0,0);
		FboArray[OPAQUE_INITIAL]->BindasTexture(1,1);
		FboArray[OPAQUE_INITIAL]->BindasTexture(2,2);
		FboArray[OPAQUE_INITIAL]->BindasTexture(3,3);
		
		FboArray[LIGHT_ACCUMULATOR]->BindasTexture(4,0);
		FboArray[LIGHT_ACCUMULATOR]->BindasTexture(5,1);
		
		ScreenquadtoFBO(FinalOpaqueShader);
	}
	
	
	//Transparency Render
	
	
	
	
	
	
	
	//Screenquad the results to the screen.
	
	FBO::unBindRenderTarget(width, height);
	FBO::clearTexture(0.0,0.0,0.0,0.0);
	ShowTextureShader->Bind();
	ShowTextureShader->setUniform1i("diffuse", 0);//NOTE TO SELF: Avoid glGetUniformLocation repeats
	FboArray[OPAQUE_FINAL]->BindasTexture(0,0); //See FINALOPAQUE.fs
	ScreenquadtoScreen(ShowTextureShader);
	//Beautiful, isn't it?
} //eof drawPipeline

G Buffer Fragment Shader:

#version 330
// #extension GL_ARB_conservative_depth : enable
// out vec4 fColor[2];
// INITIAL_OPAQUE.FS
// (C) GEKLMIN 2018
// layout (depth_greater) out float gl_FragDepth;
// ^ should probably re-enable that later

//List of flags. Some of these are no longer implemented, they caused too much of a performance problem. I do not recommend you enable them.
const uint GK_RENDER = uint(1); // Do we render it? This is perhaps the most important flag.
const uint GK_TEXTURED = uint(2); // Do we texture it? if disabled, only the texture will be used. if both this and colored are disabled, the object will be black.
const uint GK_COLORED = uint(4);// Do we color it? if disabled, only the texture will be used. if both this and textured are disabled, the object will be black.
const uint GK_FLAT_NORMAL = uint(8); // Do we use flat normals? If this is set, then the normals output to the fragment shader in the initial opaque pass will use the flat layout qualifier. 
const uint GK_FLAT_COLOR = uint(16); // Do we render flat colors? the final, provoking vertex will be used as the color for the entire triangle.
const uint GK_COLOR_IS_BASE = uint(32); //Use the color as the primary. Uses texture as primary if disabled.
const uint GK_TINT = uint(64); //Does secondary add to primary?
const uint GK_DARKEN = uint(128);//Does secondary subtract from primary?
const uint GK_AVERAGE = uint(256);//Do secondary and primary just get averaged?
const uint GK_COLOR_INVERSE = uint(512);//Do we use the inverse of the color?
const uint GK_TEXTURE_INVERSE = uint(1024);//Do we use the inverse of the texture color? DOES NOT invert alpha.
const uint GK_TEXTURE_ALPHA_MULTIPLY = uint(2048);//Do we multiply the color from the texture by the alpha before doing whatever it is we're doing? I do not recommend enabling this and alpha culling, especially if you're trying to create a texture-on-a-flat-color-model effect (Think sega saturn models)
const uint GK_ENABLE_ALPHA_CULLING = uint(4096); //Do we use the texture alpha to cull alpha fragments
const uint GK_TEXTURE_ALPHA_REPLACE_PRIMARY_COLOR = uint(8192); //if the alpha from the texture is <0.5 then the secondary color will replace the primary color.


//Utility functions
// vec4 when_eq(vec4 x, vec4 y) {
  // return 1.0 - abs(sign(x - y));
// }

// vec4 when_neq(vec4 x, vec4 y) {
  // return abs(sign(x - y));
// }

// vec4 when_gt(vec4 x, vec4 y) {
  // return max(sign(x - y), 0.0);
// }

// vec4 when_lt(vec4 x, vec4 y) {
  // return max(sign(y - x), 0.0);
// }

// vec4 when_ge(vec4 x, vec4 y) {
  // return 1.0 - when_lt(x, y);
// }

// vec4 when_le(vec4 x, vec4 y) {
  // return 1.0 - when_gt(x, y);
// }




uniform sampler2D diffuse; //This is actually the texture unit. limit 32. This one happens to be for the literal object's texture.
uniform samplerCube worldaroundme; //This is the cubemap we use for reflections.

in vec2 texcoord;
in vec3 normout;
flat in vec3 flatnormout;
flat in vec3 Flat_Vert_Color;
in vec3 Smooth_Vert_Color;
in vec4 ND_out;
in vec2 window_size;
in vec3 vert_to_camera;
in float ourdepth;
//Logic from the vertex level
in float isFlatNormal;
in float isTextured;
in float isColored;
in float isFlatColor;
in float ColorisBase;
in float AlphaReplaces;
in float isTinted;
in float isDarkened;
in float isAveraged;
in float isNotAnyofThose;
in vec3 worldout;


uniform float ambient;
uniform float specreflectivity;
uniform float specdamp;
uniform float emissivity;
uniform float jafar;
uniform float janear;
uniform float enableCubeMapReflections;
uniform float diffusivity;
uniform vec3 CameraPos; //Camera position in world space

vec2 bettertexcoord;
vec4 texture_value;
vec3 color_value;
vec3 primary_color;
vec3 secondary_color;
vec3 finalcolor = vec3(0,0,0); //default value. Does it work?
uniform uint renderflags;

void main()
{
	bettertexcoord = vec2(texcoord.x, -texcoord.y); //Looks like blender
	vec3 UnitNormal;
	vec3 usefulNormal;

	
	
	UnitNormal = ((normalize(flatnormout) + vec3(1.0,1.0,1.0)) * 0.5)* float((renderflags & GK_FLAT_NORMAL) > uint(0))+ ((normalize(normout) + vec3(1.0,1.0,1.0)) * 0.5) * (1-float((renderflags & GK_FLAT_NORMAL) > uint(0)));
	
	// if (UnitNormal.x > 1 || UnitNormal.y > 1 || UnitNormal.z > 1)
		// UnitNormal = vec3(1.0);
	
	usefulNormal = normalize(flatnormout) * float((renderflags & GK_FLAT_NORMAL) > uint(0)) + normalize(normout) * (1-float((renderflags & GK_FLAT_NORMAL) > uint(0)));
	

	
	texture_value = (texture2D(diffuse, bettertexcoord)) * float((renderflags & GK_TEXTURED) > uint(0)) + vec4(0.0,0.2,0.0,1.0) * (1-float((renderflags & GK_TEXTURED) > uint(0)));
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//UNCOMMENT THIS LINE IF YOU WANT ALPHA CULLING! It will slow down your application, be weary!
	// if ((renderflags & GK_ENABLE_ALPHA_CULLING) > uint(0))
		// if (texture_value.w == 0)
			// discard;
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	 
	

	float flat_color = float((renderflags & GK_FLAT_COLOR) > uint(0));
	float colored_at_all = float((renderflags & GK_COLORED) > uint(0));
	
	color_value = flat_color * colored_at_all * Flat_Vert_Color + (1-flat_color) * colored_at_all * Smooth_Vert_Color + (1-flat_color) * (1-colored_at_all) * vec3(0,0,0);
	
	//primary_color and secondary_color stuff
	

	float colorbase = float((renderflags & GK_COLOR_IS_BASE) > uint(0));
	
	primary_color = colorbase * color_value + (1-colorbase) * texture_value.xyz;
	secondary_color = (1-colorbase) * color_value + colorbase * texture_value.xyz;
	

	
	float alphareplace = float((renderflags & GK_TEXTURE_ALPHA_REPLACE_PRIMARY_COLOR) > uint(0));
	primary_color = primary_color * (1-alphareplace) + (primary_color * (1-texture_value.w)) + (texture_value.xyz * texture_value.w) * alphareplace;
	//EQUATION TIME!
	
	//This will be hell to break up. Maybe the compiler will do it for me?
	// if ((renderflags & GK_TINT) > uint(0))
		// finalcolor = primary_color + secondary_color;
	// else if ((renderflags & GK_DARKEN) > uint(0))
		// finalcolor = primary_color - secondary_color;
	// else if ((renderflags & GK_AVERAGE) > uint(0))
		// finalcolor = vec3(
		// (primary_color.x + secondary_color.x)/2.0,
		// (primary_color.y + secondary_color.y)/2.0,
		// (primary_color.z + secondary_color.z)/2.0);
	// else
		// finalcolor = primary_color;
	
	//Floating point logic tables?!?! 
	float isTint = float((renderflags & GK_TINT) > uint(0)); // 1 if true, 0 if false
	float isNotTint = 1-isTint;//swaps with the other value
	float isDarken = float((renderflags & GK_DARKEN) > uint(0));
	float isNotDarken = 1-isDarken;
	float isAverage = float((renderflags & GK_AVERAGE) > uint(0));
	float isNotAverage = 1-isAverage;
	//it is none of those if:
	//* More than one of them is true
	//* All of them are false
	float isNoneofThose = isTint * isDarken * isAverage + isNotTint * isAverage * isDarken + isTint * isNotAverage * isDarken + isTint * isAverage * isNotDarken + isNotTint * isNotAverage * isNotDarken;
	float isNotNoneofThose = 1-isNoneofThose;
	
	//Calc finalcolor;
	finalcolor = (primary_color + secondary_color) * isTint * isNotNoneofThose + (primary_color - secondary_color) * isDarken * isNotNoneofThose + vec3((primary_color.x + secondary_color.x)/2.0,(primary_color.y + secondary_color.y)/2.0,(primary_color.z + secondary_color.z)/2.0) * isAverage * isNotNoneofThose + primary_color * isNoneofThose;
	
	
	
	// (diffuse component * texture) + specular
	// gl_FragData[0] = mix(vec4(finalcolor,specreflectivity),vec4(texture(worldaroundme,reflect(-vert_to_camera, usefulNormal)).xyz, specreflectivity),specreflectivity/2.0); //Lol
	vec4 cubemapData = texture(worldaroundme,reflect(-vert_to_camera, usefulNormal));
	gl_FragData[0] = vec4(finalcolor,specreflectivity);
	
	float adjustedspecdamp = specdamp/128.0;
	gl_FragData[1] = vec4(UnitNormal,adjustedspecdamp); //Normals. Specular dampening goes as high as 128 in OpenGL Immediate Mode, so it has to be allowed up there. Note that we are using 32 bit floating-point accuracy, so dividing will not seriously reduce our abilities with regards to specdamp


	vec3 adjusted_world = worldout - CameraPos;
		gl_FragData[2] = vec4(adjusted_world.x/jafar + 0.5 , adjusted_world.y/jafar + 0.5, adjusted_world.z/jafar + 0.5, emissivity/2.0 + 0.5);
		
		gl_FragData[3] = vec4(diffusivity, cubemapData.xyz * enableCubeMapReflections * specreflectivity * adjustedspecdamp); //Not using ambient.

}

PointLight Fragment Shader:

#version 330
out vec4 fColor[2];

in vec2 texcoord;
in vec2 ScreenPosition;
// uniform sampler2D diffuse; //This is actually the texture unit. limit 32. This one happens to be for the literal object's texture.

uniform sampler2D tex1; //Unit 0
uniform sampler2D tex2;
uniform sampler2D tex3;
uniform sampler2D tex4; //Unit 3
uniform vec3 lightpos;
uniform vec3 lightcolor;
uniform vec3 camerapos;
uniform float range;
uniform float dropoff;
//far and near clip planes
uniform float jafar;
uniform float janear;



void main()
{
	//Grab the values from the initial opaque pass buffers
	vec4 tex1_value = texture2D(tex1, texcoord);
	vec4 tex2_value = texture2D(tex2, texcoord);
	vec4 tex3_value = texture2D(tex3, texcoord);
	vec4 tex4_value = texture2D(tex4, texcoord);
	
	vec3 world_pos = (tex3_value.xyz - vec3(0.5)) * jafar + camerapos;
	
	
	vec3 surface_normal_world = (tex2_value.xyz * 2) - vec3(1);
	vec3 unit_surface_normal_world = normalize(surface_normal_world);
	float specular_dampening = tex2_value.w * 128.0;
	float specular_reflectivity = tex1_value.w;
	float diffusivity = tex4_value.x; 
	surface_normal_world = normalize(surface_normal_world);
	//PHONG calculations begin!
	vec3 frag_to_camera = camerapos - world_pos;
	vec3 frag_to_light = lightpos - world_pos;
	
	vec3 unit_frag_to_camera = normalize(frag_to_camera); 
	vec3 unit_frag_to_light = normalize(frag_to_light);
	
	vec3 lightDir = -unit_frag_to_light;
	
	
	//DIFFUSE LIGHTING CALCULATION
	float nDotl = max(dot(unit_surface_normal_world, unit_frag_to_light), 0);
	float lightdist = length(frag_to_light); //Can never be negative
	nDotl = float(range > 0) * max(nDotl * pow(max(1-(lightdist/range),0.0), dropoff),0.0) + float(range <= 0) * nDotl;
	vec3 betterdiffuse = nDotl * lightcolor * diffusivity;
	
	//SPECULAR LIGHTING CALCULATION
	vec3 reflectedLightDir = reflect(lightDir,unit_surface_normal_world);
	
	float specFactor = max(
		dot(reflectedLightDir, unit_frag_to_camera),
		0.0 
	);
	float specDampFactor = pow(specFactor,specular_dampening);
	
	vec3 finalSpecular = specDampFactor * specular_reflectivity * lightcolor;
	finalSpecular = float(range > 0) * finalSpecular * max(1-(lightdist/range),0.0) + float(range <= 0) * finalSpecular;
	
	//The skybox has to have a diffuse of 1.
	fColor[0] = vec4(betterdiffuse,1.0);
	fColor[1] = vec4(finalSpecular,1.0);
}

Whatever you read, you misinterpreted it. To maximize the number of light sources you can process, you want to minimize the fill per light. To do so, you typically apply multiple lights per primitive, and (as best a you efficiently can) avoid applying lights to pixels they cannot influence.

yes but you said it would be faster than using a for loop over all lights in the scene in one pass

For the first time in his life, Dark photon was wrong about something.
This fragment shader which takes in 100 point lights and renders them in a for loop (WITH dynamic uniform indexing… using an iterator to index a uniform) is A BAJILLION TIMES FASTER than the one that renders one at a time (below)

#version 330

#define MAX_LIGHTS 100
out vec4 fColor[2];

in vec2 texcoord;
in vec2 ScreenPosition;
// uniform sampler2D diffuse; //This is actually the texture unit. limit 32. This one happens to be for the literal object's texture.

struct PointLight {
	vec3 pos;
	vec3 color;
	float range;
	float dropoff;
};

uniform PointLight LightArray[MAX_LIGHTS]; //MAX_LIGHTS
//NOTE: I feared a for loop might be slow because of what I saw here, but apparently technology has advanced since the 2006. My GTX 960 can do it fine!
/*
https://stackoverflow.com/questions/16039515/glsl-for-loop-array-index#26480937
*/

uniform sampler2D tex1; //Unit 0
uniform sampler2D tex2;
uniform sampler2D tex3;
uniform sampler2D tex4; //Unit 3
uniform vec3 camerapos;
uniform int numlights; //How many lights do we have?
//far and near clip planes
/* DOES NOT work!
vec3 calculate_world_position(vec2 texture_coordinate, float depth_from_depth_buffer)
{
    vec4 clip_space_position = vec4(texture_coordinate * 2.0 - vec2(1.0), 2.0 * depth_from_depth_buffer - 1.0, 1.0);

    //vec4 position = inverse_projection_matrix * clip_space_position; // Use this for view space
    vec4 position = inverse_view_projection_matrix * clip_space_position; // Use this for world space

    return(position.xyz / position.w);
}
*/

//Another thing that should work

void main()
{
	//Grab the values from the initial opaque pass buffers
	vec4 tex1_value = texture2D(tex1, texcoord);
	vec4 tex2_value = texture2D(tex2, texcoord);
	vec4 tex3_value = texture2D(tex3, texcoord);
	vec4 tex4_value = texture2D(tex4, texcoord);
	
	vec3 world_pos = tex3_value.xyz;
	vec3 unit_surface_normal_world = tex2_value.xyz;
	float specular_dampening = tex2_value.w;
	float specular_reflectivity = tex1_value.w;
	float diffusivity = tex4_value.x;
	vec3 frag_to_camera = camerapos - world_pos;
	vec3 unit_frag_to_camera = normalize(frag_to_camera);
	
	vec3 betterdiffuse;
	vec3 finalSpecular;
	//Our main for loop.
	for (int i = 0; i < numlights && i < MAX_LIGHTS; i++){
		vec3 frag_to_light = LightArray[i].pos - world_pos;
		vec3 unit_frag_to_light = normalize(frag_to_light);
		vec3 lightDir = -unit_frag_to_light;
		
		//DIFFUSE LIGHTING CALCULATION
		float nDotl = dot(unit_surface_normal_world, unit_frag_to_light);
		float lightdist = length(frag_to_light); //Can never be negative
		nDotl = max(nDotl * pow(max(1-(lightdist/LightArray[i].range),0.0), LightArray[i].dropoff),0.0);
		betterdiffuse += nDotl * LightArray[i].color * diffusivity;
		
		//SPECULAR LIGHTING CALCULATION
		vec3 reflectedLightDir = reflect(lightDir,unit_surface_normal_world);
		
		float specFactor = max(
			dot(reflectedLightDir, unit_frag_to_camera),
			0.0 
		);
		float specDampFactor = pow(specFactor,specular_dampening);
		
		finalSpecular += specDampFactor * specular_reflectivity * LightArray[i].color * pow(max(1-(lightdist/LightArray[i].range),0.0), LightArray[i].dropoff);
	}
	
	fColor[0] = vec4(betterdiffuse,1.0);
	fColor[1] = vec4(finalSpecular,1.0);
}
 #version 330
out vec4 fColor[2];

in vec2 texcoord;
in vec2 ScreenPosition;
// uniform sampler2D diffuse; //This is actually the texture unit. limit 32. This one happens to be for the literal object's texture.

uniform sampler2D tex1; //Unit 0
uniform sampler2D tex2;
uniform sampler2D tex3;
uniform sampler2D tex4; //Unit 3
uniform vec3 lightpos;
uniform vec3 lightcolor;
uniform vec3 camerapos;
uniform float range;
uniform float dropoff;
//far and near clip planes
uniform float jafar;
uniform float janear;
/* DOES NOT work!
vec3 calculate_world_position(vec2 texture_coordinate, float depth_from_depth_buffer)
{
    vec4 clip_space_position = vec4(texture_coordinate * 2.0 - vec2(1.0), 2.0 * depth_from_depth_buffer - 1.0, 1.0);

    //vec4 position = inverse_projection_matrix * clip_space_position; // Use this for view space
    vec4 position = inverse_view_projection_matrix * clip_space_position; // Use this for world space

    return(position.xyz / position.w);
}
*/

//Another thing that should work

void main()
{
	//Grab the values from the initial opaque pass buffers
	vec4 tex1_value = texture2D(tex1, texcoord);
	vec4 tex2_value = texture2D(tex2, texcoord);
	vec4 tex3_value = texture2D(tex3, texcoord);
	vec4 tex4_value = texture2D(tex4, texcoord);
	
	vec3 world_pos = tex3_value.xyz;
	vec3 unit_surface_normal_world = tex2_value.xyz;
	float specular_dampening = tex2_value.w;
	float specular_reflectivity = tex1_value.w;
	float diffusivity = tex4_value.x; 
	//PHONG calculations begin!
	vec3 frag_to_camera = camerapos - world_pos;
	vec3 frag_to_light = lightpos - world_pos;
	
	vec3 unit_frag_to_camera = normalize(frag_to_camera); 
	vec3 unit_frag_to_light = normalize(frag_to_light);
	
	vec3 lightDir = -unit_frag_to_light;
	
	
	//DIFFUSE LIGHTING CALCULATION
	float nDotl = dot(unit_surface_normal_world, unit_frag_to_light);
	float lightdist = length(frag_to_light); //Can never be negative
	nDotl = max(nDotl * pow(max(1-(lightdist/range),0.0), dropoff),0.0);
	vec3 betterdiffuse = nDotl * lightcolor * diffusivity;
	
	//SPECULAR LIGHTING CALCULATION
	vec3 reflectedLightDir = reflect(lightDir,unit_surface_normal_world);
	
	float specFactor = max(
		dot(reflectedLightDir, unit_frag_to_camera),
		0.0 
	);
	float specDampFactor = pow(specFactor,specular_dampening);
	
	vec3 finalSpecular = specDampFactor * specular_reflectivity * lightcolor;
	finalSpecular = finalSpecular * pow(max(1-(lightdist/range),0.0), dropoff);
	
	fColor[0] = vec4(betterdiffuse,1.0);
	fColor[1] = vec4(finalSpecular,1.0);
}

I still love you Dark Photon <3 no hate~~~

For the first time in his life, Dark photon was wrong about something.

I’ve looked over his posting history for the last week or so, and I’ve seen nothing about this. Perhaps you could provide a link to this supposed statement, so that we can verify your claims.


/* DOES NOT work!
vec3 calculate_world_position(vec2 texture_coordinate, float depth_from_depth_buffer)
{
    vec4 clip_space_position = vec4(texture_coordinate * 2.0 - vec2(1.0), 2.0 * depth_from_depth_buffer - 1.0, 1.0);
 
    //vec4 position = inverse_projection_matrix * clip_space_position; // Use this for view space
    vec4 position = inverse_view_projection_matrix * clip_space_position; // Use this for world space
 
    return(position.xyz / position.w);
}
*/

There is nothing wrong with this code, except from the naming: What you call “clip_space_position” are actually NDC coordinates. So please stop confusing people with your wrong information.