CG include issues (with solution)

Discussion area about developing or extending OGRE, adding plugins for it or building applications on it. No newbie questions please, use the Help forum for that.
nbeato
Gnome
Posts: 372
Joined: Thu Dec 20, 2007 1:00 am
Location: Florida
x 3

CG include issues (with solution)

Post by nbeato »

Hey, I want to submit a patch for this, but I'm looking for feedback first.

Issues:

1) CG include resolution (CgProgram::resolveIncludePaths) does not work recursively. If you have a zip file with something like "A/1.cg" include file "A/B/2.cg", which includes something like "C/3.cg", the compilation process says it can't open "C/3.cg". A more realistic scenario is something like "shaders/car.cg" including something like "details/car/high_end.cg", which requires something like "details/lighting/global_illumination.cg".

2) When including Cg files, the compiler reports line numbers that are erroneous due to included files bloating the number. (I haven't checked this recently, but I remember seeing it before).

Resolution:

CG added an include resolution callback in 2.1. I tested this and it appears to work fine in my CG code (it breaks with CGFX still, but I didn't mess with that yet).

Essentially, I removed the resolveIncludePaths and added a callback to let the CG virtual filesystem do the work...

Code: Select all

void CgProgram::loadFromSource(void)
    {
                ...
		// deal with includes
		//String sourceToUse = resolveCgIncludes(mSource, this, mFilename);
		String sourceToUse = mSource;
		
		// Add the callback and indicate the context should use the current shader
		// as the loading resource.
		msResourceBeingLoaded = this;
		cgSetCompilerIncludeCallback(mCgContext, &CgProgram::_resourceIncludeCallback);

		// compile the file
        mCgProgram = cgCreateProgram(mCgContext, CG_SOURCE, sourceToUse.c_str(), 
            mSelectedCgProfile, mEntryPoint.c_str(), const_cast<const char**>(mCgArguments));

		// clear the virtual file system and remove the callback
		cgSetCompilerIncludeString(mCgContext, NULL, NULL);
		cgSetCompilerIncludeCallback(mCgContext, NULL);
		msResourceBeingLoaded = NULL;

               ...
    }

Code: Select all

void CgProgram::_resourceIncludeCallback(CGcontext context, const char *fileName)
	{
		String file = fileName;
		// The CG runtime seems to prepend '/' to the virtual filesystem.
		// This is bad for the ogre resource manager.
		// Strip the / if it is there.
		if(file.length() > 0 && file[0] == '/')
			file = file.substr(1);

		// This should never happen, being safe though.
		if(msResourceBeingLoaded == NULL)
			OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Loading resource is null in cg include callback. This shouldn't happen.", __FILE__);

		DataStreamPtr resource = ResourceGroupManager::getSingleton().
			openResource(file, msResourceBeingLoaded->getGroup(), true, msResourceBeingLoaded);

		// check if we found it.
		// Note that CG will fallback on the file system if we failed, which will use compiler options like -I.
		if(!resource.isNull()) {
			cgSetCompilerIncludeString(context, fileName, resource->getAsString().c_str());

			// detect an error if it occured.
			// The only one should be a bad context, which is highly unlikely considering it's the same one.
			CGerror error = cgGetError();
			if(error != CG_NO_ERROR)
				OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, cgGetErrorString(error), __FILE__);
		}
	}
So issues I wanted to ask before submitting a patch:

1) The use of a static variable is necessary (for the resource group and loading resource) and really should be context dependent, but I assume there's one context here and that one thread exists per context. Is that ok? I wish there was a use data type in the API. That variable scares me if multiple threads are loading resources, but I would think that isn't happening based on the context. So as long as cgCreateProgram is only executing on one thread and those lines around it are safe, I shouldn't have to add a mutex.

1b) Can I just pass the default resource group and not pass the loading resource? That would get rid of the static variable, but I don't know if there are side effects since I'm not as familiar with why the loading resource is there.

2) I'm clearing the VFS in Cg for each program. So the include resolution happens per loading high level program. The VFS could actually exist per resource group, but that seemed harder to manage since Cg manages the VFS per context. Is that a good assumption? Note that this way matches how the old resolution works.

3) The use of "/" for their filesystem is kind of a pain in the butt. You have to make sure to include files that are in zip archives as "/Path/In/Zip/file.cg". I don't think this breaks anything though, anyone have any insight? I used to include this stuff as "Path/In/Zip/file.cg", but that makes the current file path prepend to the include file. Using '/' stomps that prepend.

4) Is the CGFX resolution useful or required? I can actually test this since I have some CGFX files causing errors for this reason. I just don't need them for the final zip file.

Thanks!
Fedyakin
Halfling
Posts: 43
Joined: Thu Jul 14, 2005 6:48 pm

Re: CG include issues (with solution)

Post by Fedyakin »

Edit: Your approach is better because resolveCgIncludes will include files that have been excluded using #if.

I encountered the same issue in 1.8 (RC1). I solved it slightly differently by changing resolveCgIncludes to be recursive. Near the end of the function it appends the included source file with the following code around line 756

Code: Select all

// Add #line to the start of the included file to correct the line count
outSource.append("#line 1 \"" + filename + "\"\n");

outSource.append(resource->getAsString());
I changed it to the following

Code: Select all

// Recursively handle includes
String sourceToUse = resolveCgIncludes(resource->getAsString(), resourceBeingLoaded, filename);

// Add #line to the start of the included file to correct the line count
outSource.append("#line 1 \"" + filename + "\"\n");

outSource.append(sourceToUse);
User avatar
sparkprime
Ogre Magi
Posts: 1137
Joined: Mon May 07, 2007 3:43 am
Location: Ossining, New York
x 13

Re: CG include issues (with solution)

Post by sparkprime »

The line numbers problem has been a major headache for me over the years. So I strongly support this.
User avatar
sparkprime
Ogre Magi
Posts: 1137
Joined: Mon May 07, 2007 3:43 am
Location: Ossining, New York
x 13

Re: CG include issues (with solution)

Post by sparkprime »

What happened with this?