/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "src/pixelflinger2/pixelflinger2.h" #include <assert.h> #include <stdio.h> #include <string.h> #include <map> #include <llvm/LLVMContext.h> #include <llvm/Module.h> #include <bcc/bcc.h> #include <dlfcn.h> #include "src/talloc/hieralloc.h" #include "src/mesa/main/shaderobj.h" #include "src/mesa/program/prog_parameter.h" #include "src/mesa/program/prog_uniform.h" #include "src/glsl/glsl_types.h" #include "src/glsl/ir_to_llvm.h" #include "src/glsl/ir_print_visitor.h" //#undef LOGD //#define LOGD(...) static void InitializeGLContext(struct gl_context *ctx) { memset(ctx, 0, sizeof(*ctx)); ctx->API = API_OPENGLES2; ctx->Extensions.ARB_draw_buffers = GL_TRUE; ctx->Extensions.ARB_fragment_coord_conventions = GL_TRUE; ctx->Extensions.EXT_texture_array = GL_TRUE; ctx->Extensions.NV_texture_rectangle = GL_TRUE; /* 1.10 minimums. */ ctx->Const.MaxLights = 8; ctx->Const.MaxClipPlanes = 8; ctx->Const.MaxTextureUnits = 2; /* More than the 1.10 minimum to appease parser tests taken from * apps that (hopefully) already checked the number of coords. */ ctx->Const.MaxTextureCoordUnits = 4; ctx->Const.VertexProgram.MaxAttribs = 16; ctx->Const.VertexProgram.MaxUniformComponents = 512; ctx->Const.MaxVarying = 8; ctx->Const.MaxVertexTextureImageUnits = 0; ctx->Const.MaxCombinedTextureImageUnits = 2; ctx->Const.MaxTextureImageUnits = 2; ctx->Const.FragmentProgram.MaxUniformComponents = 64; ctx->Const.MaxDrawBuffers = 2; } void * llvmCtx = NULL; static const struct GLContext { const gl_context * ctx; GLContext() { ctx = hieralloc_zero(NULL, gl_context); // ctx = (const gl_context*)calloc(1,sizeof(gl_context)); InitializeGLContext(const_cast<gl_context *>(ctx)); llvmCtx = new llvm::LLVMContext(); } ~GLContext() { _mesa_glsl_release_types(); // TODO: find when to release to minize memory _mesa_glsl_release_functions(); // the IR has pointers to types hieralloc_free(const_cast<gl_context *>(ctx)); // free(const_cast<gl_context *>(ctx)); ctx = NULL; delete (llvm::LLVMContext *)llvmCtx; } } glContext; extern "C" void GLContextDctr() { _mesa_glsl_release_types(); // TODO: find when to release to minize memory _mesa_glsl_release_functions(); //glContext.~GLContext(); } struct ShaderKey { struct ScanLineKey { GGLStencilState frontStencil, backStencil; GGLBufferState bufferState; GGLBlendState blendState; } scanLineKey; GGLPixelFormat textureFormats[GGL_MAXCOMBINEDTEXTUREIMAGEUNITS]; unsigned char textureParameters[GGL_MAXCOMBINEDTEXTUREIMAGEUNITS]; // wrap and filter bool operator <(const ShaderKey & rhs) const { return memcmp(this, &rhs, sizeof(*this)) < 0; } }; struct Instance { llvm::Module * module; struct BCCOpaqueScript * script; void (* function)(); ~Instance() { // TODO: check bccDisposeScript, which seems to dispose llvm::Module if (script) bccDisposeScript(script); else if (module) delete module; } }; struct Executable { // codegen info std::map<ShaderKey, Instance *> instances; }; bool do_mat_op_to_vec(exec_list *instructions); extern void link_shaders(const struct gl_context *ctx, struct gl_shader_program *prog); extern "C" void compile_shader(const struct gl_context *ctx, struct gl_shader *shader); gl_shader * GGLShaderCreate(GLenum type) { return _mesa_new_shader(NULL, 0, type); } static gl_shader * ShaderCreate(const GGLInterface * iface, GLenum type) { GGL_GET_CONST_CONTEXT(ctx, iface); if (GL_VERTEX_SHADER != type && GL_FRAGMENT_SHADER != type) { gglError(GL_INVALID_ENUM); return NULL; } gl_shader * shader = _mesa_new_shader(NULL, 0, type); if (!shader) gglError(GL_OUT_OF_MEMORY); assert(1 == shader->RefCount); return shader; } void GGLShaderSource(gl_shader_t * shader, GLsizei count, const char ** string, const int * length) { hieralloc_free(const_cast<GLchar *>(shader->Source)); for (unsigned i = 0; i < count; i++) { int len = strlen(string[i]); if (length && length[i] >= 0) len = length[i]; shader->Source = hieralloc_strndup_append(const_cast<GLchar *>(shader->Source), string[i], len); } // LOGD("pf2: GGLShaderSource: \n '%s' \n", shader->Source); } GLboolean GGLShaderCompile(gl_shader * shader, const char * glsl, const char ** infoLog) { if (glsl) shader->Source = glsl; assert(shader->Source); compile_shader(glContext.ctx, shader); if (glsl) shader->Source = NULL; if (infoLog) *infoLog = shader->InfoLog; return shader->CompileStatus; } static GLboolean ShaderCompile(const GGLInterface * iface, gl_shader * shader, const char * glsl, const char ** infoLog) { GGL_GET_CONST_CONTEXT(ctx, iface); if (!glsl && !shader->Source) { gglError(GL_INVALID_VALUE); assert(0); return GL_FALSE; } return GGLShaderCompile(shader, glsl, infoLog); } void GGLShaderDelete(gl_shader * shader) { if (shader && shader->executable) { for (std::map<ShaderKey, Instance *>::iterator it=shader->executable->instances.begin(); it != shader->executable->instances.end(); it++) (*it).second->~Instance(); shader->executable->instances.~map(); } _mesa_delete_shader(NULL, shader); } static void ShaderDelete(const GGLInterface * iface, gl_shader * shader) { GGLShaderDelete(shader); } gl_shader_program * GGLShaderProgramCreate() { gl_shader_program * program = hieralloc_zero(NULL, struct gl_shader_program); if (!program) return NULL; program->Attributes = hieralloc_zero(program, gl_program_parameter_list); if (!program->Attributes) { hieralloc_free(program); return NULL; } program->Varying = hieralloc_zero(program, gl_program_parameter_list); if (!program->Varying) { hieralloc_free(program); return NULL; } return program; } static gl_shader_program * ShaderProgramCreate(const GGLInterface * iface) { GGL_GET_CONST_CONTEXT(ctx, iface); gl_shader_program * program = GGLShaderProgramCreate(); if (!program) gglError(GL_OUT_OF_MEMORY); return program; } unsigned GGLShaderAttach(gl_shader_program * program, gl_shader * shader) { for (unsigned i = 0; i < program->NumShaders; i++) if (program->Shaders[i]->Type == shader->Type || program->Shaders[i] == shader) return GL_INVALID_OPERATION; program->Shaders = (gl_shader **)hieralloc_realloc (program, program->Shaders, gl_shader *, program->NumShaders + 1); if (!program->Shaders) { assert(0); return GL_OUT_OF_MEMORY; } program->Shaders[program->NumShaders] = shader; program->NumShaders++; shader->RefCount++; return GL_NO_ERROR; } static void ShaderAttach(const GGLInterface * iface, gl_shader_program * program, gl_shader * shader) { unsigned error = GGLShaderAttach(program, shader); if (GL_NO_ERROR != error) gglError(error); } GLboolean GGLShaderProgramLink(gl_shader_program * program, const char ** infoLog) { link_shaders(glContext.ctx, program); if (infoLog) *infoLog = program->InfoLog; if (!program->LinkStatus) return program->LinkStatus; LOGD("slots: attribute=%d varying=%d uniforms=%d \n", program->AttributeSlots, program->VaryingSlots, program->Uniforms->Slots); // for (unsigned i = 0; i < program->Attributes->NumParameters; i++) { // const gl_program_parameter & attribute = program->Attributes->Parameters[i]; // LOGD("attribute '%s': location=%d slots=%d \n", attribute.Name, attribute.Location, attribute.Slots); // } // for (unsigned i = 0; i < program->Varying->NumParameters; i++) { // const gl_program_parameter & varying = program->Varying->Parameters[i]; // LOGD("varying '%s': vs_location=%d fs_location=%d \n", varying.Name, varying.BindLocation, varying.Location); // } for (unsigned i = 0; i < program->Uniforms->NumUniforms; i++) { const gl_uniform & uniform = program->Uniforms->Uniforms[i]; LOGD("uniform '%s': location=%d type=%s \n", uniform.Name, uniform.Pos, uniform.Type->name); } return program->LinkStatus; } static GLboolean ShaderProgramLink(gl_shader_program * program, const char ** infoLog) { return GGLShaderProgramLink(program, infoLog); } static void GetShaderKey(const GGLState * ctx, const gl_shader * shader, ShaderKey * key) { memset(key, 0, sizeof(*key)); if (GL_FRAGMENT_SHADER == shader->Type) { key->scanLineKey.frontStencil = ctx->frontStencil; key->scanLineKey.backStencil = ctx->backStencil; key->scanLineKey.bufferState = ctx->bufferState; key->scanLineKey.blendState = ctx->blendState; } for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++) if (shader->SamplersUsed & (1 << i)) { const GGLTexture & texture = ctx->textureState.textures[i]; key->textureFormats[i] = texture.format; assert((1 << 2) > texture.wrapS); key->textureParameters[i] |= texture.wrapS; assert((1 << 2) > texture.wrapT); key->textureParameters[i] |= texture.wrapT << 2; assert((1 << 3) > texture.minFilter); key->textureParameters[i] |= texture.minFilter << (2 + 2); assert((1 << 1) > texture.magFilter); key->textureParameters[i] |= texture.magFilter << (2 + 2 + 3); } } static inline char HexDigit(unsigned char d) { return (d > 9 ? d + 'A' - 10 : d + '0'); } static const unsigned SHADER_KEY_STRING_LEN = GGL_MAXCOMBINEDTEXTUREIMAGEUNITS * 4 + 2; static void GetShaderKeyString(const GLenum type, const ShaderKey * key, char * buffer, const unsigned bufferSize) { assert(1 == sizeof(char)); assert(0xff >= GGL_PIXEL_FORMAT_COUNT); assert(SHADER_KEY_STRING_LEN <= bufferSize); char * str = buffer; if (GL_VERTEX_SHADER == type) *str++ = 'v'; else if (GL_FRAGMENT_SHADER == type) *str++ = 'f'; else assert(0); for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++) { *str++ = HexDigit(key->textureFormats[i] / 16); *str++ = HexDigit(key->textureFormats[i] % 16); *str++ = HexDigit(key->textureParameters[i] / 16); *str++ = HexDigit(key->textureParameters[i] % 16); } *str++ = '\0'; } static const unsigned SCANLINE_KEY_STRING_LEN = 2 * sizeof(ShaderKey::ScanLineKey) + 3 + SHADER_KEY_STRING_LEN; static char * GetScanlineKeyString(const ShaderKey * key, char * buffer, const unsigned bufferSize) { assert(1 == sizeof(char)); assert(0xff >= GGL_PIXEL_FORMAT_COUNT); assert(SCANLINE_KEY_STRING_LEN <= bufferSize); char * str = buffer; *str++ = 's'; const unsigned char * start = (const unsigned char *)&key->scanLineKey; const unsigned char * const end = start + sizeof(key->scanLineKey); for (; start < end; start++) { *str++ = HexDigit(*start / 16); *str++ = HexDigit(*start % 16); } GetShaderKeyString(GL_FRAGMENT_SHADER, key, str, bufferSize - (str - buffer)); return buffer; } struct SymbolLookupContext { const GGLState * gglCtx; const gl_shader_program * program; const gl_shader * shader; }; static void* SymbolLookup(void* pContext, const char* name) { SymbolLookupContext * ctx = (SymbolLookupContext *)pContext; const GGLState * gglCtx = ctx->gglCtx; const void * symbol = (void*)dlsym(RTLD_DEFAULT, name); if (NULL == symbol) { if (!strcmp(_PF2_TEXTURE_DATA_NAME_, name)) symbol = (void *)gglCtx->textureState.textureData; else if (!strcmp(_PF2_TEXTURE_DIMENSIONS_NAME_, name)) symbol = (void *)gglCtx->textureState.textureDimensions; else // attributes, varyings and uniforms are mapped to locations in pointers { LOGD("pf2: SymbolLookup unknown symbol: '%s'", name); assert(0); } } // printf("symbolLookup '%s'=%p \n", name, symbol); assert(symbol); return (void *)symbol; } static void CodeGen(Instance * instance, const char * mainName, gl_shader * shader, gl_shader_program * program, const GGLState * gglCtx) { SymbolLookupContext ctx = {gglCtx, program, shader}; int result = 0; // instance->module->dump(); BCCScriptRef & script = instance->script; script = bccCreateScript(); result = bccReadModule(script, "glsl", (LLVMModuleRef)instance->module, 0); assert(0 == result); result = bccRegisterSymbolCallback(script, SymbolLookup, &ctx); assert(0 == result); result = bccPrepareExecutable(script, NULL, NULL, 0); result = bccGetError(script); if (result != 0) { LOGD("failed bcc_compile"); assert(0); return; } instance->function = (void (*)())bccGetFuncAddr(script, mainName); assert(instance->function); result = bccGetError(script); if (result != BCC_NO_ERROR) LOGD("Could not find '%s': %d\n", mainName, result); // else // printf("bcc_compile %s=%p \n", mainName, instance->function); // assert(0); } void GenerateScanLine(const GGLState * gglCtx, const gl_shader_program * program, llvm::Module * mod, const char * shaderName, const char * scanlineName); void GGLShaderUse(void * llvmCtx, const GGLState * gglState, gl_shader_program * program) { // LOGD("%s", program->Shaders[MESA_SHADER_FRAGMENT]->Source); for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) { if (!program->_LinkedShaders[i]) continue; gl_shader * shader = program->_LinkedShaders[i]; shader->function = NULL; if (!shader->executable) { shader->executable = hieralloc_zero(shader, Executable); shader->executable->instances = std::map<ShaderKey, Instance *>(); } ShaderKey shaderKey; GetShaderKey(gglState, shader, &shaderKey); Instance * instance = shader->executable->instances[shaderKey]; if (!instance) { // puts("begin jit new shader"); instance = hieralloc_zero(shader->executable, Instance); instance->module = new llvm::Module("glsl", *(llvm::LLVMContext *)llvmCtx); char shaderName [SHADER_KEY_STRING_LEN] = {0}; GetShaderKeyString(shader->Type, &shaderKey, shaderName, sizeof shaderName / sizeof *shaderName); char mainName [SHADER_KEY_STRING_LEN + 6] = {"main"}; strcat(mainName, shaderName); do_mat_op_to_vec(shader->ir); // TODO: move these passes to link? //#ifdef __arm__ // static const char fileName[] = "/data/pf2.txt"; // FILE * file = freopen(fileName, "w", stdout); // assert(file); // *stdout = *file; // std::ios_base::sync_with_stdio(true); //#endif // _mesa_print_ir(shader->ir, NULL); //#ifdef __arm__ // fclose(file); // file = fopen(fileName, "r"); // assert(file); // static char str[256]; // while (!feof(file)) { // fgets(str, sizeof(str) - 1, file); // str[sizeof(str) - 1] = 0; // LOGD("%s", str); // } // fclose(file); //#endif llvm::Module * module = glsl_ir_to_llvm_module(shader->ir, instance->module, gglState, shaderName); if (!module) assert(0); //#ifdef __arm__ // static const char fileName[] = "/data/pf2.txt"; // FILE * file = freopen(fileName, "w", stderr); // assert(file); // *stderr = *file; // std::ios_base::sync_with_stdio(true); //#endif // if (strstr(program->Shaders[MESA_SHADER_FRAGMENT]->Source, // "gl_FragColor = color * texture2D(sampler, outTexCoords).a;")) { // if (i == MESA_SHADER_VERTEX) { // for (unsigned i = 0; i < program->Attributes->NumParameters; i++) { // const gl_program_parameter & attribute = program->Attributes->Parameters[i]; // LOGD("attribute '%s': location=%d slots=%d \n", attribute.Name, attribute.Location, attribute.Slots); // } // for (unsigned i = 0; i < program->Varying->NumParameters; i++) { // const gl_program_parameter & varying = program->Varying->Parameters[i]; // LOGD("varying '%s': vs_location=%d fs_location=%d \n", varying.Name, varying.BindLocation, varying.Location); // } // LOGD("%s", program->Shaders[MESA_SHADER_VERTEX]->Source); // module->dump(); // } // } //#ifdef __arm__ // fputs("end of bcc disassembly", stderr); // fclose(stderr); // // file = fopen(fileName, "r"); // assert(file); // fseek(file , 0 , SEEK_END); // long lSize = ftell(file); // rewind(file); // assert(0 <= lSize); // static char str[256]; // while (!feof(file)) { // fgets(str, sizeof(str) - 1, file); // str[sizeof(str) - 1] = 0; // LOGD("%s", str); // } // fclose(file); //#endif #if USE_LLVM_SCANLINE if (GL_FRAGMENT_SHADER == shader->Type) { char scanlineName [SCANLINE_KEY_STRING_LEN] = {0}; GetScanlineKeyString(&shaderKey, scanlineName, sizeof scanlineName / sizeof *scanlineName); GenerateScanLine(gglState, program, module, mainName, scanlineName); CodeGen(instance, scanlineName, shader, program, gglState); } else #endif CodeGen(instance, mainName, shader, program, gglState); shader->executable->instances[shaderKey] = instance; // debug_printf("jit new shader '%s'(%p) \n", mainName, instance->function); } else // debug_printf("use cached shader %p \n", instance->function); ; shader->function = instance->function; } // puts("pf2: GGLShaderUse end"); // assert(0); } static void ShaderUse(GGLInterface * iface, gl_shader_program * program) { GGL_GET_CONTEXT(ctx, iface); // so drawing calls will do nothing until ShaderUse with a program SetShaderVerifyFunctions(iface); if (!program) { ctx->CurrentProgram = NULL; return; } GGLShaderUse(ctx->llvmCtx, &ctx->state, program); for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) { if (!program->_LinkedShaders[i]) continue; if (!program->_LinkedShaders[i]->function) continue; if (GL_VERTEX_SHADER == program->_LinkedShaders[i]->Type) ctx->PickRaster(iface); else if (GL_FRAGMENT_SHADER == program->_LinkedShaders[i]->Type) ctx->PickScanLine(iface); else assert(0); } ctx->CurrentProgram = program; } unsigned GGLShaderDetach(gl_shader_program * program, gl_shader * shader) { for (unsigned i = 0; i < program->NumShaders; i++) if (program->Shaders[i] == shader) { program->NumShaders--; // just swap end to deleted shader program->Shaders[i] = program->Shaders[program->NumShaders]; shader->RefCount--; if (1 == shader->RefCount && shader->DeletePending) GGLShaderDelete(shader); return GL_NO_ERROR; } return (GL_INVALID_OPERATION); } static void ShaderDetach(const GGLInterface * iface, gl_shader_program * program, gl_shader * shader) { unsigned error = GGLShaderDetach(program, shader); if (GL_NO_ERROR != error) gglError(error); } void GGLShaderProgramDelete(gl_shader_program * program) { for (unsigned i = 0; i < program->NumShaders; i++) { GGLShaderDelete(program->Shaders[i]); // actually just mark for delete GGLShaderDetach(program, program->Shaders[i]); // detach will delete if ref == 1 i--; // GGLShaderDetach just swaps end to detached shader } for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) GGLShaderDelete(program->_LinkedShaders[i]); hieralloc_free(program); } static void ShaderProgramDelete(GGLInterface * iface, gl_shader_program * program) { GGL_GET_CONTEXT(ctx, iface); if (ctx->CurrentProgram == program) { ctx->CurrentProgram = NULL; SetShaderVerifyFunctions(iface); } GGLShaderProgramDelete(program); } void GGLShaderGetiv(const gl_shader_t * shader, const GLenum pname, GLint * params) { switch (pname) { case GL_SHADER_TYPE: *params = shader->Type; break; case GL_DELETE_STATUS: *params = shader->DeletePending; break; case GL_COMPILE_STATUS: *params = shader->CompileStatus; break; case GL_INFO_LOG_LENGTH: *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0; break; case GL_SHADER_SOURCE_LENGTH: *params = shader->Source ? strlen(shader->Source) + 1 : 0; break; default: assert(0); break; } } void GGLShaderGetInfoLog(const gl_shader_t * shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) { unsigned len = 0; infolog[0] = 0; if (shader->InfoLog) { len = strlen(shader->InfoLog); strncpy(infolog, shader->InfoLog, bufsize); infolog[bufsize] = 0; } if (length) *length = strlen(infolog); } void GGLShaderProgramGetiv(const gl_shader_program_t * program, const GLenum pname, GLint * params) { switch (pname) { case GL_DELETE_STATUS: *params = program->DeletePending; break; case GL_LINK_STATUS: *params = program->LinkStatus; break; case GL_VALIDATE_STATUS: *params = program->LinkStatus; break; case GL_INFO_LOG_LENGTH: *params = program->InfoLog ? strlen(program->InfoLog) + 1 : 0; break; case GL_ATTACHED_SHADERS: *params = program->NumShaders; break; case GL_ACTIVE_ATTRIBUTES: *params = program->AttributeSlots; break; case GL_ACTIVE_UNIFORMS: *params = program->Uniforms->Slots; break; case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: case GL_ACTIVE_UNIFORM_MAX_LENGTH: printf("pf2:GGLShaderProgramGetiv not implemented: %d \n", pname); default: assert(0); break; } } void GGLShaderProgramGetInfoLog(const gl_shader_program_t * program, GLsizei bufsize, GLsizei* length, GLchar* infolog) { unsigned len = 0; infolog[0] = 0; if (program->InfoLog) { len = strlen(program->InfoLog); strncpy(infolog, program->InfoLog, bufsize); infolog[bufsize] = 0; } if (length) *length = strlen(infolog); } void GGLShaderAttributeBind(const gl_shader_program * program, GLuint index, const GLchar * name) { int i = _mesa_add_parameter(program->Attributes, name); program->Attributes->Parameters[i].BindLocation = index; } GLint GGLShaderAttributeLocation(const gl_shader_program * program, const char * name) { int i = _mesa_get_parameter(program->Attributes, name); if (i >= 0) return program->Attributes->Parameters[i].Location; return -1; } GLint GGLShaderVaryingLocation(const gl_shader_program_t * program, const char * name, GLint * vertexOutputLocation) { for (unsigned int i = 0; i < program->Varying->NumParameters; i++) if (!strcmp(program->Varying->Parameters[i].Name, name)) { if (vertexOutputLocation) *vertexOutputLocation = program->Varying->Parameters[i].BindLocation; return program->Varying->Parameters[i].Location; } return -1; } GLint GGLShaderUniformLocation(const gl_shader_program * program, const char * name) { for (unsigned i = 0; i < program->Uniforms->NumUniforms; i++) if (!strcmp(program->Uniforms->Uniforms[i].Name, name)) return i; return -1; } void GGLShaderUniformGetfv(gl_shader_program * program, GLint location, GLfloat * params) { assert(0 <= location && program->Uniforms->NumUniforms > location); int index = program->Uniforms->Uniforms[location].Pos; assert(0 <= index && program->Uniforms->Slots > index); memcpy(params, program->ValuesUniform + index, sizeof(*program->ValuesUniform)); } void GGLShaderUniformGetiv(gl_shader_program * program, GLint location, GLint * params) { assert(0 <= location && program->Uniforms->NumUniforms > location); int index = program->Uniforms->Uniforms[location].Pos; assert(0 <= index && program->Uniforms->Slots > index); const float * uniform = program->ValuesUniform[index]; params[0] = uniform[0]; params[1] = uniform[1]; params[2] = uniform[2]; params[3] = uniform[3]; } void GGLShaderUniformGetSamplers(const gl_shader_program_t * program, int sampler2tmu[GGL_MAXCOMBINEDTEXTUREIMAGEUNITS]) { // LOGD("%s", program->Shaders[MESA_SHADER_FRAGMENT]->Source); // for (unsigned i = 0; i < program->Uniforms->Slots + program->Uniforms->SamplerSlots; i++) // LOGD("%d: %.2f \t %.2f \t %.2f \t %.2f", i, program->ValuesUniform[i][0], program->ValuesUniform[i][1], // program->ValuesUniform[i][2], program->ValuesUniform[i][3]); for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++) sampler2tmu[i] = -1; for (unsigned i = 0; i < program->Uniforms->NumUniforms; i++) { const gl_uniform & uniform = program->Uniforms->Uniforms[i]; if (uniform.Type->is_sampler()) { // LOGD("%d uniform.Pos=%d tmu=%d", program->Uniforms->Slots, uniform.Pos, (int)program->ValuesUniform[program->Uniforms->Slots + uniform.Pos][0]); sampler2tmu[uniform.Pos] = program->ValuesUniform[program->Uniforms->Slots + uniform.Pos][0]; } else if (uniform.Type->is_array() && uniform.Type->fields.array->is_sampler()) assert(0); } } GLint GGLShaderUniform(gl_shader_program * program, GLint location, GLsizei count, const GLvoid *values, GLenum type) { // LOGD("pf2: GGLShaderUniform location=%d count=%d type=0x%.4X", location, count, type); // TODO: sampler uniform and type checking if (!program) { //gglError(GL_INVALID_OPERATION); return -2; } if (-1 == location) return -1; assert(0 <= location && program->Uniforms->NumUniforms > location); const gl_uniform & uniform = program->Uniforms->Uniforms[location]; int start = -1; if (uniform.Type->is_sampler()) { start = uniform.Pos + program->Uniforms->Slots; assert(GL_INT == type && 1 == count); program->ValuesUniform[start][0] = *(float *)values; return uniform.Pos; } else if (uniform.Type->is_array() && uniform.Type->fields.array->is_sampler()) { assert(0); // not implemented } else start = uniform.Pos; int slots = 0, elems = 0; switch (type) { case GL_INT: case GL_FLOAT: case GL_BOOL: slots = count; elems = 1; break; case GL_FLOAT_VEC2: // fall through case GL_INT_VEC2: // fall through case GL_BOOL_VEC2: slots = count; elems = 2; break; case GL_INT_VEC3: // fall through case GL_BOOL_VEC3: // fall through case GL_FLOAT_VEC3: // fall through slots = count; elems = 3; break; case GL_INT_VEC4: // fall through case GL_FLOAT_VEC4: // fall through case GL_BOOL_VEC4: // fall through slots = count; elems = 4; break; default: assert(0); } // LOGD("pf2: GGLShaderUniform start=%d slots=%d elems=%d", start, slots, elems); if (0 > start) assert(0); if (start + slots > program->Uniforms->Slots) assert(0); for (int i = 0; i < slots; i++) memcpy(program->ValuesUniform + start + i, values, elems * sizeof(float)); // LOGD("pf2: GGLShaderUniform copied"); return -2; } void GGLShaderUniformMatrix(gl_shader_program * program, GLint cols, GLint rows, GLint location, GLsizei count, GLboolean transpose, const GLfloat *values) { if (location == -1) return; assert(!transpose); assert(cols == rows); assert(0 <= location && program->Uniforms->NumUniforms > location); int start = program->Uniforms->Uniforms[location].Pos; unsigned slots = cols * count; if (start < 0 || start + slots > program->Uniforms->Slots) return gglError(GL_INVALID_OPERATION); for (unsigned i = 0; i < slots; i++) { float * column = program->ValuesUniform[start + i]; for (unsigned j = 0; j < rows; j++) column[j] = values[i * 4 + j]; } // if (!strstr(program->Shaders[MESA_SHADER_FRAGMENT]->Source, // "gl_FragColor = color * texture2D(sampler, outTexCoords).a;")) // return; // // LOGD("pf2: GGLShaderUniformMatrix location=%d cols=%d count=%d", location, cols, count); // // for (unsigned i = 0; i < 4; i++) // LOGD("pf2: GGLShaderUniformMatrix %.2f \t %.2f \t %.2f \t %.2f \n", values[i * 4 + 0], // values[i * 4 + 1], values[i * 4 + 2], values[i * 4 + 3]); } static void ShaderVerifyProcessVertex(const GGLInterface * iface, const VertexInput * input, VertexOutput * output) { GGL_GET_CONST_CONTEXT(ctx, iface); if (ctx->CurrentProgram) { ShaderUse(const_cast<GGLInterface *>(iface), ctx->CurrentProgram); if (ShaderVerifyProcessVertex != iface->ProcessVertex) iface->ProcessVertex(iface, input, output); } } static void ShaderVerifyDrawTriangle(const GGLInterface * iface, const VertexInput * v0, const VertexInput * v1, const VertexInput * v2) { GGL_GET_CONST_CONTEXT(ctx, iface); if (ctx->CurrentProgram) { ShaderUse(const_cast<GGLInterface *>(iface), ctx->CurrentProgram); if (ShaderVerifyDrawTriangle != iface->DrawTriangle) iface->DrawTriangle(iface, v0, v1, v2); } } static void ShaderVerifyRasterTriangle(const GGLInterface * iface, const VertexOutput * v1, const VertexOutput * v2, const VertexOutput * v3) { GGL_GET_CONST_CONTEXT(ctx, iface); if (ctx->CurrentProgram) { ShaderUse(const_cast<GGLInterface *>(iface), ctx->CurrentProgram); if (ShaderVerifyRasterTriangle != iface->RasterTriangle) iface->RasterTriangle(iface, v1, v2, v3); } } static void ShaderVerifyRasterTrapezoid(const GGLInterface * iface, const VertexOutput * tl, const VertexOutput * tr, const VertexOutput * bl, const VertexOutput * br) { GGL_GET_CONST_CONTEXT(ctx, iface); if (ctx->CurrentProgram) { ShaderUse(const_cast<GGLInterface *>(iface), ctx->CurrentProgram); if (ShaderVerifyRasterTrapezoid != iface->RasterTrapezoid) iface->RasterTrapezoid(iface, tl, tr, bl, br); } } static void ShaderVerifyScanLine(const GGLInterface * iface, const VertexOutput * v1, const VertexOutput * v2) { GGL_GET_CONST_CONTEXT(ctx, iface); if (ctx->CurrentProgram) { ShaderUse(const_cast<GGLInterface *>(iface), ctx->CurrentProgram); if (ShaderVerifyScanLine != iface->ScanLine) iface->ScanLine(iface, v1, v2); } } // called after state changes so that drawing calls will trigger JIT void SetShaderVerifyFunctions(struct GGLInterface * iface) { iface->ProcessVertex = ShaderVerifyProcessVertex; iface->DrawTriangle = ShaderVerifyDrawTriangle; iface->RasterTriangle = ShaderVerifyRasterTriangle; iface->RasterTrapezoid = ShaderVerifyRasterTrapezoid; iface->ScanLine = ShaderVerifyScanLine; } void InitializeShaderFunctions(struct GGLInterface * iface) { GGL_GET_CONTEXT(ctx, iface); ctx->llvmCtx = new llvm::LLVMContext(); iface->ShaderCreate = ShaderCreate; iface->ShaderSource = GGLShaderSource; iface->ShaderCompile = ShaderCompile; iface->ShaderDelete = ShaderDelete; iface->ShaderProgramCreate = ShaderProgramCreate; iface->ShaderAttach = ShaderAttach; iface->ShaderDetach = ShaderDetach; iface->ShaderProgramLink = ShaderProgramLink; iface->ShaderUse = ShaderUse; iface->ShaderProgramDelete = ShaderProgramDelete; iface->ShaderGetiv = GGLShaderGetiv; iface->ShaderGetInfoLog = GGLShaderGetInfoLog; iface->ShaderProgramGetiv = GGLShaderProgramGetiv; iface->ShaderProgramGetInfoLog = GGLShaderProgramGetInfoLog; iface->ShaderAttributeBind = GGLShaderAttributeBind; iface->ShaderAttributeLocation = GGLShaderAttributeLocation; iface->ShaderVaryingLocation = GGLShaderVaryingLocation; iface->ShaderUniformLocation = GGLShaderUniformLocation; iface->ShaderUniformGetfv = GGLShaderUniformGetfv; iface->ShaderUniformGetiv = GGLShaderUniformGetiv; iface->ShaderUniformGetSamplers = GGLShaderUniformGetSamplers; iface->ShaderUniform = GGLShaderUniform; iface->ShaderUniformMatrix = GGLShaderUniformMatrix; } void DestroyShaderFunctions(GGLInterface * iface) { GGL_GET_CONTEXT(ctx, iface); _mesa_glsl_release_types(); _mesa_glsl_release_functions(); delete ctx->llvmCtx; ctx->llvmCtx = NULL; }