//============================================================================== /// Given a string that defines blending return the GLenum static GLenum blendToEnum(const CString& str) { // Dont make idiotic mistakes #define TXT_AND_ENUM(x) \ if(str == #x) \ { \ return x; \ } TXT_AND_ENUM(GL_ZERO) TXT_AND_ENUM(GL_ONE) TXT_AND_ENUM(GL_DST_COLOR) TXT_AND_ENUM(GL_ONE_MINUS_DST_COLOR) TXT_AND_ENUM(GL_SRC_ALPHA) TXT_AND_ENUM(GL_ONE_MINUS_SRC_ALPHA) TXT_AND_ENUM(GL_DST_ALPHA) TXT_AND_ENUM(GL_ONE_MINUS_DST_ALPHA) TXT_AND_ENUM(GL_SRC_ALPHA_SATURATE) TXT_AND_ENUM(GL_SRC_COLOR) TXT_AND_ENUM(GL_ONE_MINUS_SRC_COLOR); ANKI_ASSERT(0); throw ANKI_EXCEPTION("Incorrect blend enum"); #undef TXT_AND_ENUM }
//============================================================================== Bool ProgramPrePreprocessor::parseType(const PPPString& line) { U i; Bool found = false; for(i = 0; i < static_cast<U>(ShaderType::COUNT); i++) { if(line.find(commands[i]) == 0) { found = true; break; } } if(found) { if(m_type != ShaderType::COUNT) { throw ANKI_EXCEPTION("The shader type is already set. Line %s", &line[0]); } m_type = static_cast<ShaderType>(i); } return found; }
//============================================================================== void Material::load(const CString& filename, ResourceInitializer& init) { try { m_vars = std::move(ResourceVector<MaterialVariable*>(init.m_alloc)); Dictionary<MaterialVariable*> dict(10, Dictionary<MaterialVariable*>::hasher(), Dictionary<MaterialVariable*>::key_equal(), init.m_alloc); m_varDict = std::move(dict); m_progs = std::move(ResourceVector<ProgramResourcePointer>(init.m_alloc)); m_pplines = std::move(ResourceVector<GlProgramPipelineHandle>(init.m_alloc)); XmlDocument doc; doc.loadFile(filename, init.m_tempAlloc); parseMaterialTag(doc.getChildElement("material"), init); } catch(std::exception& e) { throw ANKI_EXCEPTION("Failed to load material") << e; } }
//============================================================================== void NativeWindow::swapBuffers() { ANKI_ASSERT(isCreated()); if(eglSwapBuffers(impl->display, impl->surface) == EGL_FALSE) { throw ANKI_EXCEPTION("eglSwapBuffers() failed"); } }
//============================================================================== String getHomeDirectory(HeapAllocator<U8>& alloc) { const char* home = getenv("HOME"); if(home == nullptr) { throw ANKI_EXCEPTION("HOME environment variable not set"); } return String(CString(home), alloc); }
//============================================================================== void NativeWindow::swapBuffers() { ANKI_COUNTER_START_TIMER(SWAP_BUFFERS_TIME); ANKI_ASSERT(isCreated()); if(eglSwapBuffers(impl->display, impl->surface) == EGL_FALSE) { throw ANKI_EXCEPTION("eglSwapBuffers() failed"); } ANKI_COUNTER_STOP_TIMER_INC(SWAP_BUFFERS_TIME); }
//============================================================================== void Hdr::init(const ConfigSet& initializer) { try { initInternal(initializer); } catch(const std::exception& e) { throw ANKI_EXCEPTION("Failed to init PPS HDR") << e; } }
//============================================================================== void Pps::init(const ConfigSet& config) { try { initInternal(config); } catch(const std::exception& e) { throw ANKI_EXCEPTION("Failed to init PPS") << e; } }
//============================================================================== void TextureResource::load(const CString& filename, ResourceInitializer& init) { try { loadInternal(filename, init); } catch(std::exception& e) { throw ANKI_EXCEPTION("Failed to load texture") << e; } }
//============================================================================== void createDirectory(const CString& dir) { if(directoryExists(dir)) { return; } if(mkdir(dir.get(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) { throw ANKI_EXCEPTION("%s : %s", strerror(errno), dir.get()); } }
//============================================================================== void removeDirectory(const CString& dirname) { DIR* dir; struct dirent* entry; char path[PATH_MAX]; if(path == nullptr) { throw ANKI_EXCEPTION("Out of memory error"); } dir = opendir(dirname.get()); if(dir == nullptr) { throw ANKI_EXCEPTION("opendir() failed"); } while((entry = readdir(dir)) != nullptr) { if(strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) { std::snprintf( path, (size_t)PATH_MAX, "%s/%s", dirname.get(), entry->d_name); if(entry->d_type == DT_DIR) { removeDirectory(CString(path)); } else { remove(path); } } } closedir(dir); remove(dirname.get()); }
static MaterialVariable* newMaterialVariable( const GlProgramVariable& glvar, const MaterialProgramCreator::Input& in, ResourceAllocator<U8>& alloc, TempResourceAllocator<U8>& talloc) { MaterialVariable* out = nullptr; if(in.m_value.size() > 0) { // Has values U floatsNeeded = glvar.getArraySize() * (sizeof(T) / sizeof(F32)); if(in.m_value.size() != floatsNeeded) { throw ANKI_EXCEPTION("Incorrect number of values. Variable %s", &glvar.getName()[0]); } TempResourceVector<F32> floatvec(talloc); floatvec.resize(floatsNeeded); for(U i = 0; i < floatsNeeded; ++i) { floatvec[i] = in.m_value[i].toF64(); } out = alloc.newInstance<MaterialVariableTemplate<T>>( &glvar, in.m_instanced, (T*)&floatvec[0], glvar.getArraySize(), alloc); } else { // Buildin out = alloc.newInstance<MaterialVariableTemplate<T>>( &glvar, in.m_instanced, nullptr, 0, alloc); } return out; }
//============================================================================== void ProgramPrePreprocessor::parseFile(const CString& filename) { try { auto alloc = m_shaderSource.getAllocator(); // Parse files recursively parseFileForPragmas( PPPString(filename, alloc), 0); m_shaderSource = m_sourceLines.join("\n"); } catch(Exception& e) { throw ANKI_EXCEPTION("Loading file failed: %s", &filename[0]) << e; } }
//============================================================================== /// Given a string return info about the shader static void getShaderInfo( const CString& str, GLenum& type, GLbitfield& bit, U& idx) { if(str == "vert"_cstr) { type = GL_VERTEX_SHADER; bit = GL_VERTEX_SHADER_BIT; idx = 0; } else if(str == "tesc"_cstr) { type = GL_TESS_CONTROL_SHADER; bit = GL_TESS_CONTROL_SHADER_BIT; idx = 1; } else if(str == "tese"_cstr) { type = GL_TESS_EVALUATION_SHADER; bit = GL_TESS_EVALUATION_SHADER_BIT; idx = 2; } else if(str == "geom"_cstr) { type = GL_GEOMETRY_SHADER; bit = GL_GEOMETRY_SHADER_BIT; idx = 3; } else if(str == "frag"_cstr) { type = GL_GEOMETRY_SHADER; bit = GL_GEOMETRY_SHADER_BIT; idx = 4; } else { throw ANKI_EXCEPTION("Incorrect type %s", &str[0]); } }
//============================================================================== void MaterialProgramCreator::parseProgramsTag(const XmlElement& el) { // // First gather all the inputs // XmlElement programEl = el.getChildElement("program"_cstr); do { parseInputsTag(programEl); programEl = programEl.getNextSiblingElement("program"_cstr); } while(programEl); // Sort them by name to decrease the change of creating unique shaders std::sort(m_inputs.begin(), m_inputs.end(), InputSortFunctor()); // // Then parse the includes, operations and other parts of the program // programEl = el.getChildElement("program"_cstr); do { parseProgramTag(programEl); programEl = programEl.getNextSiblingElement("program"_cstr); } while(programEl); // // Sanity checks // // Check that all input is referenced for(Input& in : m_inputs) { if(in.m_shaderDefinedMask != in.m_shaderReferencedMask) { throw ANKI_EXCEPTION("Variable not referenced or not defined %s", &in.m_name[0]); } } }
//============================================================================== void GlFramebuffer::createFbo( const Array<U, MAX_COLOR_ATTACHMENTS + 1>& layers, GLenum depthStencilBindingPoint) { ANKI_ASSERT(!isCreated()); glGenFramebuffers(1, &m_glName); ANKI_ASSERT(m_glName != 0); const GLenum target = GL_FRAMEBUFFER; glBindFramebuffer(target, m_glName); // Attach color for(U i = 0; i < MAX_COLOR_ATTACHMENTS; i++) { if(!m_attachments[i].isCreated()) { continue; } const GlTexture& tex = m_attachments[i]._get(); attachTextureInternal(GL_COLOR_ATTACHMENT0 + i, tex, layers[i]); } // Attach depth/stencil if(m_attachments[MAX_COLOR_ATTACHMENTS].isCreated()) { ANKI_ASSERT(depthStencilBindingPoint != GL_NONE); const GlTexture& tex = m_attachments[MAX_COLOR_ATTACHMENTS]._get(); attachTextureInternal(depthStencilBindingPoint, tex, layers[MAX_COLOR_ATTACHMENTS]); } // Check completeness GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if(status != GL_FRAMEBUFFER_COMPLETE) { destroy(); throw ANKI_EXCEPTION("FBO is incomplete"); } }
//============================================================================== void NativeWindow::create(Initializer& init, HeapAllocator<U8>& alloc) { m_alloc = alloc; m_impl = m_alloc.newInstance<NativeWindowImpl>(); if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER) != 0) { throw ANKI_EXCEPTION("SDL_Init() failed"); } // // Set GL attributes // if(SDL_GL_SetAttribute(SDL_GL_RED_SIZE, init.m_rgbaBits[0]) != 0 || SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, init.m_rgbaBits[1]) != 0 || SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, init.m_rgbaBits[2]) != 0 || SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, init.m_rgbaBits[3]) != 0 || SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, init.m_depthBits) != 0 || SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, init.m_doubleBuffer) != 0 || SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, init.m_majorVersion) != 0 || SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, init.m_minorVersion) != 0 || SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE) != 0) { throw ANKI_EXCEPTION("SDL_GL_SetAttribute() failed"); } if(init.m_debugContext) { if(SDL_GL_SetAttribute( SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG) != 0) { throw ANKI_EXCEPTION("SDL_GL_SetAttribute() failed"); } } // // Create window // U32 flags = SDL_WINDOW_OPENGL; if(init.m_fullscreenDesktopRez) { flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; } m_impl->m_window = SDL_CreateWindow( init.m_title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, init.m_width, init.m_height, flags); if(m_impl->m_window == nullptr) { throw ANKI_EXCEPTION("SDL_CreateWindow() failed"); } // Set the size after loading a fullscreen window if(init.m_fullscreenDesktopRez) { int w, h; SDL_GetWindowSize(m_impl->m_window, &w, &h); m_width = w; m_height = h; } else { m_width = init.m_width; m_height = init.m_height; } // // Create context // m_impl->m_context = SDL_GL_CreateContext(m_impl->m_window); if(m_impl->m_context == nullptr) { throw ANKI_EXCEPTION("SDL_GL_CreateContext() failed"); } // // GLEW // glewExperimental = GL_TRUE; if(glewInit() != GLEW_OK) { throw ANKI_EXCEPTION("GLEW initialization failed"); } glGetError(); }
//============================================================================== void Renderer::init(const ConfigSet& initializer) { // Set from the initializer m_width = initializer.get("width"); m_height = initializer.get("height"); m_lodDistance = initializer.get("lodDistance"); m_framesNum = 0; m_samples = initializer.get("samples"); m_isOffscreen = initializer.get("offscreen"); m_renderingQuality = initializer.get("renderingQuality"); m_tilesCount.x() = initializer.get("tilesXCount"); m_tilesCount.y() = initializer.get("tilesYCount"); m_tessellation = initializer.get("tessellation"); // A few sanity checks if(m_samples != 1 && m_samples != 4 && m_samples != 8 && m_samples != 16 && m_samples != 32) { throw ANKI_EXCEPTION("Incorrect samples"); } if(m_width < 10 || m_height < 10) { throw ANKI_EXCEPTION("Incorrect sizes"); } // quad setup static const F32 quadVertCoords[][2] = {{1.0, 1.0}, {-1.0, 1.0}, {1.0, -1.0}, {-1.0, -1.0}}; GlDevice& gl = GlDeviceSingleton::get(); GlCommandBufferHandle jobs(&gl); GlClientBufferHandle tmpBuff = GlClientBufferHandle(jobs, sizeof(quadVertCoords), (void*)&quadVertCoords[0][0]); m_quadPositionsBuff = GlBufferHandle(jobs, GL_ARRAY_BUFFER, tmpBuff, 0); m_drawQuadVert.load("shaders/Quad.vert.glsl"); // Init the stages. Careful with the order!!!!!!!!!! m_tiler.init(this); m_ms.init(initializer);; m_is.init(initializer); m_bs.init(initializer); m_pps.init(initializer); m_dbg.init(initializer); // Init the shaderPostProcessorString std::stringstream ss; ss << "#define RENDERING_WIDTH " << m_width << "\n" << "#define RENDERING_HEIGHT " << m_height << "\n"; m_shaderPostProcessorString = ss.str(); // Default FB m_defaultFb = GlFramebufferHandle(jobs, {}); jobs.finish(); }
static int glf_program_populate_vars(glf_program *prog) { int num; int num2; char name_[512]; GLsizei length; GLint size; GLenum type; int i; GLint loc; assert(prog); assert(prog->id); assert(prog->vars == NULL); assert(prog->vars_num == 0); glGetProgramiv(prog->id, GL_ACTIVE_ATTRIBUTES, &num); glGetProgramiv(prog->id, GL_ACTIVE_UNIFORMS, &num2); /* make the allocations */ prog->vars_num = num + num2; prog->vars = (glf_shader_variable*)malloc( sizeof(glf_shader_variable) * prog->vars_num); assert(prog->vars); memset(prog->vars, 0, sizeof(glf_shader_variable) * prog->vars_num); /* attrib locations */ for(i = 0; i < num; i++) { glGetActiveAttrib(prog->id, i, sizeof(name_) / sizeof(char), &length, &size, &type, &name_[0]); name_[length] = '\0'; /* check if its FFP location */ loc = glGetAttribLocation(prog->id, &name_[0]); if(loc == -1) // if -1 it means that its an FFP var { GLF_LOGE("You are using FFP vertex attributes"); } ShaderProgramAttributeVariable* var = new ShaderProgramAttributeVariable(loc, &name_[0], type, size, this); vars.push_back(var); attribs.push_back(var); nameToVar[var->getName().c_str()] = var; nameToAttribVar[var->getName().c_str()] = var; } // uni locations glGetProgramiv(glId, GL_ACTIVE_UNIFORMS, &num); for(int i = 0; i < num; i++) // loop all uniforms { glGetActiveUniform(glId, i, sizeof(name_) / sizeof(char), &length, &size, &type, &name_[0]); name_[length] = '\0'; // check if its FFP location int loc = glGetUniformLocation(glId, &name_[0]); if(loc == -1) // if -1 it means that its an FFP var { throw ANKI_EXCEPTION("You are using FFP vertex uniforms"); } ShaderProgramUniformVariable* var = new ShaderProgramUniformVariable(loc, &name_[0], type, size, this); vars.push_back(var); unis.push_back(var); nameToVar[var->getName().c_str()] = var; nameToUniVar[var->getName().c_str()] = var; } }
//============================================================================== void ProgramPrePreprocessor::parseFileForPragmas( const PPPString& filename, U32 depth) { // first check the depth if(depth > MAX_DEPTH) { throw ANKI_EXCEPTION("The include depth is too high. " "Probably circular includance"); } // load file in lines auto alloc = m_shaderSource.getAllocator(); PPPString txt(alloc); PPPStringList lines(alloc); File file; file.open(filename.toCString(), File::OpenFlag::READ); file.readAllText(txt); lines = PPPStringList::splitString(txt.toCString(), '\n', alloc); if(lines.size() < 1) { throw ANKI_EXCEPTION("File is empty: %s", &filename[0]); } for(const PPPString& line : lines) { PtrSize npos = 0; if(line.find("#pragma anki") == 0) { Bool malformed = true; if(parseType(line)) { malformed = false; // All OK } else if((npos = line.find(commands[6])) == 0) { // Include if(line.getLength() >= std::strlen(commands[6]) + 2) { PPPString filen( line.begin() + std::strlen(commands[6]), line.end() - 1, alloc); filen = m_manager->fixResourceFilename(filen.toCString()); parseFileForPragmas(filen, depth + 1); malformed = false; // All OK } } if(malformed) { throw ANKI_EXCEPTION("Malformed pragma anki: %s", &line[0]); } } else { m_sourceLines.push_back(line); } } // Sanity checks if(m_type == ShaderType::COUNT) { throw ANKI_EXCEPTION("Shader is missing the type"); } }
//============================================================================== void NativeWindowImpl::create(NativeWindowInitInfo& init) { Array<EGLint, 256> attribs; U attr = 0; EGLint configsCount; EGLint format; EGLConfig config; ANKI_LOGI("Creating native window"); ANKI_ASSERT(gAndroidApp); android_app& andApp = *gAndroidApp; loopUntilWindowIsReady(andApp); // EGL init // display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if(display == EGL_NO_DISPLAY) { throw ANKI_EXCEPTION("Failed to create display"); } int major, minor; if(eglInitialize(display, &major, &minor) == EGL_FALSE) { throw ANKI_EXCEPTION("Failed to initialize EGL"); } // // EGL config // attribs[attr++] = EGL_SURFACE_TYPE; attribs[attr++] = EGL_WINDOW_BIT; attribs[attr++] = EGL_RENDERABLE_TYPE; attribs[attr++] = EGL_OPENGL_ES2_BIT; if(init.samplesCount > 1) { attribs[attr++] = EGL_SAMPLES; attribs[attr++] = init.samplesCount; } attribs[attr++] = EGL_RED_SIZE; attribs[attr++] = init.rgbaBits[0]; attribs[attr++] = EGL_GREEN_SIZE; attribs[attr++] = init.rgbaBits[1]; attribs[attr++] = EGL_BLUE_SIZE; attribs[attr++] = init.rgbaBits[2]; attribs[attr++] = EGL_ALPHA_SIZE; attribs[attr++] = init.rgbaBits[3]; attribs[attr++] = EGL_DEPTH_SIZE; attribs[attr++] = init.depthBits; attribs[attr++] = EGL_STENCIL_SIZE; attribs[attr++] = init.stencilBits; attribs[attr++] = EGL_NONE; if(eglChooseConfig(display, &attribs[0], &config, 1, &configsCount) == EGL_FALSE) { throw ANKI_EXCEPTION("Failed to query required EGL configs"); } if(configsCount == 0) { throw ANKI_EXCEPTION("No matching EGL configs found"); } eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format); ANKI_ASSERT(andApp.window); ANativeWindow_setBuffersGeometry(andApp.window, 0, 0, format); // Surface // surface = eglCreateWindowSurface(display, config, andApp.window, NULL); if(surface == EGL_NO_SURFACE) { throw ANKI_EXCEPTION("Cannot create surface"); } // Context // EGLint ctxAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctxAttribs); if(context == EGL_NO_CONTEXT) { throw ANKI_EXCEPTION("Cannot create context"); } if(eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { throw ANKI_EXCEPTION("Cannot make the context current"); } // Query width and height // EGLint w, h; eglQuerySurface(display, surface, EGL_WIDTH, &w); eglQuerySurface(display, surface, EGL_HEIGHT, &h); init.width = w; init.height = h; }
//============================================================================== void Material::populateVariables(const MaterialProgramCreator& mspc) { for(auto in : mspc.getInputVariables()) { if(in.m_constant) { continue; } MaterialVariable* mtlvar = nullptr; const GlProgramVariable* glvar = nullptr; // Find the input variable in one of the programs for(const ProgramResourcePointer& progr : m_progs) { const GlProgramHandle& prog = progr->getGlProgram(); glvar = prog.tryFindVariable(in.m_name.toCString()); if(glvar) { break; } } // Check if variable found if(glvar == nullptr) { throw ANKI_EXCEPTION("Variable not found in " "at least one program: %s", &in.m_name[0]); } switch(glvar->getDataType()) { // samplers case GL_SAMPLER_2D: case GL_SAMPLER_CUBE: { TextureResourcePointer tp; if(in.m_value.size() > 0) { tp = TextureResourcePointer( in.m_value[0].toCString(), m_resources); } auto alloc = m_resources->_getAllocator(); mtlvar = alloc.newInstance< MaterialVariableTemplate<TextureResourcePointer>>( glvar, false, &tp, 1, alloc); } break; // F32 case GL_FLOAT: mtlvar = newMaterialVariable<F32>(*glvar, in, m_resources->_getAllocator(), m_resources->_getTempAllocator()); break; // vec2 case GL_FLOAT_VEC2: mtlvar = newMaterialVariable<Vec2>(*glvar, in, m_resources->_getAllocator(), m_resources->_getTempAllocator()); break; // vec3 case GL_FLOAT_VEC3: mtlvar = newMaterialVariable<Vec3>(*glvar, in, m_resources->_getAllocator(), m_resources->_getTempAllocator()); break; // vec4 case GL_FLOAT_VEC4: mtlvar = newMaterialVariable<Vec4>(*glvar, in, m_resources->_getAllocator(), m_resources->_getTempAllocator()); break; // mat3 case GL_FLOAT_MAT3: mtlvar = newMaterialVariable<Mat3>(*glvar, in, m_resources->_getAllocator(), m_resources->_getTempAllocator()); break; // mat4 case GL_FLOAT_MAT4: mtlvar = newMaterialVariable<Mat4>(*glvar, in, m_resources->_getAllocator(), m_resources->_getTempAllocator()); break; // default is error default: ANKI_ASSERT(0); } m_vars.push_back(mtlvar); } }
//============================================================================== void NativeWindowImpl::create(NativeWindowInitializer& init) { // Create window // fbwin = (fbdev_window*)malloc(sizeof(fbdev_window)); if(fbwin == NULL) { throw ANKI_EXCEPTION("malloc() failed"); } fbwin->width = init.width; fbwin->height = init.height; // EGL init // display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if(display == EGL_NO_DISPLAY) { throw ANKI_EXCEPTION("Failed to create display"); } int major, minor; if(eglInitialize(display, &major, &minor) == EGL_FALSE) { throw ANKI_EXCEPTION("Failed to initialize EGL"); } int maxConfigs; if(eglGetConfigs(display, NULL, 0, &maxConfigs) == EGL_FALSE) { throw ANKI_EXCEPTION("Failed to query EGL configs"); } if(maxConfigs < 1) { throw ANKI_EXCEPTION("Error in number of configs"); } Vector<EGLConfig> configs(maxConfigs); Array<EGLint, 256> attribs; U attr = 0; attribs[attr++] = EGL_RENDERABLE_TYPE; attribs[attr++] = EGL_OPENGL_ES2_BIT; if(init.samplesCount > 1) { attribs[attr++] = EGL_SAMPLES; attribs[attr++] = init.samplesCount; } attribs[attr++] = EGL_RED_SIZE; attribs[attr++] = init.rgbaBits[0]; attribs[attr++] = EGL_GREEN_SIZE; attribs[attr++] = init.rgbaBits[1]; attribs[attr++] = EGL_BLUE_SIZE; attribs[attr++] = init.rgbaBits[2]; attribs[attr++] = EGL_ALPHA_SIZE; attribs[attr++] = init.rgbaBits[3]; attribs[attr++] = EGL_DEPTH_SIZE; attribs[attr++] = init.depthBits; attribs[attr++] = EGL_STENCIL_SIZE; attribs[attr++] = init.stencilBits; attribs[attr++] = EGL_NONE; EGLint configsCount; if(eglChooseConfig(display, &attribs[0], &configs[0], maxConfigs, &configsCount) == EGL_FALSE) { throw ANKI_EXCEPTION("Failed to query required EGL configs"); } if(configsCount == 0) { throw ANKI_EXCEPTION("No matching EGL configs found"); } EGLConfig config_ = nullptr; for(EGLint i = 0; i < configsCount; i++) { EGLint value; EGLConfig config = configs[i]; // Use this to explicitly check that the EGL config has the // expected color depths eglGetConfigAttrib(display, config, EGL_RED_SIZE, &value); if(value != (EGLint)init.rgbaBits[0]) { continue; } eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &value); if(value != (EGLint)init.rgbaBits[1]) { continue; } eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &value); if(value != (EGLint)init.rgbaBits[2]) { continue; } eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &value); if(value != (EGLint)init.rgbaBits[3]) { continue; } eglGetConfigAttrib(display, config, EGL_SAMPLES, &value); if(value != (EGLint)init.samplesCount) { continue; } eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &value); if(value != (EGLint)init.depthBits) { continue; } eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &value); if(value != (EGLint)init.stencilBits) { continue; } // We found what we wanted config_ = config; break; } if(config_ == nullptr) { throw ANKI_EXCEPTION("Unable to find suitable EGL config"); } // Surface // surface = eglCreateWindowSurface(display, config_, static_cast<EGLNativeWindowType>(fbwin), NULL); if(surface == EGL_NO_SURFACE) { throw ANKI_EXCEPTION("Cannot create surface"); } // Context // EGLint ctxAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; context = eglCreateContext(display, config_, EGL_NO_CONTEXT, ctxAttribs); if(context == EGL_NO_CONTEXT) { throw ANKI_EXCEPTION("Cannot create context"); } if(eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { throw ANKI_EXCEPTION("Cannot make the context current"); } }
//============================================================================== void MaterialProgramCreator::parseInputsTag(const XmlElement& programEl) { XmlElement inputsEl = programEl.getChildElementOptional("inputs"); if(!inputsEl) { return; } // Get shader type GLbitfield glshaderbit; GLenum glshader; U shaderidx; getShaderInfo( programEl.getChildElement("type").getText(), glshader, glshaderbit, shaderidx); XmlElement inputEl = inputsEl.getChildElement("input"); do { Input inpvar(m_alloc); // <name> inpvar.m_name = inputEl.getChildElement("name").getText(); // <type> inpvar.m_type = inputEl.getChildElement("type").getText(); // <value> XmlElement valueEl = inputEl.getChildElement("value"); if(valueEl.getText()) { inpvar.m_value = MPStringList::splitString( valueEl.getText(), ' ', m_alloc); } // <const> XmlElement constEl = inputEl.getChildElementOptional("const"); inpvar.m_constant = (constEl) ? constEl.getInt() : false; // <arraySize> XmlElement arrSizeEl = inputEl.getChildElementOptional("arraySize"); inpvar.m_arraySize = (arrSizeEl) ? arrSizeEl.getInt() : 0; // <instanced> if(inpvar.m_arraySize == 0) { XmlElement instancedEl = inputEl.getChildElementOptional("instanced"); inpvar.m_instanced = (instancedEl) ? instancedEl.getInt() : 0; // If one input var is instanced notify the whole program that // it's instanced if(inpvar.m_instanced) { m_instanced = true; } } // Now you have the info to check if duplicate Input* duplicateInp = nullptr; for(Input& in : m_inputs) { if(in.m_name == inpvar.m_name) { duplicateInp = ∈ break; } } if(duplicateInp != nullptr) { // Duplicate. Make sure it's the same as the other shader Bool same = duplicateInp->m_type == inpvar.m_type || duplicateInp->m_value == inpvar.m_value || duplicateInp->m_constant == inpvar.m_constant || duplicateInp->m_arraySize == inpvar.m_arraySize || duplicateInp->m_instanced == inpvar.m_instanced; if(!same) { throw ANKI_EXCEPTION("Variable defined differently between " "shaders: %s", &inpvar.m_name[0]); } duplicateInp->m_shaderDefinedMask |= glshaderbit; goto advance; } if(inpvar.m_constant == false) { // Handle NON-consts inpvar.m_line = inpvar.m_type + " " + inpvar.m_name; if(inpvar.m_arraySize > 1) { MPString tmp(MPString::toString(inpvar.m_arraySize, m_alloc)); inpvar.m_line += "[" + tmp + "U]"; } if(inpvar.m_instanced) { MPString tmp( MPString::toString(ANKI_GL_MAX_INSTANCES, m_alloc)); inpvar.m_line += "[" + tmp + "U]"; } inpvar.m_line += ";"; // Can put it block if(inpvar.m_type == "sampler2D" || inpvar.m_type == "samplerCube") { MPString tmp( MPString::toString(m_texBinding++, m_alloc)); inpvar.m_line = ANKI_STRL("layout(binding = ") + tmp + ") uniform " + inpvar.m_line; inpvar.m_inBlock = false; } else { inpvar.m_inBlock = true; m_uniformBlock.push_back(inpvar.m_line); m_uniformBlockReferencedMask |= glshaderbit; } } else { // Handle consts if(inpvar.m_value.size() == 0) { throw ANKI_EXCEPTION("Empty value and const is illogical"); } if(inpvar.m_arraySize > 0) { throw ANKI_EXCEPTION("Const arrays currently cannot " "be handled"); } inpvar.m_inBlock = false; inpvar.m_line = ANKI_STRL("const ") + inpvar.m_type + " " + inpvar.m_name + " = " + inpvar.m_type + "(" + inpvar.m_value.join(", ") + ");"; } inpvar.m_shaderDefinedMask = glshaderbit; m_inputs.push_back(inpvar); advance: // Advance inputEl = inputEl.getNextSiblingElement("input"); } while(inputEl); }
//============================================================================== void MaterialProgramCreator::parseOperationTag( const XmlElement& operationTag, GLenum glshader, GLbitfield glshaderbit, MPString& out) { static const char OUT[] = {"out"}; // <id></id> I id = operationTag.getChildElement("id").getInt(); // <returnType></returnType> XmlElement retTypeEl = operationTag.getChildElement("returnType"); MPString retType(retTypeEl.getText(), m_alloc); MPString operationOut(m_alloc); if(retType != "void") { MPString tmp(MPString::toString(id, m_alloc)); operationOut = ANKI_STRL(OUT) + tmp; } // <function>functionName</function> MPString funcName( operationTag.getChildElement("function").getText(), m_alloc); // <arguments></arguments> XmlElement argsEl = operationTag.getChildElementOptional("arguments"); MPStringList argsList(m_alloc); if(argsEl) { // Get all arguments XmlElement argEl = argsEl.getChildElement("argument"); do { MPString arg(argEl.getText(), m_alloc); // Search for all the inputs and mark the appropriate Input* input = nullptr; for(Input& in : m_inputs) { // Check that the first part of the string is equal to the // variable and the following char is '[' if(in.m_name == arg) { input = ∈ in.m_shaderReferencedMask = glshaderbit; break; } } // The argument should be an input variable or an outXX if(!(input != nullptr || std::strncmp(&arg[0], OUT, sizeof(OUT) - 1) == 0)) { throw ANKI_EXCEPTION("Incorrect argument: %s", &arg[0]); } // Add to a list and do something special if instanced if(input && input->m_instanced) { if(glshader == GL_VERTEX_SHADER) { argsList.push_back(ANKI_STRL(argEl.getText()) + "[gl_InstanceID]"); m_instanceIdMask |= glshaderbit; } else if(glshader == GL_TESS_CONTROL_SHADER) { argsList.push_back(ANKI_STRL(argEl.getText()) + "[vInstanceId[0]]"); m_instanceIdMask |= glshaderbit; } else if(glshader == GL_TESS_EVALUATION_SHADER) { argsList.push_back(ANKI_STRL(argEl.getText()) + "[commonPatch.instanceId]"); m_instanceIdMask |= glshaderbit; } else if(glshader == GL_FRAGMENT_SHADER) { argsList.push_back(ANKI_STRL(argEl.getText()) + "[vInstanceId]"); m_instanceIdMask |= glshaderbit; } else { throw ANKI_EXCEPTION( "Cannot access the instance ID in all shaders"); } } else { argsList.push_back(MPString(argEl.getText(), m_alloc)); } // Advance argEl = argEl.getNextSiblingElement("argument"); } while(argEl); } // Now write everything MPString lines(m_alloc); lines.reserve(256); lines += "#if defined(" + funcName + "_DEFINED)"; // Write the defines for the operationOuts for(const MPString& arg : argsList) { if(arg.find(OUT) == 0) { lines += " && defined(" + arg + "_DEFINED)"; } } lines += "\n"; if(retType != "void") { lines += "#\tdefine " + operationOut + "_DEFINED\n\t" + retTypeEl.getText() + " " + operationOut + " = "; } else { lines += "\t"; } // write the blah = func(args...) lines += funcName + "("; lines += argsList.join(", "); lines += ");\n"; lines += "#endif"; // Done out = std::move(lines); }