void ShaderVariation::ParseParameters(unsigned char* bufData, unsigned bufSize) { MOJOSHADER_parseData const* parseData = MOJOSHADER_parse("bytecode", bufData, bufSize, 0, 0, 0, 0, 0, 0, 0); for (int i = 0; i < parseData->symbol_count; i++) { MOJOSHADER_symbol const& symbol = parseData->symbols[i]; String name(symbol.name); unsigned reg = symbol.register_index; unsigned regCount = symbol.register_count; // Check if the parameter is a constant or a texture sampler bool isSampler = (name[0] == 's'); name = name.Substring(1); if (isSampler) { // Skip if it's a G-buffer sampler, which are aliases for the standard texture units if (reg < MAX_TEXTURE_UNITS) { if (name != "AlbedoBuffer" && name != "NormalBuffer" && name != "DepthBuffer" && name != "LightBuffer") useTextureUnit_[reg] = true; } } else { ShaderParameter parameter; parameter.type_ = type_; parameter.name_ = name; parameter.register_ = reg; parameter.regCount_ = regCount; parameters_[StringHash(name)] = parameter; } } MOJOSHADER_freeParseData(parseData); }
// !!! FIXME: this is sort of a big, ugly function. const MOJOSHADER_effect *MOJOSHADER_parseEffect(const char *profile, const unsigned char *buf, const unsigned int _len, const MOJOSHADER_swizzle *swiz, const unsigned int swizcount, const MOJOSHADER_samplerMap *smap, const unsigned int smapcount, MOJOSHADER_malloc m, MOJOSHADER_free f, void *d) { if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) ) return &MOJOSHADER_out_of_mem_effect; // supply both or neither. if (m == NULL) m = MOJOSHADER_internal_malloc; if (f == NULL) f = MOJOSHADER_internal_free; MOJOSHADER_effect *retval = (MOJOSHADER_effect*)m(sizeof (MOJOSHADER_effect), d); if (retval == NULL) return &MOJOSHADER_out_of_mem_effect; // supply both or neither. memset(retval, '\0', sizeof (*retval)); retval->malloc = m; retval->free = f; retval->malloc_data = d; const uint8 *ptr = (const uint8 *) buf; uint32 len = (uint32) _len; size_t siz = 0; int i, j, k; if (len < 8) goto parseEffect_unexpectedEOF; const uint8 *base = NULL; if (readui32(&ptr, &len) != 0xFEFF0901) // !!! FIXME: is this always magic? goto parseEffect_notAnEffectsFile; else { const uint32 offset = readui32(&ptr, &len); base = ptr; //printf("base offset == %u\n", offset); if (offset > len) goto parseEffect_unexpectedEOF; ptr += offset; len -= offset; } // else // params... if (len < 16) goto parseEffect_unexpectedEOF; const uint32 numparams = readui32(&ptr, &len); const uint32 numtechniques = readui32(&ptr, &len); readui32(&ptr, &len); // !!! FIXME: there are 8 unknown bytes here. Annotations? /*const uint32 numobjects = */ readui32(&ptr, &len); if (numparams > 0) { siz = sizeof (MOJOSHADER_effectParam) * numparams; retval->params = (MOJOSHADER_effectParam *) m(siz, d); if (retval->params == NULL) goto parseEffect_outOfMemory; memset(retval->params, '\0', siz); retval->param_count = numparams; for (i = 0; i < numparams; i++) { if (len < 16) goto parseEffect_unexpectedEOF; const uint32 typeoffset = readui32(&ptr, &len); /*const uint32 valoffset =*/ readui32(&ptr, &len); /*const uint32 flags =*/ readui32(&ptr, &len); const uint32 numannos = readui32(&ptr, &len); for (j = 0; j < numannos; j++) { if (len < 8) goto parseEffect_unexpectedEOF; // !!! FIXME: parse annotations. readui32(&ptr, &len); readui32(&ptr, &len); } // for const uint8 *typeptr = base + typeoffset; unsigned int typelen = 9999999; // !!! FIXME /*const uint32 paramtype =*/ readui32(&typeptr, &typelen); /*const uint32 paramclass =*/ readui32(&typeptr, &typelen); const uint32 paramname = readui32(&typeptr, &typelen); const uint32 paramsemantic = readui32(&typeptr, &typelen); // !!! FIXME: sanity checks! const char *namestr = ((const char *) base) + paramname; const char *semstr = ((const char *) base) + paramsemantic; uint32 len; char *strptr; len = *((const uint32 *) namestr); strptr = (char *) m(len + 1, d); memcpy(strptr, namestr + 4, len); strptr[len] = '\0'; retval->params[i].name = strptr; len = *((const uint32 *) semstr); strptr = (char *) m(len + 1, d); memcpy(strptr, semstr + 4, len); strptr[len] = '\0'; retval->params[i].semantic = strptr; } // for } // if uint32 numshaders = 0; // we'll calculate this later. // techniques... if (numtechniques > 0) { siz = sizeof (MOJOSHADER_effectTechnique) * numtechniques; retval->techniques = (MOJOSHADER_effectTechnique *) m(siz, d); if (retval->techniques == NULL) goto parseEffect_outOfMemory; memset(retval->techniques, '\0', siz); retval->technique_count = numtechniques; for (i = 0; i < numtechniques; i++) { if (len < 12) goto parseEffect_unexpectedEOF; MOJOSHADER_effectTechnique *technique = &retval->techniques[i]; const uint32 nameoffset = readui32(&ptr, &len); const uint32 numannos = readui32(&ptr, &len); const uint32 numpasses = readui32(&ptr, &len); if (nameoffset >= _len) goto parseEffect_unexpectedEOF; if (numannos > 0) { // !!! FIXME: expose these to the caller? for (j = 0; j < numannos; j++) { if (len < 8) goto parseEffect_unexpectedEOF; readui32(&ptr, &len); // typedef offset readui32(&ptr, &len); // value offset } // for } // if // !!! FIXME: verify this doesn't go past EOF looking for a null. { const char *namestr = ((char *) base) + nameoffset; uint32 len = *((const uint32 *) namestr); char *strptr = (char *) m(len + 1, d); memcpy(strptr, namestr + 4, len); strptr[len] = '\0'; technique->name = strptr; } if (numpasses > 0) { technique->pass_count = numpasses; siz = sizeof (MOJOSHADER_effectPass) * numpasses; technique->passes = (MOJOSHADER_effectPass *) m(siz, d); if (technique->passes == NULL) goto parseEffect_outOfMemory; memset(technique->passes, '\0', siz); for (j = 0; j < numpasses; j++) { if (len < 12) goto parseEffect_unexpectedEOF; MOJOSHADER_effectPass *pass = &technique->passes[j]; const uint32 passnameoffset = readui32(&ptr, &len); const uint32 numannos = readui32(&ptr, &len); const uint32 numstates = readui32(&ptr, &len); if (passnameoffset >= _len) goto parseEffect_unexpectedEOF; // !!! FIXME: verify this doesn't go past EOF looking for a null. { const char *namestr = ((char *) base) + passnameoffset; uint32 len = *((const uint32 *) namestr); char *strptr = (char *) m(len + 1, d); memcpy(strptr, namestr + 4, len); strptr[len] = '\0'; pass->name = strptr; } if (numannos > 0) { for (k = 0; k < numannos; k++) { if (len < 8) goto parseEffect_unexpectedEOF; // !!! FIXME: do something with this. readui32(&ptr, &len); readui32(&ptr, &len); } // for } // if if (numstates > 0) { pass->state_count = numstates; siz = sizeof (MOJOSHADER_effectState) * numstates; pass->states = (MOJOSHADER_effectState *) m(siz, d); if (pass->states == NULL) goto parseEffect_outOfMemory; memset(pass->states, '\0', siz); for (k = 0; k < numstates; k++) { if (len < 16) goto parseEffect_unexpectedEOF; MOJOSHADER_effectState *state = &pass->states[k]; const uint32 type = readui32(&ptr, &len); readui32(&ptr, &len); // !!! FIXME: don't know what this field does. /*const uint32 offsetend = */ readui32(&ptr, &len); /*const uint32 offsetstart = */ readui32(&ptr, &len); state->type = type; if ((type == 0x92) || (type == 0x93)) numshaders++; } // for } // if } // for } // if } // for } // if // textures... if (len < 8) goto parseEffect_unexpectedEOF; const int numtextures = readui32(&ptr, &len); const int numobjects = readui32(&ptr, &len); // !!! FIXME: "objects" for lack of a better word. if (numtextures > 0) { siz = sizeof (MOJOSHADER_effectTexture) * numtextures; retval->textures = (MOJOSHADER_effectTexture*)m(siz, d); if (retval->textures == NULL) goto parseEffect_outOfMemory; memset(retval->textures, '\0', siz); for (i = 0; i < numtextures; i++) { if (len < 8) goto parseEffect_unexpectedEOF; MOJOSHADER_effectTexture *texture = &retval->textures[i]; const uint32 texparam = readui32(&ptr, &len); const uint32 texsize = readui32(&ptr, &len); // apparently texsize will pad out to 32 bits. const uint32 readsize = (((texsize + 3) / 4) * 4); if (len < readsize) goto parseEffect_unexpectedEOF; texture->param = texparam; char *str = (char*)m(texsize + 1, d); if (str == NULL) goto parseEffect_outOfMemory; memcpy(str, ptr, texsize); str[texsize] = '\0'; texture->name = str; ptr += readsize; len -= readsize; } // for } // if // shaders... if (numshaders > 0) { siz = sizeof (MOJOSHADER_effectShader) * numshaders; retval->shaders = (MOJOSHADER_effectShader *) m(siz, d); if (retval->shaders == NULL) goto parseEffect_outOfMemory; memset(retval->shaders, '\0', siz); retval->shader_count = numshaders; // !!! FIXME: I wonder if we should pull these from offsets and not // !!! FIXME: count on them all being in a line like this. for (i = 0; i < numshaders; i++) { if (len < 24) goto parseEffect_unexpectedEOF; MOJOSHADER_effectShader *shader = &retval->shaders[i]; const uint32 technique = readui32(&ptr, &len); const uint32 pass = readui32(&ptr, &len); readui32(&ptr, &len); // !!! FIXME: don't know what this does. readui32(&ptr, &len); // !!! FIXME: don't know what this does (vertex/pixel/geometry?) readui32(&ptr, &len); // !!! FIXME: don't know what this does. const uint32 shadersize = readui32(&ptr, &len); if (len < shadersize) goto parseEffect_unexpectedEOF; shader->technique = technique; shader->pass = pass; shader->shader = MOJOSHADER_parse(profile, ptr, shadersize, swiz, swizcount, smap, smapcount, m, f, d); // !!! FIXME: check for errors. ptr += shadersize; len -= shadersize; } // for } // if // !!! FIXME: we parse this, but don't expose the data, yet. // mappings ... assert(numshaders <= numobjects); const uint32 nummappings = numobjects - numshaders; if (nummappings > 0) { for (i = 0; i < nummappings; i++) { if (len < 24) goto parseEffect_unexpectedEOF; /*const uint32 magic = */ readui32(&ptr, &len); /*const uint32 index = */ readui32(&ptr, &len); readui32(&ptr, &len); // !!! FIXME: what is this field? readui32(&ptr, &len); // !!! FIXME: what is this field? /*const uint32 type = */ readui32(&ptr, &len); const uint32 mapsize = readui32(&ptr, &len); if (mapsize > 0) { const uint32 readsize = (((mapsize + 3) / 4) * 4); if (len < readsize) goto parseEffect_unexpectedEOF; } // if } // for } // if retval->profile = (char *) m(strlen(profile) + 1, d); if (retval->profile == NULL) goto parseEffect_outOfMemory; strcpy((char *) retval->profile, profile); return retval; // !!! FIXME: do something with this. parseEffect_notAnEffectsFile: parseEffect_unexpectedEOF: parseEffect_outOfMemory: MOJOSHADER_freeEffect(retval); return &MOJOSHADER_out_of_mem_effect; } // MOJOSHADER_parseEffect
static int do_file(const char *profile, const char *dname, const char *fn, int *total) { int do_quit = 0; #if FINDERRORS_COMPILE_SHADERS SDL_Event e; // pump event queue to keep OS happy. while (SDL_PollEvent(&e)) { if (e.type == SDL_QUIT) do_quit = 1; } // while SDL_GL_SwapBuffers(); #endif if (do_quit) { report("FAIL: user requested quit!\n"); return 0; } // if int assembly = 0; if (strstr(fn, ".bytecode") != NULL) assembly = 0; else if (strstr(fn, ".disasm") != NULL) assembly = 1; else return 1; (*total)++; char *fname = (char *) alloca(strlen(fn) + strlen(dname) + 1); sprintf(fname, "%s/%s", dname, fn); FILE *io = fopen(fname, "rb"); if (io == NULL) { report("FAIL: %s fopen() failed.\n", fname); return 1; } // if static unsigned char buf[1024 * 256]; int rc = fread(buf, 1, sizeof (buf), io); fclose(io); if (rc == -1) { report("FAIL: %s %s\n", fname, strerror(errno)); return 1; } // if if (assembly) { const MOJOSHADER_parseData *a; buf[rc] = '\0'; // make sure the source is null-terminated. a = MOJOSHADER_assemble(fname, (char *) buf, rc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); if (a->error_count > 0) { report("FAIL: %s (line %d) %s\n", a->errors[0].filename ? a->errors[0].filename : "???", a->errors[0].error_position, a->errors[0].error); return 1; } // if else if (a->output_len > sizeof (buf)) { report("FAIL: %s buffer overflow in finderrors.c\n", fname); return 1; } // if rc = a->output_len; memcpy(buf, a->output, rc); MOJOSHADER_freeParseData(a); } // if #if FINDERRORS_COMPILE_SHADERS MOJOSHADER_glShader *shader = MOJOSHADER_glCompileShader(buf, rc, NULL, 0); if (shader == NULL) report("FAIL: %s %s\n", fname, MOJOSHADER_glGetError()); else { const MOJOSHADER_parseData *pd = MOJOSHADER_glGetShaderParseData(shader); MOJOSHADER_glShader *v = (pd->shader_type == MOJOSHADER_TYPE_VERTEX) ? shader : NULL; MOJOSHADER_glShader *p = (pd->shader_type == MOJOSHADER_TYPE_PIXEL) ? shader : NULL; MOJOSHADER_glProgram *program = MOJOSHADER_glLinkProgram(v, p); if (program == NULL) report("FAIL: %s %s\n", fname, MOJOSHADER_glGetError()); else { report("PASS: %s\n", fname); MOJOSHADER_glDeleteProgram(program); } // else MOJOSHADER_glDeleteShader(shader); } #else const MOJOSHADER_parseData *pd = MOJOSHADER_parse(profile, buf, rc, NULL, 0, NULL, NULL, NULL); if (pd->error_count == 0) report("PASS: %s\n", fname); else { int i; for (i = 0; i < pd->error_count; i++) { report("FAIL: %s (position %d) %s\n", pd->errors[i].filename, pd->errors[i].error_position, pd->errors[i].error); } // for } // else MOJOSHADER_freeParseData(pd); #endif return 1; } // do_file