Issue with internal jit.gl.texture not having valid texture ID.
Oct 29 2010 | 7:23 pm
Hello.
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 jit.gl.texture object. This jit.gl.texture 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 jit.gl.syphonclient for fun), all is well, our internal jit.gl.texture 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 jit.gl.texture 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 jit.gl.syphonclient 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 jit.gl.texture 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_setsym(jit_gl_syphon_client_instance->output,gensym("defaultimage"),gensym("black")); 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); } else { post("error creating internal texture object"); jit_object_error((t_object *)jit_gl_syphon_client_instance,"jit.gl.syphonserver: 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]; } else { 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_attr_setsym(jit_gl_syphon_client_instance->output,ps_drawto,jit_attr_getsym(jit_gl_syphon_client_instance,ps_drawto)); 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) { object_attr_setvalueof(jit_gl_syphon_client_instance->output,s,argc,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... if(jit_gl_syphon_client_instance->output) { jit_gl_syphon_client_instance->needsRedraw = NO; // where the hell are we? jit_ob3d_set_context(jit_gl_syphon_client_instance); 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. glPushAttrib(GL_ALL_ATTRIB_BITS); glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); // We are going to bind our FBO to our internal jit.gl.texture 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); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, texname, 0); // it work? GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if(status == GL_FRAMEBUFFER_COMPLETE) { // snipped } else { post("jit.gl.syphonclient could not attach to FBO, error: %xjit.gl.syphonclient.mxo", 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 :)