Issue with internal not having valid texture ID.

    Oct 29 2010 | 7:23 pm
    I'm squishing bugs in a soon to be released Jitter external, and have an issue I'm trying to understand and fix.
    When our object is initialized we create a new internal object. This is used as an FBO GL_COLOR_ATTACHMENT0 so we can render into it (similar to maybe a slab). Upon the first load of a patch that has our external (lets, uh, call it for fun), all is well, our internal has the dims I specified, has a valid texture ID, etc, and my FBO attachment code works. Yay and stuff. Close the patch, re-open it, and the object exists, has the wrong dims, and the texture ID is 0. Why would instantiating the same patch again cause different behaviour? What is interesting is if I cause the rendering context to be rebuilt via say a fullscreen method, it works. But the initial load does not.
    We create our like so:
    t_jit_gl_syphon_client *jit_gl_syphon_client_new(t_symbol * dest_name)
    	t_jit_gl_syphon_client *jit_gl_syphon_client_instance;
    	// make jit object
    	if (jit_gl_syphon_client_instance = (t_jit_gl_syphon_client *)jit_object_alloc(_jit_gl_syphon_client_class))
    		// TODO : is this right ?
    		// set up attributes
    		jit_attr_setsym(jit_gl_syphon_client_instance->servername, _jit_sym_name, gensym("servername"));
    		jit_attr_setsym(jit_gl_syphon_client_instance->appname, _jit_sym_name, gensym("appname"));
    		jit_gl_syphon_client_instance->needsRedraw = YES;
    		// instantiate a single internal should we need it.
    		jit_gl_syphon_client_instance->output = jit_object_new(ps_jit_gl_texture,dest_name);
    		jit_gl_syphon_client_instance->latestBounds = NSMakeRect(0, 0, 640, 480);
    		if (jit_gl_syphon_client_instance->output)
    			jit_gl_syphon_client_instance->texturename = jit_symbol_unique();		
    			// set texture attributes.
    			jit_attr_setsym(jit_gl_syphon_client_instance->output,_jit_sym_name, jit_gl_syphon_client_instance->texturename);
    			jit_attr_setlong(jit_gl_syphon_client_instance->output,gensym("rectangle"), 1);
    			jit_attr_setlong(jit_gl_syphon_client_instance->output, gensym("flip"), 0);
    			jit_gl_syphon_client_instance->dim[0] = 640;
    			jit_gl_syphon_client_instance->dim[1] = 480;
    			jit_attr_setlong_array(jit_gl_syphon_client_instance->output, _jit_sym_dim, 2, jit_gl_syphon_client_instance->dim);
    			post("error creating internal texture object");
    			jit_object_error((t_object *)jit_gl_syphon_client_instance," could not create texture");
    			jit_gl_syphon_client_instance->texturename = _jit_sym_nothing;
    		// create and attach ob3d
    		jit_ob3d_new(jit_gl_syphon_client_instance, dest_name);
    		jit_gl_syphon_client_instance->syClient = [[SyphonNameboundClient alloc] init];
    		jit_gl_syphon_client_instance = NULL;
    	return jit_gl_syphon_client_instance;
    This is how we handle context destination changed / drawto :
    t_jit_err jit_gl_syphon_client_dest_changed(t_jit_gl_syphon_client *jit_gl_syphon_client_instance)
    	// try and find a context.
    	t_jit_gl_context jit_ctx = 0;
    	// jitter context
    	jit_ctx = jit_gl_get_context();
    	if (jit_gl_syphon_client_instance->output)
    	jit_gl_syphon_client_instance->needsRedraw = YES;
    	return JIT_ERR_NONE;
    t_jit_err jit_gl_syphon_client_drawto(t_jit_gl_syphon_client *jit_gl_syphon_client_instance, t_symbol *s, int argc, t_atom *argv)
    	jit_ob3d_dest_name_set((t_jit_object *)jit_gl_syphon_client_instance, NULL, argc, argv);
    	return JIT_ERR_NONE;
    And in our render method, we do something like (this is snipped, for brevity):
    // clearly we need our texture for this...
    			jit_gl_syphon_client_instance->needsRedraw = NO;
                // where the hell are we?
                CGLContextObj cgl_ctx = CGLGetCurrentContext();            
                //NSLog(@"Jitter render context: %p, CGLContext: %p", jit_gl_get_context(), cgl_ctx);
    			// add texture to OB3D list.
    			jit_attr_setsym(jit_gl_syphon_client_instance,ps_texture, jit_attr_getsym(jit_gl_syphon_client_instance->output, gensym("name")));
                // Bind the Syphon Texture early, so we can base the viewport on the framesize and update our internal texture
                // ahead of rendering.
    			SyphonImage *frame = [client newFrameImageForContext:cgl_ctx];
    			jit_gl_syphon_client_instance->latestBounds.size = [frame textureSize];
    			// we need to update our internal texture to the latest known size of our syphonservers image.
                long newdim[2];			// output dim
    			newdim[0] = jit_gl_syphon_client_instance->latestBounds.size.width;
    			newdim[1] = jit_gl_syphon_client_instance->latestBounds.size.height;
                // update our internal attribute so attr messages work
    			jit_attr_setlong_array(jit_gl_syphon_client_instance, _jit_sym_dim, 2, newdim);
    			// save some state
    			GLint previousFBO;	// make sure we pop out to the right FBO
    			GLint previousReadFBO;
    			GLint previousDrawFBO;
    			GLint previousMatrixMode;
    			glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &previousFBO);
    			glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &previousReadFBO);
    			glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &previousDrawFBO);
    			glGetIntegerv(GL_MATRIX_MODE, &previousMatrixMode);
    			// save texture state, client state, etc.
    			// We are going to bind our FBO to our internal as COLOR_0 attachment
    			// We need the ID, width/height.
    			GLuint texname = jit_attr_getlong(jit_gl_syphon_client_instance->output,ps_glid);
    			GLuint width = jit_attr_getlong(jit_gl_syphon_client_instance->output,ps_width);
    			GLuint height = jit_attr_getlong(jit_gl_syphon_client_instance->output,ps_height);
    			post("texture id is %u width %u height %u", texname, width, height);
    			// FBO generation/attachment to texture
    			GLuint tempFBO;
    			glGenFramebuffers(1, &tempFBO);
    			glBindFramebuffer(GL_FRAMEBUFFER, tempFBO);
    			// it work?
    			GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    			if(status == GL_FRAMEBUFFER_COMPLETE)
    			{ // snipped
    				post(" could not attach to FBO, error:", status);
    Hopefully this is legible in the forum, and makes some sense. What does one have to do when using an internal texture to ensure it is available for use, has a valid internal texture ID and size? Why would loading the same patch at different times cause different behaviours? Is there some caching of objects that maybe is precluding some initialization I may have in the 'wrong' place from running the second time? Are our OB3D api calls correct?
    Thanks very much. once this is squashed, Syphon Public Beta 1 will be available :)

    • Oct 29 2010 | 7:27 pm
      Oh, I should add some more detail perhaps. The first run opening/running of the patch we get valid FBO attachment, and valid dims. The second run through, Texture ID, width and height are all 0, and we error with framebuffer status invalid attachment:
      First opening:
      Jitter 1.7.0 installed
      dumpout: clear
      dumpout: dim 640 480 building GL on window "clientcontext"...
      dumpout: clear
      dumpout: servername
      dumpout: appname Simple Server
      texture id is 1 width 640 height 480
      dumpout: clear
      dumpout: servername
      dumpout: appname Simple Server
      dumpout: dim 640 480 building GL on window "clientcontext"...
      texture id is 0 width 0 height 0 could not attach to FBO, error: 8cd7
      Thanks again for any insight.
    • Oct 30 2010 | 4:52 pm
      Hi Anton,
      The first thing which comes to mind is that the texture has not been bound yet. The texture must be bound at least once while its parent context is valid in order to generate the gpu texture resource (and hence id). The next thing that your message demonstrates is that, unlike the first time, something like a clear message and servername message are happening *before* context creation (and thus texture creation). Any setup or binding code related to that could be the culprit. Hard to know, without more info.
      Let us know how it goes.
    • Nov 02 2010 | 8:12 pm
      Thanks Joshua, binding then immediately unbinding the texture when the context changes fixed it.