void CQuad::draw() { CHECK_GLERROR(""); glBegin(GL_QUADS); glMultiTexCoord2fARB(GL_TEXTURE0_ARB,u0, v0); glVertex2f(x0, y0); glMultiTexCoord2fARB(GL_TEXTURE0_ARB,u0, v1); glVertex2f(x0, y1); glMultiTexCoord2fARB(GL_TEXTURE0_ARB,u1, v1); glVertex2f(x1, y1); glMultiTexCoord2fARB(GL_TEXTURE0_ARB,u1, v0); glVertex2f(x1, y0); glEnd(); CHECK_GLERROR(""); }
// Initialize the runtime, in particular all fields in halide_opengl_state. EXPORT int halide_opengl_init(void *user_context) { if (ST.initialized) return 0; // Make a context if there isn't one if (halide_opengl_create_context(user_context)) { halide_printf(user_context, "Failed to make opengl context\n"); return 1; } // Initialize pointers to OpenGL functions. #define GLFUNC(TYPE, VAR) \ ST.VAR = (TYPE)halide_opengl_get_proc_address(user_context, "gl" #VAR); \ if (!ST.VAR) { \ halide_printf(user_context, "Could not load function pointer for %s\n", "gl" #VAR); \ return 1; \ } USED_GL_FUNCTIONS; #undef GLFUNC ST.kernels = NULL; ST.textures = NULL; // Initialize all OpenGL objects that are shared between kernels. ST.GenFramebuffers(1, &ST.framebuffer_id); CHECK_GLERROR(1); ST.vertex_shader_id = halide_opengl_make_shader(user_context, GL_VERTEX_SHADER, vertex_shader_src, NULL); if (ST.vertex_shader_id == 0) { halide_error(user_context, "Failed to create vertex shader"); return 1; } GLuint buf; ST.GenBuffers(1, &buf); ST.BindBuffer(GL_ARRAY_BUFFER, buf); ST.BufferData(GL_ARRAY_BUFFER, sizeof(square_vertices), square_vertices, GL_STATIC_DRAW); CHECK_GLERROR(1); ST.vertex_buffer = buf; ST.GenBuffers(1, &buf); ST.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf); ST.BufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(square_indices), square_indices, GL_STATIC_DRAW); CHECK_GLERROR(1); ST.element_buffer = buf; ST.initialized = true; return 0; }
inline bool CShader::set<float>( const std::string & pName, const float & v) const { const GLint iP= getParamLocation(pName); if (iP < 0) return false; glUniform1f(iP, static_cast<GLfloat>(v));CHECK_GLERROR(""); return true; }
inline bool CShader::set<float>( const std::string & pName, const float & v0, const float & v1 ) const { const GLint iP= getParamLocation(pName); if (iP < 0) return false; glUniform2f(iP, v0, v1);CHECK_GLERROR(""); return true; }
inline bool CShader::setArray<CVector4i>( const std::string & pName, int count, const CVector4i * v) const { const GLint iP= getParamLocation(pName); if (iP < 0) return false; glUniform4iv(iP, static_cast<const GLint>(count), (const GLint*)(v));CHECK_GLERROR(""); return true; }
inline bool CShader::set<int>( const std::string & pName, const int & v0, const int & v1, const int & v2, const int & v3 ) const { const GLint iP= getParamLocation(pName); if (iP < 0) return false; glUniform4i(iP, v0, v1, v2, v3);CHECK_GLERROR(""); return true; }
// Delete all texture information associated with a buffer. The OpenGL texture // itself is only deleted if it was actually allocated by Halide and not // provided by the host application. EXPORT int halide_opengl_dev_free(void *user_context, buffer_t *buf) { CHECK_INITIALIZED(1); GLuint tex = get_texture_id(buf); if (tex == 0) { return 0; } // Look up corresponding HalideOpenGLTexture and unlink it from the list. HalideOpenGLTexture **ptr = &ST.textures; HalideOpenGLTexture *texinfo = *ptr; for (; texinfo != NULL; ptr = &texinfo->next, texinfo = *ptr) { if (texinfo->id == tex) { *ptr = texinfo->next; texinfo->next = NULL; break; } } if (!texinfo) { halide_error(user_context, "Internal error: texture not found"); return 1; } // Delete texture if it was allocated by us. if (texinfo->halide_allocated) { ST.DeleteTextures(1, &tex); CHECK_GLERROR(1); buf->dev = 0; } free(texinfo); return 0; }
void App::printInfo() { #define PRINT(x) { printf( "%s\t\"%s\"\n", #x, (char*)glGetString(x) ); } PRINT( GL_RENDERER ); PRINT( GL_VERSION ); PRINT( GL_VENDOR ); PRINT( GL_SHADING_LANGUAGE_VERSION ); //PRINT( GL_EXTENSIONS ); #undef PRINT #define PRINT(x) { GLint i=0; glGetIntegerv(x,&i); printf( "%s\t%d\n", #x, i ); } PRINT( GL_DEPTH_BITS ); PRINT( GL_STENCIL_BITS ); //PRINT( GL_MAX_MODELVIEW_STACK_DEPTH ); //PRINT( GL_MAX_PROJECTION_STACK_DEPTH ); PRINT( GL_MAX_TEXTURE_SIZE ); #undef PRINT CHECK_GLERROR( "App::printInfo" ); #define PRINT(x) printf( "%s\t%d\n", #x, static_cast<int>(x) ); //PRINT( sizeof(Viewer) ); //PRINT( sizeof(Camera) ); #undef PRINT }
void App::draw() { if( _needUpdate ) update(); setTime( getElapsedTime() ); // [seconds] _scene->animate( *this, _config ); _viewer->frame( *_scene ); CHECK_GLERROR( "App::draw" ); updateStats(); }
bool App::create( int argc, char** argv ) { const char* configFilename = APP_NAME "_config.txt"; switch( argc ) { case 1: // use default configFilename break; case 2: configFilename = argv[1]; break; default: // print usage printf( "\nusage: %s [configFilename]\n\n", argv[0] ); return false; } char cwd[512]; if( getcwd( cwd, sizeof(cwd)-1 ) == NULL ) cwd[0] = '\0'; printf( "CWD\t\"%s\"\n", cwd ); printf( "configFilename\t\"%s\"\n", configFilename ); _config.create( configFilename ); registerLuaFunctions(); if( ! _config.loadFile() ) return false; printf( "instanceName\t\"%s\"\n", _instanceName.c_str() ); if( ! createGlSurface() ) return false; // now an OpenGL context exists _viewer = Viewer::factory( Viewer::getType( _config ) ); _scene = Scene::factory( Scene::getType( _config ) ); CHECK_GLERROR( "App::create" ); printInfo(); printf( "\n" ); resetStats(); return true; }
// Release all data allocated by the runtime. // // The OpenGL context itself is generally managed by the host application, so // we leave it untouched. EXPORT void halide_opengl_release(void *user_context) { CHECK_INITIALIZED(); ST.DeleteShader(ST.vertex_shader_id); ST.DeleteFramebuffers(1, &ST.framebuffer_id); HalideOpenGLKernel *cur = ST.kernels; while (cur) { HalideOpenGLKernel *next = cur->next; halide_opengl_delete_kernel(user_context, cur); cur = next; } // Delete all textures that were allocated by us. HalideOpenGLTexture *tex = ST.textures; int freed_textures = 0; while (tex) { HalideOpenGLTexture *next = tex->next; if (tex->halide_allocated) { ST.DeleteTextures(1, &tex->id); CHECK_GLERROR(); freed_textures++; } free(tex); tex = next; } #ifdef DEBUG if (freed_textures > 0) { halide_printf(user_context, "halide_opengl_release: deleted %d dangling texture(s).\n", freed_textures); } #endif ST.DeleteBuffers(1, &ST.vertex_buffer); ST.DeleteBuffers(1, &ST.element_buffer); ST.vertex_shader_id = 0; ST.framebuffer_id = 0; ST.vertex_buffer = 0; ST.element_buffer = 0; ST.kernels = NULL; ST.textures = NULL; ST.initialized = false; }
inline bool CShader::set<CVector2i>( const std::string & pName, const CVector2i & v) const { return set<int>(pName, v[0], v[1]); CHECK_GLERROR(""); }
inline bool CShader::set<CVector3f>( const std::string & pName, const CVector3f & v) const { return set<float>(pName, v[0], v[1], v[2]); CHECK_GLERROR(""); }
EXPORT int halide_opengl_dev_run( void *user_context, void *state_ptr, const char *entry_name, int blocksX, int blocksY, int blocksZ, int threadsX, int threadsY, int threadsZ, int shared_mem_bytes, size_t arg_sizes[], void *args[]) { CHECK_INITIALIZED(1); HalideOpenGLKernel *kernel = halide_opengl_find_kernel(entry_name); if (!kernel) { halide_printf(user_context, "Could not find a kernel named '%s'\n", entry_name); return 1; } ST.UseProgram(kernel->program_id); HalideOpenGLArgument *kernel_arg; // Copy input arguments to corresponding GLSL uniforms. GLint num_active_textures = 0; kernel_arg = kernel->arguments; for (int i = 0; args[i]; i++, kernel_arg = kernel_arg->next) { if (!kernel_arg) { halide_printf(user_context, "Argument %d: size=%d value=%p\n", i, arg_sizes[i], args[i]); halide_error(user_context, "Too many arguments passed to halide_opengl_dev_run"); return 1; } if (kernel_arg->kind == ARGKIND_OUTBUF) { // Outbuf textures are handled explicitly below continue; } else if (kernel_arg->kind == ARGKIND_INBUF) { GLint loc = ST.GetUniformLocation(kernel->program_id, kernel_arg->name); if (loc == -1) { halide_error(user_context, "No sampler defined for input texture.\n"); return 1; } GLuint tex = *((GLuint *)args[i]); ST.ActiveTexture(GL_TEXTURE0 + num_active_textures); ST.BindTexture(GL_TEXTURE_2D, tex); ST.Uniform1iv(loc, 1, &num_active_textures); num_active_textures++; // TODO: check maximum number of active textures } else if (kernel_arg->kind == ARGKIND_VAR) { GLint loc = ST.GetUniformLocation(kernel->program_id, kernel_arg->name); if (loc == -1) { // Argument was probably optimized away by GLSL compiler. #ifdef DEBUG halide_printf(user_context, "Ignoring argument '%s'\n", kernel_arg->name); #endif continue; } switch (kernel_arg->type) { case ARGTYPE_INT: #ifdef DEBUG halide_printf(user_context, "Int argument %d (%s): %d\n", i, kernel_arg->name, *((int *)args[i])); #endif ST.Uniform1iv(loc, 1, (GLint *)args[i]); break; case ARGTYPE_FLOAT: { #ifdef DEBUG halide_printf(user_context, "Float argument %d (%s): %g\n", i, kernel_arg->name, *((float *)args[i])); #endif ST.Uniform1fv(loc, 1, (GLfloat *)args[i]); break; } case ARGTYPE_NONE: default: halide_error(user_context, "Unknown kernel argument type"); return 1; } } } if (kernel_arg) { halide_error(user_context, "Too few arguments passed to halide_opengl_dev_run"); return 1; } // Prepare framebuffer for rendering to output textures. GLint output_min[2] = { 0, 0 }; GLint output_extent[2] = { 0, 0 }; ST.BindFramebuffer(GL_FRAMEBUFFER, ST.framebuffer_id); ST.Disable(GL_CULL_FACE); ST.Disable(GL_DEPTH_TEST); GLint num_output_textures = 0; kernel_arg = kernel->arguments; for (int i = 0; args[i]; i++, kernel_arg = kernel_arg->next) { if (kernel_arg->kind != ARGKIND_OUTBUF) continue; // TODO: GL_MAX_COLOR_ATTACHMENTS if (num_output_textures >= 1) { halide_error(user_context, "OpenGL ES 2.0 only supports one single output texture"); return 1; } GLuint tex = *((GLuint*)args[i]); #ifdef DEBUG halide_printf(user_context, "Output texture %d: %d\n", num_output_textures, tex); #endif ST.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + num_output_textures, GL_TEXTURE_2D, tex, 0); CHECK_GLERROR(1); HalideOpenGLTexture *texinfo = halide_opengl_find_texture(tex); if (!texinfo) { halide_error(user_context, "Undefined output texture"); return 1; } output_min[0] = texinfo->min[0]; output_min[1] = texinfo->min[1]; output_extent[0] = texinfo->extent[0]; output_extent[1] = texinfo->extent[1]; num_output_textures++; } // TODO: GL_MAX_DRAW_BUFFERS if (num_output_textures == 0) { halide_printf(user_context, "Warning: kernel '%s' has no output\n", kernel->name); // TODO: cleanup return 1; } else { GLenum *draw_buffers = (GLenum*) malloc(num_output_textures * sizeof(GLenum)); for (int i=0; i<num_output_textures; i++) draw_buffers[i] = GL_COLOR_ATTACHMENT0 + i; ST.DrawBuffers(num_output_textures, draw_buffers); CHECK_GLERROR(1); free(draw_buffers); } // Check that framebuffer is set up correctly GLenum status = ST.CheckFramebufferStatus(GL_FRAMEBUFFER); CHECK_GLERROR(1); if (status != GL_FRAMEBUFFER_COMPLETE) { halide_printf(user_context, "Setting up GL framebuffer %d failed (%x)\n", ST.framebuffer_id, status); // TODO: cleanup return 1; } // Set vertex attributes GLint loc = ST.GetUniformLocation(kernel->program_id, "output_extent"); ST.Uniform2iv(loc, 1, output_extent); CHECK_GLERROR(1); loc = ST.GetUniformLocation(kernel->program_id, "output_min"); ST.Uniform2iv(loc, 1, output_min); CHECK_GLERROR(1); // Setup viewport ST.Viewport(0, 0, output_extent[0], output_extent[1]); // Execute shader GLint position = ST.GetAttribLocation(kernel->program_id, "position"); ST.BindBuffer(GL_ARRAY_BUFFER, ST.vertex_buffer); ST.VertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, // normalized? sizeof(GLfloat)*2, NULL); ST.EnableVertexAttribArray(position); ST.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ST.element_buffer); ST.DrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, NULL); CHECK_GLERROR(1); ST.DisableVertexAttribArray(position); // Cleanup for (int i = 0; i < num_active_textures; i++) { ST.ActiveTexture(GL_TEXTURE0 + i); ST.BindTexture(GL_TEXTURE_2D, 0); } ST.BindFramebuffer(GL_FRAMEBUFFER, 0); return 0; }
// Copy image data from texture back to host memory. EXPORT int halide_opengl_copy_to_host(void *user_context, buffer_t *buf) { CHECK_INITIALIZED(1); if (!buf->dev_dirty) { return 0; } if (!buf->host || !buf->dev) { #ifdef DEBUG print_buffer(user_context, buf); #endif halide_error(user_context, "Invalid copy_to_host operation"); return 1; } GLuint tex = get_texture_id(buf); #ifdef DEBUG halide_printf(user_context, "halide_copy_to_host: %d\n", tex); #endif GLint format; GLint type; if (!get_texture_format(user_context, buf, &format, &type)) { halide_error(user_context, "Invalid texture format\n"); return 1; } GLint width = buf->extent[0]; GLint height = buf->extent[1]; ST.BindTexture(GL_TEXTURE_2D, tex); CHECK_GLERROR(1); bool is_interleaved = (buf->stride[2] == 1 && buf->stride[0] == buf->extent[2]); if (is_interleaved) { // TODO: GL_UNPACK_ROW_LENGTH ST.PixelStorei(GL_PACK_ROW_LENGTH, buf->extent[1]); ST.PixelStorei(GL_PACK_ALIGNMENT, 1); ST.GetTexImage(GL_TEXTURE_2D, 0, format, type, buf->host); CHECK_GLERROR(1); } else { #ifdef DEBUG halide_printf(user_context, "Warning: In copy_to_host, host buffer is not interleaved. Doing slow deinterleave.\n"); #endif size_t size = width * height * buf->extent[2] * buf->elem_size; uint8_t *tmp = (uint8_t*)halide_malloc(user_context, size); ST.PixelStorei(GL_PACK_ALIGNMENT, 1); ST.GetTexImage(GL_TEXTURE_2D, 0, format, type, tmp); CHECK_GLERROR(1); switch (type) { case GL_UNSIGNED_BYTE: interleaved_to_halide<uint8_t>(buf, (uint8_t*)tmp, width, height, buf->extent[2]); break; case GL_UNSIGNED_SHORT: interleaved_to_halide<uint16_t>(buf, (uint16_t*)tmp, width, height, buf->extent[2]); break; case GL_FLOAT: interleaved_to_halide<float>(buf, (float*)tmp, width, height, buf->extent[2]); break; } halide_free(user_context, tmp); } ST.BindTexture(GL_TEXTURE_2D, 0); buf->dev_dirty = false; return 0; }
// Allocate a new texture matching the dimension and color format of the // specified buffer. EXPORT int halide_opengl_dev_malloc(void *user_context, buffer_t *buf) { if (int error = halide_opengl_init(user_context)) return error; if (!buf) { halide_error(user_context, "Invalid buffer"); return 1; } // If the texture was already created by the host application, check that // it has the correct format. Otherwise, allocate and set up an // appropriate texture. GLuint tex = get_texture_id(buf); bool halide_allocated = false; GLint format = 0; GLint width, height; if (tex != 0) { ST.BindTexture(GL_TEXTURE_2D, tex); ST.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); ST.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height); CHECK_GLERROR(1); if (width < buf->extent[0] || height < buf->extent[1]) { #ifdef DEBUG halide_printf(user_context, "Texture size: %dx%d, buffer size: %dx%d\n", width, height, buf->extent[0], buf->extent[1]); #endif halide_error(user_context, "Existing texture is smaller than buffer"); return 1; } } else { if (buf->extent[3] > 1) { halide_error(user_context, "3D textures are not supported"); return 1; } // Generate texture ID ST.GenTextures(1, &tex); CHECK_GLERROR(1); // Set parameters for this texture: no interpolation and clamp to edges. ST.BindTexture(GL_TEXTURE_2D, tex); ST.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); ST.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); ST.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); ST.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); CHECK_GLERROR(1); // Create empty texture here and fill it with glTexSubImage2D later. GLint type = GL_UNSIGNED_BYTE; if (!get_texture_format(user_context, buf, &format, &type)) { halide_error(user_context, "Invalid texture format\n"); return 1; } width = buf->extent[0]; height = buf->extent[1]; ST.TexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, NULL); CHECK_GLERROR(1); buf->dev = tex; halide_allocated = true; #ifdef DEBUG halide_printf(user_context, "Allocated texture %d of size %d x %d\n", tex, width, height); #endif ST.BindTexture(GL_TEXTURE_2D, 0); } // Record main information about texture and remember it for later. In // halide_opengl_dev_run we are only given the texture ID and not the full // buffer_t, so we copy the interesting information here. HalideOpenGLTexture *texinfo = (HalideOpenGLTexture*) malloc(sizeof(HalideOpenGLTexture)); texinfo->id = tex; for (int i=0; i<3; i++) { texinfo->min[i] = buf->min[i]; texinfo->extent[i] = buf->extent[i]; } texinfo->format = format; texinfo->halide_allocated = halide_allocated; texinfo->next = ST.textures; ST.textures = texinfo; return 0; }