Example #1
0
CGLMShaderPair::CGLMShaderPair( GLMContext *ctx  )
{
	m_ctx = ctx;
	m_ctx->MakeCurrent();
	
	m_vertexProg = m_fragmentProg = NULL;

	m_program = glCreateProgramObjectARB();
	GLMCheckError();

	m_locVertexParams = -1;
	m_locVertexInteger0 = -1;	// "i0"
	m_locVertexBool0 = -1;		// "b0"
	m_locVertexBool1 = -1;		// "b1"
	m_locVertexBool2 = -1;		// "b2"
	m_locVertexBool3 = -1;		// "b3"
	
	m_locFragmentParams = -1;
	m_locFragmentFakeSRGBEnable = -1;
	m_fakeSRGBEnableValue = -1.0f;
	
	memset( m_locSamplers, 0xFF, sizeof( m_locSamplers ) );
	
	m_valid = false;
	m_samplersFixed = false;	// fix them at draw time, and only do it once.
	m_revision = 0;				// bumps to 1 once linked
}
Example #2
0
CGLMProgram::~CGLMProgram( )
{
	m_ctx->CheckCurrent();
	
	// if there is an arb program, delete it
	GLMShaderDesc *arbDesc = &m_descs[ kGLMARB ];
	if (arbDesc->m_object.arb)
	{
		glDeleteProgramsARB( 1, &arbDesc->m_object.arb );
		GLMCheckError();
		arbDesc->m_object.arb = 0;
	}
	
	// if there is a GLSL shader, delete it
	GLMShaderDesc *glslDesc = &m_descs[kGLMGLSL];
	if (glslDesc->m_object.glsl)
	{
		glDeleteShader( (uintptr_t)glslDesc->m_object.glsl );	// why do I need a cast here again ?
		GLMCheckError();
		glslDesc->m_object.glsl = 0;
	}

#if GLMDEBUG
	if (m_editable)
	{
		delete m_editable;
		m_editable = NULL;
	}
#endif

	if (m_text)
	{
		free( m_text );
		m_text = NULL;
	}
	m_ctx = NULL;
}
CGLMBuffer::~CGLMBuffer( )
{
	m_ctx->CheckCurrent();
	
	if (m_pseudo)
	{
		free (m_pseudoBuf);
		m_pseudoBuf = NULL;
	}
	else
	{
		glDeleteBuffersARB( 1, &m_name );
		GLMCheckError();
	}
	
	m_ctx = NULL;
	m_name = 0;
	m_bound = 0;
	
	m_lastMappedAddress = NULL;
}
Example #4
0
bool	CGLMShaderPair::SetProgramPair			( CGLMProgram *vp, CGLMProgram *fp )
{
	m_valid	= false;			// assume failure
	
	// true result means successful link and query
	bool vpgood = (vp!=NULL) && (vp->m_descs[ kGLMGLSL ].m_valid);
	bool fpgood = (fp!=NULL) && (fp->m_descs[ kGLMGLSL ].m_valid);
	
	if (!fpgood)
	{
		// fragment side allowed to be "null".
		fp = m_ctx->m_nullFragmentProgram;
	}

	if (vpgood && fpgood)
	{
		// attempt link. but first, detach any previously attached programs
		if (m_vertexProg)
		{
			glDetachObjectARB(m_program, m_vertexProg->m_descs[kGLMGLSL].m_object.glsl);
			GLMCheckError();
			m_vertexProg = NULL;			
		}
		
		if (m_fragmentProg)
		{
			glDetachObjectARB(m_program, m_fragmentProg->m_descs[kGLMGLSL].m_object.glsl);
			GLMCheckError();
			m_fragmentProg = NULL;			
		}
		
		// now attach
		
		glAttachObjectARB(m_program, vp->m_descs[kGLMGLSL].m_object.glsl);
		m_vertexProg = vp;
		GLMCheckError();

		glAttachObjectARB(m_program, fp->m_descs[kGLMGLSL].m_object.glsl);
		m_fragmentProg = fp;
		GLMCheckError();
	
		// force the locations for input attributes v0-vN to be at locations 0-N
		// use the vertex attrib map to know which slots are live or not... oy!  we don't have that map yet... but it's OK.
		// fallback - just force v0-v15 to land in locations 0-15 as a standard.
		
		if (vp->m_descs[kGLMGLSL].m_valid)
		{
			for( int i=0; i < 16; i++)
			{
				char tmp[16];
				sprintf(tmp, "v%d", i);	// v0 v1 v2 ... et al
				
				glBindAttribLocationARB( m_program, i, tmp );
				GLMCheckError();			
			}
		}
			
		// now link
		glLinkProgramARB( m_program );
		GLMCheckError();			

		// check for success
		GLint result = 0;
		glGetObjectParameterivARB(m_program,GL_OBJECT_LINK_STATUS_ARB,&result);	// want GL_TRUE
		
		if (result == GL_TRUE)
		{
			// success
			
			m_valid	= true;
			m_revision++;
		}
		else
		{
			GLint length = 0;
			GLint laux = 0;
			
			// do some digging
			glGetObjectParameterivARB(m_program,GL_OBJECT_INFO_LOG_LENGTH_ARB,&length);

			GLcharARB *logString = (GLcharARB *)malloc(length * sizeof(GLcharARB));
			glGetInfoLogARB(m_program, length, &laux, logString);	

			char *vtemp = strdup(vp->m_text);
			vtemp[ vp->m_descs[kGLMGLSL].m_textOffset + vp->m_descs[kGLMGLSL].m_textLength ] = 0;
			
			char *ftemp = strdup(fp->m_text);
			ftemp[ fp->m_descs[kGLMGLSL].m_textOffset + fp->m_descs[kGLMGLSL].m_textLength ] = 0;
			
			GLMPRINTF(("-D- ----- GLSL link failed: \n %s ",logString ));

			GLMPRINTF(("-D- ----- GLSL vertex program selected: %08x (handle %08x)", vp, vp->m_descs[kGLMGLSL].m_object.glsl ));
			GLMPRINTTEXT(( vtemp + vp->m_descs[kGLMGLSL].m_textOffset, eDebugDump, GLMPRINTTEXT_NUMBEREDLINES ));
			
			GLMPRINTF(("-D- ----- GLSL fragment program selected: %08x (handle %08x)", fp, vp->m_descs[kGLMGLSL].m_object.glsl ));
			GLMPRINTTEXT(( ftemp + fp->m_descs[kGLMGLSL].m_textOffset, eDebugDump, GLMPRINTTEXT_NUMBEREDLINES ));
			
			GLMPRINTF(("-D- -----end-----" ));

			free( ftemp );
			free( vtemp );
			free( logString );
		}
	}
	else
	{
		// fail
		Assert(!"Can't link these programs");
	}
	
	if (m_valid)
	{
		m_locVertexParams = glGetUniformLocationARB( m_program, "vc");
		GLMCheckError();

		m_locVertexInteger0 = glGetUniformLocationARB( m_program, "i0");
		GLMCheckError();

		m_locVertexBool0 = glGetUniformLocationARB( m_program, "b0");
		GLMCheckError();
		m_locVertexBool1 = glGetUniformLocationARB( m_program, "b1");
		GLMCheckError();
		m_locVertexBool2 = glGetUniformLocationARB( m_program, "b2");
		GLMCheckError();
		m_locVertexBool3 = glGetUniformLocationARB( m_program, "b3");
		GLMCheckError();

 		m_locFragmentParams = glGetUniformLocationARB( m_program, "pc");
		GLMCheckError();

 		m_locFragmentFakeSRGBEnable = glGetUniformLocationARB( m_program, "flSRGBWrite");
		GLMCheckError();
		m_fakeSRGBEnableValue = -1.0f;
		
		for( int sampler=0; sampler<16; sampler++)
		{
			char tmp[16];
			sprintf(tmp, "sampler%d", sampler);	// sampler0 .. sampler1.. etc
			
			m_locSamplers[sampler] = glGetUniformLocationARB( m_program, tmp );
			GLMCheckError();
		}
	}
	else
	{
		m_locVertexParams = -1;

		m_locVertexInteger0 = -1;
		m_locVertexBool0 = -1;
		m_locVertexBool1 = -1;
		m_locVertexBool2 = -1;
		m_locVertexBool3 = -1;

		m_locFragmentParams = -1;
		m_locFragmentFakeSRGBEnable = -1;
		m_fakeSRGBEnableValue = -999;
		
		memset( m_locSamplers, 0xFF, sizeof( m_locSamplers ) );
		
		m_revision = 0;		
	}

	return m_valid;
}
Example #5
0
bool CGLMProgram::CheckValidity( EGLMProgramLang lang )
{
	static char *targnames[] = { "vertex", "fragment" };

	switch(lang)
	{
		case kGLMARB:
		{
			GLMShaderDesc *arbDesc;
			arbDesc = &m_descs[ kGLMARB ];
			
			GLenum arbTarget = GLMProgTypeToARBEnum( m_type );

			Assert( arbDesc->m_compiled );
			
			arbDesc->m_valid = true;	// assume success til we see otherwise

			// assume program is bound.  is there anything wrong with it ?

			GLint isNative=0;
			glGetProgramivARB( arbTarget, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &isNative );
			GLMCheckError();
			
			// If the program is over the hardware's limits, print out some information
			if (isNative!=1)
			{
				arbDesc->m_valid = false;
				
				// check everything we can check
				char checkmask = (1<<m_type);	// 1 for VP, 2 for FP
				
				for( GLMShaderLimitDesc *desc = g_glmShaderLimitDescs; desc->m_valueEnum !=0; desc++ )
				{
					if ( desc->m_flags & checkmask )
					{
						// test it
						GLint value = 0;
						GLint limit = 0;
						glGetProgramivARB(arbTarget, desc->m_valueEnum, &value);
						GLMCheckError();
						
						glGetProgramivARB(arbTarget, desc->m_limitEnum, &limit);
						GLMCheckError();
						
						if (value > limit)
						{
							GLMPRINTF(("-D- Invalid %s program: program has %d %s; limit is %d", targnames[ m_type ], value, desc->m_debugName, limit ));
						}
					}
				}
			}

			// syntax error check
			GLint errorLine;
			glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errorLine );
			GLMCheckError();

			if ( errorLine!=-1 )
			{
				const GLubyte* errorString = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
				GLMPRINTF(( "-D- Syntax error in ARB %s program: %s",targnames[ m_type ], errorString ));
				arbDesc->m_valid = false;
			}
			if (!arbDesc->m_valid)
			{
				char *temp = strdup(m_text);
				temp[ arbDesc->m_textOffset + arbDesc->m_textLength ] = 0;
				GLMPRINTF(("-D- ----- ARB compile failed; bad source follows -----" ));
				GLMPRINTTEXT(( temp + arbDesc->m_textOffset, eDebugDump, GLMPRINTTEXT_NUMBEREDLINES ));
				GLMPRINTF(("-D- -----end-----" ));
				free( temp );
			}
			
			return arbDesc->m_valid;
		}
		break;
		
		case kGLMGLSL:
		{
			GLMShaderDesc *glslDesc;			
			glslDesc = &m_descs[ kGLMGLSL ];
			
			GLenum glslStage = GLMProgTypeToGLSLEnum( m_type );

			Assert( glslDesc->m_compiled );
			
			glslDesc->m_valid = true;	// assume success til we see otherwise

			// GLSL error check
			int compiled = 0, length = 0, laux = 0;

			glGetObjectParameterivARB( (GLhandleARB)glslDesc->m_object.glsl, GL_OBJECT_COMPILE_STATUS_ARB, &compiled);
			glGetObjectParameterivARB( (GLhandleARB)glslDesc->m_object.glsl, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
			GLcharARB *logString = (GLcharARB *)malloc(length * sizeof(GLcharARB));
			glGetInfoLogARB((GLhandleARB)glslDesc->m_object.glsl, length, &laux, logString);	
			
			// we may not be able to check "native limits" stuff until link time. meh

			if (!compiled)
			{
				glslDesc->m_valid = false;
			}
			
			if (!glslDesc->m_valid)
			{
				char *temp = strdup(m_text);
				temp[ glslDesc->m_textOffset + glslDesc->m_textLength ] = 0;
				GLMPRINTF(("-D- ----- GLSL compile failed: \n %s \n",logString ));
				GLMPRINTTEXT(( temp + glslDesc->m_textOffset, eDebugDump, GLMPRINTTEXT_NUMBEREDLINES ));
				GLMPRINTF(("-D- -----end-----" ));
				free( temp );
			}
			
			free( logString );

			return glslDesc->m_valid;
		}
		break;
	}
	
	return false;
}
Example #6
0
bool	CGLMProgram::Compile( EGLMProgramLang lang )
{
	bool result = true;	// indicating validity..
	bool noisy = false;
	int loglevel = gl_shaderpair_cachelog/* .GetInt() */;
	
	switch( lang )
	{
		case kGLMARB:
		{
			GLMShaderDesc *arbDesc;
			
			arbDesc = &m_descs[ kGLMARB ];
			
			// make sure no GLSL program is set up
			glUseProgram(0);
			GLMCheckError();
			// bind our program container to context
			GLenum arbTarget = GLMProgTypeToARBEnum( m_type );

			glSetEnable( arbTarget, true );							// unclear if I need this to compile or just to draw...
			GLMCheckError();

			glBindProgramARB( arbTarget, arbDesc->m_object.arb );	// object created or just re-bound
			GLMCheckError();

			char *section = m_text + arbDesc->m_textOffset;
			char *lastCharOfSection = section + arbDesc->m_textLength;	// actually it's one past the last textual character

			#if GLMDEBUG				
				if(noisy)
				{
					GLMPRINTF((">-D- CGLMProgram::Compile submitting following text for ARB %s program (name %d) ---------------------",
						arbTarget == GL_FRAGMENT_PROGRAM_ARB ? "fragment" : "vertex",
						arbDesc->m_object.arb ));

					// we don't have a "print this many chars" call yet
					// just temporarily null terminate the text we want to print
					
					char saveChar = *lastCharOfSection;
					
					*lastCharOfSection= 0;
					GLMPRINTTEXT(( section, eDebugDump ));
					*lastCharOfSection= saveChar;

					GLMPRINTF(("<-D- CGLMProgram::Compile ARB EOT--" ));
				}
			#endif

			glProgramStringARB( arbTarget, GL_PROGRAM_FORMAT_ASCII_ARB, arbDesc->m_textLength, section );
			GLMCheckError( true, false );			
			arbDesc->m_compiled = true;	// compiled but not necessarily valid
			
			CheckValidity( lang );
			GLMCheckError();
			// leave it bound n enabled, don't care (draw will sort it all out)

			result = arbDesc->m_valid;
		}
		break;

		case kGLMGLSL:
		{
			GLMShaderDesc *glslDesc;
			
			glslDesc = &m_descs[ kGLMGLSL ];

			GLenum glslStage = GLMProgTypeToGLSLEnum( m_type );
			
			// there's no binding to do for GLSL.  but make sure no ARB stuff is bound for tidiness.
			glSetEnable( GL_VERTEX_PROGRAM_ARB, false );
			glSetEnable( GL_FRAGMENT_PROGRAM_ARB, false );	// add check errors on these
			
			glBindProgramARB( GL_VERTEX_PROGRAM_ARB, 0 );
			glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, 0 );

			// no GLSL program either
			glUseProgram(0);
			
			// pump text into GLSL shader object

			char *section = m_text + glslDesc->m_textOffset;
			char *lastCharOfSection = section + glslDesc->m_textLength;	// actually it's one past the last textual character

			#if GLMDEBUG
				if(noisy)
				{
					GLMPRINTF((">-D- CGLMProgram::Compile submitting following text for GLSL %s program (name %d) ---------------------",
						glslStage == GL_FRAGMENT_SHADER_ARB ? "fragment" : "vertex",
						glslDesc->m_object.glsl ));

					// we don't have a "print this many chars" call yet
					// just temporarily null terminate the text we want to print
					
					char saveChar = *lastCharOfSection;
					
					*lastCharOfSection= 0;
					GLMPRINTTEXT(( section, eDebugDump ));
					*lastCharOfSection= saveChar;

					GLMPRINTF(("<-D- CGLMProgram::Compile GLSL EOT--" ));
				}
			#endif

			glShaderSourceARB( glslDesc->m_object.glsl, 1, (const GLchar **)&section, &glslDesc->m_textLength);	
			GLMCheckError( true, false );			

			// compile
			glCompileShaderARB( glslDesc->m_object.glsl );
			glslDesc->m_compiled = true;	// compiled but not necessarily valid
			GLMCheckError( true, false );			

			CheckValidity( lang );
			GLMCheckError();			

			if (loglevel>=2)
			{
				char tempname[128];
				int tempindex = -1;
				int tempcombo = -1;

				//GetLabelIndexCombo( tempname, sizeof(tempname), &tempindex, &tempcombo );
				//printf("\ncompile: - [ %s/%d/%d ] on GL name %d ", tempname, tempindex, tempcombo, glslDesc->m_object.glsl );
				

				GetComboIndexNameString( tempname, sizeof(tempname) );
				printf("\ncompile: %s on GL name %p ", tempname, glslDesc->m_object.glsl );
			}

			result = glslDesc->m_valid;
		}
		break;
	}
	return result;
}
void	CGLMBuffer::Lock( GLMBuffLockParams *params, char **addressOut )
{
	char	*resultPtr = NULL;
	
	//Assert( !m_mapped);
	
	m_ctx->CheckCurrent();
	GLMCheckError();

	if (params->m_offset >= m_size)
		Debugger();
	
	if (params->m_offset + params->m_size > m_size)
		Debugger();

	// bind (yes, even for pseudo - this binds name 0)
	m_ctx->BindBufferToCtx( this->m_type, this );
	
	if (m_pseudo)
	{
		// discard is a no-op

		// async map modes are a no-op

		// latch last mapped address (silly..)
		m_lastMappedAddress = (float*)m_pseudoBuf;

		// calc lock address
		resultPtr = m_pseudoBuf + params->m_offset;
		
		// dirty range is a no-op
	}
	else
	{
		// perform discard if requested
		if (params->m_discard)
		{
			// observe gl_bufmode on any orphan event.
			// if orphaned and bufmode is nonzero, flip it to dynamic.
			GLenum hint = gl_bufmode /*.GetInt()*/ ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB;
			glBufferDataARB( m_buffGLTarget, m_size, NULL, hint );
			
			m_lastMappedAddress = NULL;
			
			m_revision++;	// revision grows on orphan event
		}

		// adjust async map option appropriately, leave explicit flush unchanged
		this->SetModes( params->m_nonblocking, m_enableExplicitFlush );

		// map
		char *mapPtr = (char*)glMapBufferARB( this->m_buffGLTarget, GL_READ_WRITE_ARB );
		
		if (!mapPtr)
		{
			Debugger();
		}
		
		if (m_lastMappedAddress)
		{
			// just check if it moved
			//Assert (m_lastMappedAddress == (float*)mapPtr);
		}

		m_lastMappedAddress = (float*)mapPtr;

		// calculate offset location
		resultPtr = mapPtr + params->m_offset;

		// adjust dirty range
		if (m_dirtyMinOffset != m_dirtyMaxOffset)
		{
			// grow range
			m_dirtyMinOffset = std::min( m_dirtyMinOffset, params->m_offset );
			m_dirtyMaxOffset = std::min( m_dirtyMaxOffset, params->m_offset+params->m_size );
		}
		else
		{
			// set range
			m_dirtyMinOffset = params->m_offset;
			m_dirtyMaxOffset = params->m_offset+params->m_size;
		}

		// pad and clamp dirty range to choice of boundary
		uint quantum = (m_ctx->Caps().m_hasPerfPackage1) ? gl_buffer_alignment_quantum_slgu /*.GetInt()*/ : gl_buffer_alignment_quantum /*.GetInt()*/ ;
		uint quantum_mask = quantum - 1;

		m_dirtyMinOffset = m_dirtyMinOffset & (~quantum_mask);
		m_dirtyMaxOffset = (m_dirtyMaxOffset + quantum_mask) & (~quantum_mask);
		m_dirtyMaxOffset = std::min( m_dirtyMaxOffset, m_size );
	}

	m_mapped = true;
	
	*addressOut = resultPtr;
}
CGLMBuffer::CGLMBuffer( GLMContext *ctx, EGLMBufferType type, uint size, uint options )
{
	m_ctx = ctx;
	m_type = type;
	switch(m_type)
	{
		case	kGLMVertexBuffer:		m_buffGLTarget = GL_ARRAY_BUFFER_ARB; break;
		case	kGLMIndexBuffer:		m_buffGLTarget = GL_ELEMENT_ARRAY_BUFFER_ARB; break;
		case	kGLMUniformBuffer:		m_buffGLTarget = GL_UNIFORM_BUFFER_EXT; break;
		case	kGLMPixelBuffer:		m_buffGLTarget = GL_PIXEL_UNPACK_BUFFER_ARB; break;
		
		default:	//Assert(!"Unknown buffer type" );
		break;
	}
	m_size = size;
	m_bound = false;
	m_mapped = false;
	m_lastMappedAddress = NULL;

	m_enableAsyncMap = false;
	m_enableExplicitFlush = false;
	m_dirtyMinOffset = m_dirtyMaxOffset = 0;								// adjust/grow on lock, clear on unlock

	m_ctx->CheckCurrent();
	m_revision = rand();

	// make a decision about pseudo mode
	// this looked like it didn't help much or was actually slower, so leave it available but only as opt-in.
	// a more clever implementation would be able to select pseudo buf storage for small batches only..
	m_pseudo = false;	// (m_type==kGLMIndexBuffer) && (CommandLine()->FindParm("-gl_enable_pseudobufs"));	
	if (m_pseudo)
	{
		m_name		= 0;		
		m_pseudoBuf	= (char*)malloc( size );
		
		m_ctx->BindBufferToCtx( m_type, NULL );		// exit with no buffer bound
	}
	else
	{
		glGenBuffersARB( 1, &m_name );
		GLMCheckError();

		m_ctx->BindBufferToCtx( m_type, this );	// causes glBindBufferARB

		// buffers start out static, but if they get orphaned and gl_bufmode is non zero,
		// then they will get flipped to dynamic.
		
		GLenum hint = GL_STATIC_DRAW_ARB;
		switch(m_type)
		{
			case	kGLMVertexBuffer:		hint = (options & GLMBufferOptionDynamic) ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB; break;
			case	kGLMIndexBuffer:		hint = (options & GLMBufferOptionDynamic) ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB; break;
			case	kGLMUniformBuffer:		hint = GL_DYNAMIC_DRAW_ARB; break;	// "fwiw" - shrug
			case	kGLMPixelBuffer:		hint = (options & GLMBufferOptionDynamic) ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB; break;
			
			default:	//Assert(!"Unknown buffer type" );
			break;
		}

		glBufferDataARB( m_buffGLTarget, m_size, NULL, hint );	// may ultimately need more hints to set the usage correctly (esp for streaming)

		this->SetModes( false, true, true );

		m_ctx->BindBufferToCtx( m_type, NULL );	// unbind me
	}
}