1cb93a386Sopenharmony_ci// Copyright 2019 The Chromium Authors. All rights reserved. 2cb93a386Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 3cb93a386Sopenharmony_ci// found in the LICENSE file. 4cb93a386Sopenharmony_ci 5cb93a386Sopenharmony_cipackage main 6cb93a386Sopenharmony_ci 7cb93a386Sopenharmony_ci// gen_interface creates the assemble/validate cpp files given the 8cb93a386Sopenharmony_ci// interface.json5 file. 9cb93a386Sopenharmony_ci// See README for more details. 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ciimport ( 12cb93a386Sopenharmony_ci "flag" 13cb93a386Sopenharmony_ci "fmt" 14cb93a386Sopenharmony_ci "io/ioutil" 15cb93a386Sopenharmony_ci "os" 16cb93a386Sopenharmony_ci "path/filepath" 17cb93a386Sopenharmony_ci "sort" 18cb93a386Sopenharmony_ci "strings" 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_ci "github.com/flynn/json5" 21cb93a386Sopenharmony_ci) 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_civar ( 24cb93a386Sopenharmony_ci outDir = flag.String("out_dir", "../../src/gpu/gl", "Where to output the GrGlAssembleInterface_* and GrGlInterface.cpp files") 25cb93a386Sopenharmony_ci inTable = flag.String("in_table", "./interface.json5", "The JSON5 table to read in") 26cb93a386Sopenharmony_ci dryRun = flag.Bool("dryrun", false, "Print the outputs, don't write to file") 27cb93a386Sopenharmony_ci) 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ciconst ( 30cb93a386Sopenharmony_ci CORE_FEATURE = "<core>" 31cb93a386Sopenharmony_ci SPACER = " " 32cb93a386Sopenharmony_ci GLES_FILE_NAME = "GrGLAssembleGLESInterfaceAutogen.cpp" 33cb93a386Sopenharmony_ci GL_FILE_NAME = "GrGLAssembleGLInterfaceAutogen.cpp" 34cb93a386Sopenharmony_ci WEBGL_FILE_NAME = "GrGLAssembleWebGLInterfaceAutogen.cpp" 35cb93a386Sopenharmony_ci INTERFACE_FILE_NAME = "GrGLInterfaceAutogen.cpp" 36cb93a386Sopenharmony_ci) 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci// FeatureSet represents one set of requirements for each of the GL "standards" that 39cb93a386Sopenharmony_ci// Skia supports. This is currently OpenGL, OpenGL ES and WebGL. 40cb93a386Sopenharmony_ci// OpenGL is typically abbreviated as just "GL". 41cb93a386Sopenharmony_ci// https://www.khronos.org/registry/OpenGL/index_gl.php 42cb93a386Sopenharmony_ci// https://www.khronos.org/opengles/ 43cb93a386Sopenharmony_ci// https://www.khronos.org/registry/webgl/specs/1.0/ 44cb93a386Sopenharmony_citype FeatureSet struct { 45cb93a386Sopenharmony_ci GLReqs []Requirement `json:"GL"` 46cb93a386Sopenharmony_ci GLESReqs []Requirement `json:"GLES"` 47cb93a386Sopenharmony_ci WebGLReqs []Requirement `json:"WebGL"` 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ci Functions []string `json:"functions"` 50cb93a386Sopenharmony_ci HardCodeFunctions []HardCodeFunction `json:"hardcode_functions"` 51cb93a386Sopenharmony_ci OptionalFunctions []string `json:"optional"` // not checked in validate 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci // only assembled/validated when testing 54cb93a386Sopenharmony_ci TestOnlyFunctions []string `json:"test_functions"` 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci Required bool `json:"required"` 57cb93a386Sopenharmony_ci} 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci// Requirement lists how we know if a function exists. Extension is the 60cb93a386Sopenharmony_ci// GL extension (or the string CORE_FEATURE if it's part of the core functionality). 61cb93a386Sopenharmony_ci// MinVersion optionally indicates the minimum version of a standard 62cb93a386Sopenharmony_ci// that has the function. 63cb93a386Sopenharmony_ci// SuffixOverride allows the extension suffix to be manually specified instead 64cb93a386Sopenharmony_ci// of automatically derived from the extension name. 65cb93a386Sopenharmony_ci// (for example, if an NV extension specifies some EXT extensions) 66cb93a386Sopenharmony_citype Requirement struct { 67cb93a386Sopenharmony_ci Extension string `json:"ext"` // required 68cb93a386Sopenharmony_ci MinVersion *GLVersion `json:"min_version"` 69cb93a386Sopenharmony_ci SuffixOverride *string `json:"suffix"` 70cb93a386Sopenharmony_ci} 71cb93a386Sopenharmony_ci 72cb93a386Sopenharmony_ci// HardCodeFunction indicates to not use the C++ macro and just directly 73cb93a386Sopenharmony_ci// adds a given function ptr to the struct. 74cb93a386Sopenharmony_citype HardCodeFunction struct { 75cb93a386Sopenharmony_ci PtrName string `json:"ptr_name"` 76cb93a386Sopenharmony_ci CastName string `json:"cast_name"` 77cb93a386Sopenharmony_ci GetName string `json:"get_name"` 78cb93a386Sopenharmony_ci} 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_civar CORE_REQUIREMENT = Requirement{Extension: CORE_FEATURE, MinVersion: nil} 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_citype GLVersion [2]int 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_ci// RequirementGetter functions allows us to "iterate" over the requirements 85cb93a386Sopenharmony_ci// of the different standards which are stored as keys in FeatureSet and 86cb93a386Sopenharmony_ci// normally not easily iterable. 87cb93a386Sopenharmony_citype RequirementGetter func(FeatureSet) []Requirement 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_cifunc glRequirements(fs FeatureSet) []Requirement { 90cb93a386Sopenharmony_ci return fs.GLReqs 91cb93a386Sopenharmony_ci} 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_cifunc glesRequirements(fs FeatureSet) []Requirement { 94cb93a386Sopenharmony_ci return fs.GLESReqs 95cb93a386Sopenharmony_ci} 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_cifunc webglRequirements(fs FeatureSet) []Requirement { 98cb93a386Sopenharmony_ci return fs.WebGLReqs 99cb93a386Sopenharmony_ci} 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci// generateAssembleInterface creates one GrGLAssembleInterface_[type]_gen.cpp 102cb93a386Sopenharmony_ci// for each of the standards 103cb93a386Sopenharmony_cifunc generateAssembleInterface(features []FeatureSet) { 104cb93a386Sopenharmony_ci gl := fillAssembleTemplate(ASSEMBLE_INTERFACE_GL, features, glRequirements) 105cb93a386Sopenharmony_ci writeToFile(*outDir, GL_FILE_NAME, gl) 106cb93a386Sopenharmony_ci gles := fillAssembleTemplate(ASSEMBLE_INTERFACE_GL_ES, features, glesRequirements) 107cb93a386Sopenharmony_ci writeToFile(*outDir, GLES_FILE_NAME, gles) 108cb93a386Sopenharmony_ci webgl := fillAssembleTemplate(ASSEMBLE_INTERFACE_WEBGL, features, webglRequirements) 109cb93a386Sopenharmony_ci writeToFile(*outDir, WEBGL_FILE_NAME, webgl) 110cb93a386Sopenharmony_ci} 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci// fillAssembleTemplate returns a generated file given a template (for a single standard) 113cb93a386Sopenharmony_ci// to fill out and a slice of features with which to fill it. getReqs is used to select 114cb93a386Sopenharmony_ci// the requirements for the standard we are working on. 115cb93a386Sopenharmony_cifunc fillAssembleTemplate(template string, features []FeatureSet, getReqs RequirementGetter) string { 116cb93a386Sopenharmony_ci content := "" 117cb93a386Sopenharmony_ci for _, feature := range features { 118cb93a386Sopenharmony_ci // For each feature set, we are going to create a series of 119cb93a386Sopenharmony_ci // if statements, which check for the requirements (e.g. extensions, version) 120cb93a386Sopenharmony_ci // and inside those if branches, write the code to load the 121cb93a386Sopenharmony_ci // correct function pointer to the interface. GET_PROC and 122cb93a386Sopenharmony_ci // GET_PROC_SUFFIX are macros defined in C++ part of the template 123cb93a386Sopenharmony_ci // to accomplish this (for a core feature and extensions, respectively). 124cb93a386Sopenharmony_ci reqs := getReqs(feature) 125cb93a386Sopenharmony_ci if len(reqs) == 0 { 126cb93a386Sopenharmony_ci continue 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci // blocks holds all the if blocks generated - it will be joined with else 129cb93a386Sopenharmony_ci // after and appended to content 130cb93a386Sopenharmony_ci blocks := []string{} 131cb93a386Sopenharmony_ci for i, req := range reqs { 132cb93a386Sopenharmony_ci block := "" 133cb93a386Sopenharmony_ci ifExpr := requirementIfExpression(req, true) 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_ci if ifExpr != "" { 136cb93a386Sopenharmony_ci if strings.HasPrefix(ifExpr, "(") { 137cb93a386Sopenharmony_ci ifExpr = "if " + ifExpr + " {" 138cb93a386Sopenharmony_ci } else { 139cb93a386Sopenharmony_ci ifExpr = "if (" + ifExpr + ") {" 140cb93a386Sopenharmony_ci } 141cb93a386Sopenharmony_ci // Indent the first if statement 142cb93a386Sopenharmony_ci if i == 0 { 143cb93a386Sopenharmony_ci block = addLine(block, ifExpr) 144cb93a386Sopenharmony_ci } else { 145cb93a386Sopenharmony_ci block += ifExpr + "\n" 146cb93a386Sopenharmony_ci } 147cb93a386Sopenharmony_ci } 148cb93a386Sopenharmony_ci // sort for determinism 149cb93a386Sopenharmony_ci sort.Strings(feature.Functions) 150cb93a386Sopenharmony_ci for _, function := range feature.Functions { 151cb93a386Sopenharmony_ci block = assembleFunction(block, ifExpr, function, req) 152cb93a386Sopenharmony_ci } 153cb93a386Sopenharmony_ci sort.Strings(feature.TestOnlyFunctions) 154cb93a386Sopenharmony_ci if len(feature.TestOnlyFunctions) > 0 { 155cb93a386Sopenharmony_ci block += "#if GR_TEST_UTILS\n" 156cb93a386Sopenharmony_ci for _, function := range feature.TestOnlyFunctions { 157cb93a386Sopenharmony_ci block = assembleFunction(block, ifExpr, function, req) 158cb93a386Sopenharmony_ci } 159cb93a386Sopenharmony_ci block += "#endif\n" 160cb93a386Sopenharmony_ci } 161cb93a386Sopenharmony_ci 162cb93a386Sopenharmony_ci // a hard code function does not use the C++ macro 163cb93a386Sopenharmony_ci for _, hcf := range feature.HardCodeFunctions { 164cb93a386Sopenharmony_ci if ifExpr != "" { 165cb93a386Sopenharmony_ci // extra tab for being in an if statement 166cb93a386Sopenharmony_ci block += SPACER 167cb93a386Sopenharmony_ci } 168cb93a386Sopenharmony_ci line := fmt.Sprintf(`functions->%s =(%s*)get(ctx, "%s");`, hcf.PtrName, hcf.CastName, hcf.GetName) 169cb93a386Sopenharmony_ci block = addLine(block, line) 170cb93a386Sopenharmony_ci } 171cb93a386Sopenharmony_ci if ifExpr != "" { 172cb93a386Sopenharmony_ci block += SPACER + "}" 173cb93a386Sopenharmony_ci } 174cb93a386Sopenharmony_ci blocks = append(blocks, block) 175cb93a386Sopenharmony_ci } 176cb93a386Sopenharmony_ci content += strings.Join(blocks, " else ") 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci if feature.Required && reqs[0] != CORE_REQUIREMENT { 179cb93a386Sopenharmony_ci content += ` else { 180cb93a386Sopenharmony_ci SkASSERT(false); // Required feature 181cb93a386Sopenharmony_ci return nullptr; 182cb93a386Sopenharmony_ci }` 183cb93a386Sopenharmony_ci } 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci if !strings.HasSuffix(content, "\n") { 186cb93a386Sopenharmony_ci content += "\n" 187cb93a386Sopenharmony_ci } 188cb93a386Sopenharmony_ci // Add an extra space between blocks for easier readability 189cb93a386Sopenharmony_ci content += "\n" 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_ci } 192cb93a386Sopenharmony_ci 193cb93a386Sopenharmony_ci return strings.Replace(template, "[[content]]", content, 1) 194cb93a386Sopenharmony_ci} 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_ci// assembleFunction is a little helper that will add a function to the interface 197cb93a386Sopenharmony_ci// using an appropriate macro (e.g. if the function is added) 198cb93a386Sopenharmony_ci// with an extension. 199cb93a386Sopenharmony_cifunc assembleFunction(block, ifExpr, function string, req Requirement) string { 200cb93a386Sopenharmony_ci if ifExpr != "" { 201cb93a386Sopenharmony_ci // extra tab for being in an if statement 202cb93a386Sopenharmony_ci block += SPACER 203cb93a386Sopenharmony_ci } 204cb93a386Sopenharmony_ci suffix := deriveSuffix(req.Extension) 205cb93a386Sopenharmony_ci // Some ARB extensions don't have ARB suffixes because they were written 206cb93a386Sopenharmony_ci // for backwards compatibility simultaneous to adding them as required 207cb93a386Sopenharmony_ci // in a new GL version. 208cb93a386Sopenharmony_ci if suffix == "ARB" { 209cb93a386Sopenharmony_ci suffix = "" 210cb93a386Sopenharmony_ci } 211cb93a386Sopenharmony_ci if req.SuffixOverride != nil { 212cb93a386Sopenharmony_ci suffix = *req.SuffixOverride 213cb93a386Sopenharmony_ci } 214cb93a386Sopenharmony_ci if req.Extension == CORE_FEATURE || suffix == "" { 215cb93a386Sopenharmony_ci block = addLine(block, fmt.Sprintf("GET_PROC(%s);", function)) 216cb93a386Sopenharmony_ci } else if req.Extension != "" { 217cb93a386Sopenharmony_ci block = addLine(block, fmt.Sprintf("GET_PROC_SUFFIX(%s, %s);", function, suffix)) 218cb93a386Sopenharmony_ci } 219cb93a386Sopenharmony_ci return block 220cb93a386Sopenharmony_ci} 221cb93a386Sopenharmony_ci 222cb93a386Sopenharmony_ci// requirementIfExpression returns a string that is an if expression 223cb93a386Sopenharmony_ci// Notably, there is no if expression if the function is a "core" function 224cb93a386Sopenharmony_ci// on all supported versions. 225cb93a386Sopenharmony_ci// The expressions are wrapped in parentheses so they can be safely 226cb93a386Sopenharmony_ci// joined together with && or ||. 227cb93a386Sopenharmony_cifunc requirementIfExpression(req Requirement, isLocal bool) string { 228cb93a386Sopenharmony_ci mv := req.MinVersion 229cb93a386Sopenharmony_ci if req == CORE_REQUIREMENT { 230cb93a386Sopenharmony_ci return "" 231cb93a386Sopenharmony_ci } 232cb93a386Sopenharmony_ci if req.Extension == CORE_FEATURE && mv != nil { 233cb93a386Sopenharmony_ci return fmt.Sprintf("(glVer >= GR_GL_VER(%d,%d))", mv[0], mv[1]) 234cb93a386Sopenharmony_ci } 235cb93a386Sopenharmony_ci extVar := "fExtensions" 236cb93a386Sopenharmony_ci if isLocal { 237cb93a386Sopenharmony_ci extVar = "extensions" 238cb93a386Sopenharmony_ci } 239cb93a386Sopenharmony_ci // We know it has an extension 240cb93a386Sopenharmony_ci if req.Extension != "" { 241cb93a386Sopenharmony_ci if mv == nil { 242cb93a386Sopenharmony_ci return fmt.Sprintf("%s.has(%q)", extVar, req.Extension) 243cb93a386Sopenharmony_ci } else { 244cb93a386Sopenharmony_ci return fmt.Sprintf("(glVer >= GR_GL_VER(%d,%d) && %s.has(%q))", mv[0], mv[1], extVar, req.Extension) 245cb93a386Sopenharmony_ci } 246cb93a386Sopenharmony_ci } 247cb93a386Sopenharmony_ci abort("ERROR: requirement must have ext") 248cb93a386Sopenharmony_ci return "ERROR" 249cb93a386Sopenharmony_ci} 250cb93a386Sopenharmony_ci 251cb93a386Sopenharmony_ci// driveSuffix returns the suffix of the function associated with the given 252cb93a386Sopenharmony_ci// extension. 253cb93a386Sopenharmony_cifunc deriveSuffix(ext string) string { 254cb93a386Sopenharmony_ci // Some extensions begin with GL_ and then have the actual 255cb93a386Sopenharmony_ci // extension like KHR, EXT etc. 256cb93a386Sopenharmony_ci ext = strings.TrimPrefix(ext, "GL_") 257cb93a386Sopenharmony_ci return strings.Split(ext, "_")[0] 258cb93a386Sopenharmony_ci} 259cb93a386Sopenharmony_ci 260cb93a386Sopenharmony_ci// addLine is a little helper function which handles the newline and tab 261cb93a386Sopenharmony_cifunc addLine(str, line string) string { 262cb93a386Sopenharmony_ci return str + SPACER + line + "\n" 263cb93a386Sopenharmony_ci} 264cb93a386Sopenharmony_ci 265cb93a386Sopenharmony_cifunc writeToFile(parent, file, content string) { 266cb93a386Sopenharmony_ci p := filepath.Join(parent, file) 267cb93a386Sopenharmony_ci if *dryRun { 268cb93a386Sopenharmony_ci fmt.Printf("Writing to %s\n", p) 269cb93a386Sopenharmony_ci fmt.Println(content) 270cb93a386Sopenharmony_ci } else { 271cb93a386Sopenharmony_ci if err := ioutil.WriteFile(p, []byte(content), 0644); err != nil { 272cb93a386Sopenharmony_ci abort("Error while writing to file %s: %s", p, err) 273cb93a386Sopenharmony_ci } 274cb93a386Sopenharmony_ci } 275cb93a386Sopenharmony_ci} 276cb93a386Sopenharmony_ci 277cb93a386Sopenharmony_ci// validationEntry is a helper struct that contains anything 278cb93a386Sopenharmony_ci// necessary to make validation code for a given standard. 279cb93a386Sopenharmony_citype validationEntry struct { 280cb93a386Sopenharmony_ci StandardCheck string 281cb93a386Sopenharmony_ci GetReqs RequirementGetter 282cb93a386Sopenharmony_ci} 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_cifunc generateValidateInterface(features []FeatureSet) { 285cb93a386Sopenharmony_ci standards := []validationEntry{ 286cb93a386Sopenharmony_ci { 287cb93a386Sopenharmony_ci StandardCheck: "GR_IS_GR_GL(fStandard)", 288cb93a386Sopenharmony_ci GetReqs: glRequirements, 289cb93a386Sopenharmony_ci }, { 290cb93a386Sopenharmony_ci StandardCheck: "GR_IS_GR_GL_ES(fStandard)", 291cb93a386Sopenharmony_ci GetReqs: glesRequirements, 292cb93a386Sopenharmony_ci }, { 293cb93a386Sopenharmony_ci StandardCheck: "GR_IS_GR_WEBGL(fStandard)", 294cb93a386Sopenharmony_ci GetReqs: webglRequirements, 295cb93a386Sopenharmony_ci }, 296cb93a386Sopenharmony_ci } 297cb93a386Sopenharmony_ci content := "" 298cb93a386Sopenharmony_ci // For each feature, we are going to generate a series of 299cb93a386Sopenharmony_ci // boolean expressions which check that the functions we thought 300cb93a386Sopenharmony_ci // were gathered during the assemble phase actually were applied to 301cb93a386Sopenharmony_ci // the interface (functionCheck). This check will be guarded 302cb93a386Sopenharmony_ci // another set of if statements (one per standard) based 303cb93a386Sopenharmony_ci // on the same requirements (standardChecks) that were used when 304cb93a386Sopenharmony_ci // assembling the interface. 305cb93a386Sopenharmony_ci for _, feature := range features { 306cb93a386Sopenharmony_ci if allReqsAreCore(feature) { 307cb93a386Sopenharmony_ci content += functionCheck(feature, 1) 308cb93a386Sopenharmony_ci } else { 309cb93a386Sopenharmony_ci content += SPACER 310cb93a386Sopenharmony_ci standardChecks := []string{} 311cb93a386Sopenharmony_ci for _, std := range standards { 312cb93a386Sopenharmony_ci reqs := std.GetReqs(feature) 313cb93a386Sopenharmony_ci if reqs == nil || len(reqs) == 0 { 314cb93a386Sopenharmony_ci continue 315cb93a386Sopenharmony_ci } 316cb93a386Sopenharmony_ci expr := []string{} 317cb93a386Sopenharmony_ci for _, r := range reqs { 318cb93a386Sopenharmony_ci e := requirementIfExpression(r, false) 319cb93a386Sopenharmony_ci if e != "" { 320cb93a386Sopenharmony_ci expr = append(expr, e) 321cb93a386Sopenharmony_ci } 322cb93a386Sopenharmony_ci } 323cb93a386Sopenharmony_ci check := "" 324cb93a386Sopenharmony_ci if len(expr) == 0 { 325cb93a386Sopenharmony_ci check = fmt.Sprintf("%s", std.StandardCheck) 326cb93a386Sopenharmony_ci } else { 327cb93a386Sopenharmony_ci lineBreak := "\n" + SPACER + " " 328cb93a386Sopenharmony_ci check = fmt.Sprintf("(%s && (%s%s))", std.StandardCheck, lineBreak, strings.Join(expr, " ||"+lineBreak)) 329cb93a386Sopenharmony_ci } 330cb93a386Sopenharmony_ci standardChecks = append(standardChecks, check) 331cb93a386Sopenharmony_ci } 332cb93a386Sopenharmony_ci content += fmt.Sprintf("if (%s) {\n", strings.Join(standardChecks, " ||\n"+SPACER+" ")) 333cb93a386Sopenharmony_ci content += functionCheck(feature, 2) 334cb93a386Sopenharmony_ci 335cb93a386Sopenharmony_ci content += SPACER + "}\n" 336cb93a386Sopenharmony_ci } 337cb93a386Sopenharmony_ci // add additional line between each block 338cb93a386Sopenharmony_ci content += "\n" 339cb93a386Sopenharmony_ci } 340cb93a386Sopenharmony_ci content = strings.Replace(VALIDATE_INTERFACE, "[[content]]", content, 1) 341cb93a386Sopenharmony_ci writeToFile(*outDir, INTERFACE_FILE_NAME, content) 342cb93a386Sopenharmony_ci} 343cb93a386Sopenharmony_ci 344cb93a386Sopenharmony_ci// functionCheck returns an if statement that checks that all functions 345cb93a386Sopenharmony_ci// in the passed in slice are on the interface (that is, they are truthy 346cb93a386Sopenharmony_ci// on the fFunctions struct) 347cb93a386Sopenharmony_cifunc functionCheck(feature FeatureSet, indentLevel int) string { 348cb93a386Sopenharmony_ci // sort for determinism 349cb93a386Sopenharmony_ci sort.Strings(feature.Functions) 350cb93a386Sopenharmony_ci indent := strings.Repeat(SPACER, indentLevel) 351cb93a386Sopenharmony_ci 352cb93a386Sopenharmony_ci checks := []string{} 353cb93a386Sopenharmony_ci for _, function := range feature.Functions { 354cb93a386Sopenharmony_ci if in(function, feature.OptionalFunctions) { 355cb93a386Sopenharmony_ci continue 356cb93a386Sopenharmony_ci } 357cb93a386Sopenharmony_ci checks = append(checks, "!fFunctions.f"+function) 358cb93a386Sopenharmony_ci } 359cb93a386Sopenharmony_ci testOnly := []string{} 360cb93a386Sopenharmony_ci for _, function := range feature.TestOnlyFunctions { 361cb93a386Sopenharmony_ci if in(function, feature.OptionalFunctions) { 362cb93a386Sopenharmony_ci continue 363cb93a386Sopenharmony_ci } 364cb93a386Sopenharmony_ci testOnly = append(testOnly, "!fFunctions.f"+function) 365cb93a386Sopenharmony_ci } 366cb93a386Sopenharmony_ci for _, hcf := range feature.HardCodeFunctions { 367cb93a386Sopenharmony_ci checks = append(checks, "!fFunctions."+hcf.PtrName) 368cb93a386Sopenharmony_ci } 369cb93a386Sopenharmony_ci preCheck := "" 370cb93a386Sopenharmony_ci if len(testOnly) != 0 { 371cb93a386Sopenharmony_ci preCheck = fmt.Sprintf(`#if GR_TEST_UTILS 372cb93a386Sopenharmony_ci%sif (%s) { 373cb93a386Sopenharmony_ci%s%sRETURN_FALSE_INTERFACE; 374cb93a386Sopenharmony_ci%s} 375cb93a386Sopenharmony_ci#endif 376cb93a386Sopenharmony_ci`, indent, strings.Join(testOnly, " ||\n"+indent+" "), indent, SPACER, indent) 377cb93a386Sopenharmony_ci } 378cb93a386Sopenharmony_ci 379cb93a386Sopenharmony_ci if len(checks) == 0 { 380cb93a386Sopenharmony_ci return preCheck + strings.Repeat(SPACER, indentLevel) + "// all functions were marked optional or test_only\n" 381cb93a386Sopenharmony_ci } 382cb93a386Sopenharmony_ci 383cb93a386Sopenharmony_ci return preCheck + fmt.Sprintf(`%sif (%s) { 384cb93a386Sopenharmony_ci%s%sRETURN_FALSE_INTERFACE; 385cb93a386Sopenharmony_ci%s} 386cb93a386Sopenharmony_ci`, indent, strings.Join(checks, " ||\n"+indent+" "), indent, SPACER, indent) 387cb93a386Sopenharmony_ci} 388cb93a386Sopenharmony_ci 389cb93a386Sopenharmony_ci// allReqsAreCore returns true iff the FeatureSet is part of "core" for 390cb93a386Sopenharmony_ci// all standards 391cb93a386Sopenharmony_cifunc allReqsAreCore(feature FeatureSet) bool { 392cb93a386Sopenharmony_ci if feature.GLReqs == nil || feature.GLESReqs == nil { 393cb93a386Sopenharmony_ci return false 394cb93a386Sopenharmony_ci } 395cb93a386Sopenharmony_ci return feature.GLReqs[0] == CORE_REQUIREMENT && feature.GLESReqs[0] == CORE_REQUIREMENT && feature.WebGLReqs[0] == CORE_REQUIREMENT 396cb93a386Sopenharmony_ci} 397cb93a386Sopenharmony_ci 398cb93a386Sopenharmony_cifunc validateFeatures(features []FeatureSet) { 399cb93a386Sopenharmony_ci seen := map[string]bool{} 400cb93a386Sopenharmony_ci for _, feature := range features { 401cb93a386Sopenharmony_ci for _, fn := range feature.Functions { 402cb93a386Sopenharmony_ci if seen[fn] { 403cb93a386Sopenharmony_ci abort("ERROR: Duplicate function %s", fn) 404cb93a386Sopenharmony_ci } 405cb93a386Sopenharmony_ci seen[fn] = true 406cb93a386Sopenharmony_ci } 407cb93a386Sopenharmony_ci for _, fn := range feature.TestOnlyFunctions { 408cb93a386Sopenharmony_ci if seen[fn] { 409cb93a386Sopenharmony_ci abort("ERROR: Duplicate function %s\n", fn) 410cb93a386Sopenharmony_ci } 411cb93a386Sopenharmony_ci seen[fn] = true 412cb93a386Sopenharmony_ci } 413cb93a386Sopenharmony_ci } 414cb93a386Sopenharmony_ci} 415cb93a386Sopenharmony_ci 416cb93a386Sopenharmony_ci// in returns true if |s| is *in* |a| slice. 417cb93a386Sopenharmony_cifunc in(s string, a []string) bool { 418cb93a386Sopenharmony_ci for _, x := range a { 419cb93a386Sopenharmony_ci if x == s { 420cb93a386Sopenharmony_ci return true 421cb93a386Sopenharmony_ci } 422cb93a386Sopenharmony_ci } 423cb93a386Sopenharmony_ci return false 424cb93a386Sopenharmony_ci} 425cb93a386Sopenharmony_ci 426cb93a386Sopenharmony_cifunc abort(fmtStr string, inputs ...interface{}) { 427cb93a386Sopenharmony_ci fmt.Printf(fmtStr+"\n", inputs...) 428cb93a386Sopenharmony_ci os.Exit(1) 429cb93a386Sopenharmony_ci} 430cb93a386Sopenharmony_ci 431cb93a386Sopenharmony_cifunc main() { 432cb93a386Sopenharmony_ci flag.Parse() 433cb93a386Sopenharmony_ci b, err := ioutil.ReadFile(*inTable) 434cb93a386Sopenharmony_ci if err != nil { 435cb93a386Sopenharmony_ci abort("Could not read file %s", err) 436cb93a386Sopenharmony_ci } 437cb93a386Sopenharmony_ci 438cb93a386Sopenharmony_ci dir, err := os.Open(*outDir) 439cb93a386Sopenharmony_ci if err != nil { 440cb93a386Sopenharmony_ci abort("Could not write to output dir %s", err) 441cb93a386Sopenharmony_ci } 442cb93a386Sopenharmony_ci defer dir.Close() 443cb93a386Sopenharmony_ci if fi, err := dir.Stat(); err != nil { 444cb93a386Sopenharmony_ci abort("Error getting info about %s: %s", *outDir, err) 445cb93a386Sopenharmony_ci } else if !fi.IsDir() { 446cb93a386Sopenharmony_ci abort("%s must be a directory", *outDir) 447cb93a386Sopenharmony_ci } 448cb93a386Sopenharmony_ci 449cb93a386Sopenharmony_ci features := []FeatureSet{} 450cb93a386Sopenharmony_ci 451cb93a386Sopenharmony_ci err = json5.Unmarshal(b, &features) 452cb93a386Sopenharmony_ci if err != nil { 453cb93a386Sopenharmony_ci abort("Invalid JSON: %s", err) 454cb93a386Sopenharmony_ci } 455cb93a386Sopenharmony_ci 456cb93a386Sopenharmony_ci validateFeatures(features) 457cb93a386Sopenharmony_ci 458cb93a386Sopenharmony_ci generateAssembleInterface(features) 459cb93a386Sopenharmony_ci generateValidateInterface(features) 460cb93a386Sopenharmony_ci} 461